OS मेकफाइल का पता लगा रहा है


250

मैं नियमित रूप से कई अलग-अलग कंप्यूटरों और कई अलग-अलग ऑपरेटिंग सिस्टमों पर काम करता हूं, जो मैक ओएस एक्स, लिनक्स या सोलारिस हैं। मैं जिस प्रोजेक्ट पर काम कर रहा हूं, उसके लिए मैं एक रिमोट गिट रिपॉजिटरी से अपना कोड खींचता हूं।

मुझे अपनी परियोजनाओं पर काम करने में सक्षम होना पसंद है चाहे मैं किस टर्मिनल पर हो। अब तक, मैंने हर बार जब मैं कंप्यूटर स्विच करता हूं, तो मेकफाइल को बदलकर ओएस में बदलाव लाने के तरीके खोजे हैं। हालांकि, यह थकाऊ है और सिरदर्द का एक गुच्छा होता है।

मैं अपने मेकफाइल को कैसे संशोधित कर सकता हूं ताकि यह पता लगा सके कि मैं किस ओएस का उपयोग कर रहा हूं और तदनुसार सिंटैक्स को संशोधित कर रहा हूं?

यहाँ मेकफाइल है:

cc = gcc -g
CC = g++ -g
yacc=$(YACC)
lex=$(FLEX)

all: assembler

assembler: y.tab.o lex.yy.o
        $(CC) -o assembler y.tab.o lex.yy.o -ll -l y

assembler.o: assembler.c
        $(cc) -o assembler.o assembler.c

y.tab.o: assem.y
        $(yacc) -d assem.y
        $(CC) -c y.tab.c

lex.yy.o: assem.l
        $(lex) assem.l
        $(cc) -c lex.yy.c

clean:
        rm -f lex.yy.c y.tab.c y.tab.h assembler *.o *.tmp *.debug *.acts

जवाबों:


283

यहाँ पहले से ही कई अच्छे जवाब हैं, लेकिन मैं एक और पूर्ण उदाहरण साझा करना चाहता था कि दोनों:

  • unameविंडोज पर मौजूद नहीं है
  • प्रोसेसर का भी पता लगाता है

यहाँ परिभाषित CCFLAGS अनुशंसित या आदर्श नहीं हैं; वे सिर्फ वही प्रोजेक्ट हैं जिसके लिए मैं OS / CPU ऑटो-डिटेक्शन जोड़ रहा था जो प्रयोग में लाया गया।

ifeq ($(OS),Windows_NT)
    CCFLAGS += -D WIN32
    ifeq ($(PROCESSOR_ARCHITEW6432),AMD64)
        CCFLAGS += -D AMD64
    else
        ifeq ($(PROCESSOR_ARCHITECTURE),AMD64)
            CCFLAGS += -D AMD64
        endif
        ifeq ($(PROCESSOR_ARCHITECTURE),x86)
            CCFLAGS += -D IA32
        endif
    endif
else
    UNAME_S := $(shell uname -s)
    ifeq ($(UNAME_S),Linux)
        CCFLAGS += -D LINUX
    endif
    ifeq ($(UNAME_S),Darwin)
        CCFLAGS += -D OSX
    endif
    UNAME_P := $(shell uname -p)
    ifeq ($(UNAME_P),x86_64)
        CCFLAGS += -D AMD64
    endif
    ifneq ($(filter %86,$(UNAME_P)),)
        CCFLAGS += -D IA32
    endif
    ifneq ($(filter arm%,$(UNAME_P)),)
        CCFLAGS += -D ARM
    endif
endif

8
अफसोस की बात यह है PROCESSOR_ARCHITECTUREकि यह प्रक्रिया 32-बिट या 64-बिट के आधार पर एन्वारराइज की गई है। इसलिए यदि आपका make32-बिट है और आप 64-बिट एप्लिकेशन बनाने का प्रयास कर रहे हैं, तो यह विफल हो जाएगा। PROCESSOR_ARCHITEW6432मेरे साथ काम करने के संयोजन में इसका उपयोग करना ( यह देखें , और वह )
थॉमस

4
अच्छा होगा यदि makeटीम ओएस और आर्च के साथ कुछ जादुई चर जोड़ दे, शायद बहुत परेशानी हो।
एलेक्स

6
@JanusTroelsen: यह कोई फर्क नहीं पड़ता कि क्या OSगैर-विंडोज सिस्टम पर सेट है। व्यवहार को खाली के रूप में ही परेशान करें, जो uname-based ब्लॉक के लिए एक कूद का कारण होगा । आपको बस वहां एक FreeBSD चेक जोड़ना होगा।
ट्रेवर रॉबिन्सन

3
यह ओएक्सएक्स पर भी टूट जाता है। /bin/sh: -c: line 0: syntax error near unexpected token , Windows_NT '/ bin / sh: -c: लाइन 0:ifeq (,Windows_NT)' make: *** [os] Error 2
k107

1
@kristi ऐसा लगता है कि आपने इसे शेल कमांड के रूप में चलाया है न कि मेकफाइल निर्देश संदर्भ में।
फॉर्ड

119

बिना किसी पैरामीटर के अनाम कमांड ( http://developer.apple.com/documentation/Darwin/Reference/ManPages/man1/uname.1.html ) आपको ऑपरेटिंग सिस्टम का नाम नहीं बताना चाहिए। मैं इसका उपयोग करूंगा, फिर वापसी के मूल्य के आधार पर सशर्त बनाऊंगा।

उदाहरण

UNAME := $(shell uname)

ifeq ($(UNAME), Linux)
# do something Linux-y
endif
ifeq ($(UNAME), Solaris)
# do something Solaris-y
endif

बस स्पष्ट होने के लिए, वह लाइन आपके मेकफाइल में जाती है। मैंने सिगविन और OSX में मेकफाइल्स में उस निर्माण की कोशिश की, और यह उम्मीद के मुताबिक काम किया। कुछ करने की कोशिश: अपनी कमांड लाइन पर टाइप करें। वह आपको उस OS का मान बताएगा। OSX संभवतः "डार्विन" होगा।
dbrown0708

GnuWin32 परियोजना के दोनों नाम और Gnu देशी विंडोज अनुप्रयोगों के रूप में उपलब्ध हैं, इस तकनीक को एक कमांड प्रॉम्प्ट पर MingW के साथ-साथ विंडोज पर Cygwin में पोर्टेबल बनाते हैं।
RBerteig

यह मेरे सोलारिस मशीन पर विफल रहता है जब यह मेकफाइल के अंदर होता है। उस सिस्टम पर uname कमांड उपलब्ध है।
समोझ

4
ध्यान दें कि यदि आप इसे Maketarget के अंदर रखते हैं तो इसे इंडेंट नहीं किया जाना चाहिए।
नाइलंड

4
GNU मेक के लिए ": =" सिंटैक्स विशिष्ट नहीं है?
अंकुर सेठी

40

दो सरल चाल का उपयोग कर ऑपरेटिंग सिस्टम का पता लगाएं:

  • पहले पर्यावरण चर OS
  • फिर unameआज्ञा
ifeq ($(OS),Windows_NT)     # is Windows_NT on XP, 2000, 7, Vista, 10...
    detected_OS := Windows
else
    detected_OS := $(shell uname)  # same as "uname -s"
endif

या अधिक सुरक्षित तरीका, यदि विंडोज पर unameउपलब्ध नहीं है और अनुपलब्ध है:

ifeq ($(OS),Windows_NT) 
    detected_OS := Windows
else
    detected_OS := $(shell sh -c 'uname 2>/dev/null || echo Unknown')
endif

यदि आप Cygwin / MinGW / MSYS / Windows को अलग करना चाहते हैं तो केन जैक्सन एक दिलचस्प विकल्प का प्रस्ताव करता है। उसका जवाब देखें जो इस तरह दिखता है:

ifeq '$(findstring ;,$(PATH))' ';'
    detected_OS := Windows
else
    detected_OS := $(shell uname 2>/dev/null || echo Unknown)
    detected_OS := $(patsubst CYGWIN%,Cygwin,$(detected_OS))
    detected_OS := $(patsubst MSYS%,MSYS,$(detected_OS))
    detected_OS := $(patsubst MINGW%,MSYS,$(detected_OS))
endif

फिर आप संबंधित सामान का चयन कर सकते हैं detected_OS:

ifeq ($(detected_OS),Windows)
    CFLAGS += -D WIN32
endif
ifeq ($(detected_OS),Darwin)        # Mac OS X
    CFLAGS += -D OSX
endif
ifeq ($(detected_OS),Linux)
    CFLAGS   +=   -D LINUX
endif
ifeq ($(detected_OS),GNU)           # Debian GNU Hurd
    CFLAGS   +=   -D GNU_HURD
endif
ifeq ($(detected_OS),GNU/kFreeBSD)  # Debian kFreeBSD
    CFLAGS   +=   -D GNU_kFreeBSD
endif
ifeq ($(detected_OS),FreeBSD)
    CFLAGS   +=   -D FreeBSD
endif
ifeq ($(detected_OS),NetBSD)
    CFLAGS   +=   -D NetBSD
endif
ifeq ($(detected_OS),DragonFly)
    CFLAGS   +=   -D DragonFly
endif
ifeq ($(detected_OS),Haiku)
    CFLAGS   +=   -D Haiku
endif

टिप्पणियाँ:

  • आदेश unameसमान है uname -sक्योंकि विकल्प -s( --kernel-name) डिफ़ॉल्ट है। देखें क्यों uname -sकी तुलना में बेहतर हैuname -o

  • OS(के बजाय uname) का उपयोग पहचान एल्गोरिथ्म को सरल करता है। आप अभी भी पूरी तरह से उपयोग कर सकते हैं uname, लेकिन आपको if/elseसभी MinGW, Cygwin, आदि विविधताओं की जांच करने के लिए ब्लॉकों से निपटना होगा ।

  • पर्यावरण चर OSहमेशा "Windows_NT"अलग-अलग विंडोज संस्करणों पर सेट होता है ( %OS%विकिपीडिया पर पर्यावरण चर देखें )।

  • OSपर्यावरण चर का एक विकल्प है MSVC(यह एमएस विज़ुअल स्टूडियो की उपस्थिति की जांच करता है , दृश्य सी ++ का उपयोग करके उदाहरण देखें )।


नीचे मैं एक साझा पुस्तकालय का उपयोग कर makeऔर एक पूर्ण उदाहरण प्रदान करता हूं gcc: *.soया *.dllप्लेटफॉर्म पर निर्भर करता है। उदाहरण उतना ही सरल है जितना अधिक समझा जा सकता है।

विंडोज पर स्थापित करने makeऔर gccदेखने के लिए Cygwin या MinGW देखें ।

मेरा उदाहरण पांच फाइलों पर आधारित है

 ├── lib
    └── Makefile
    └── hello.h
    └── hello.c
 └── app
     └── Makefile
     └── main.c

अनुस्मारक: सारणीकरणMakefile का उपयोग करने के लिए प्रेरित किया जाता है । नमूना फ़ाइलों के नीचे कॉपी-पेस्ट करते समय सावधानी।

दो Makefileफाइलें

1। lib/Makefile

ifeq ($(OS),Windows_NT)
    uname_S := Windows
else
    uname_S := $(shell uname -s)
endif

ifeq ($(uname_S), Windows)
    target = hello.dll
endif
ifeq ($(uname_S), Linux)
    target = libhello.so
endif
#ifeq ($(uname_S), .....) #See https://stackoverflow.com/a/27776822/938111
#    target = .....
#endif

%.o: %.c
    gcc  -c $<  -fPIC  -o $@
    # -c $<  => $< is first file after ':' => Compile hello.c
    # -fPIC  => Position-Independent Code (required for shared lib)
    # -o $@  => $@ is the target => Output file (-o) is hello.o

$(target): hello.o
    gcc  $^  -shared  -o $@
    # $^      => $^ expand to all prerequisites (after ':') => hello.o
    # -shared => Generate shared library
    # -o $@   => Output file (-o) is $@ (libhello.so or hello.dll)

2। app/Makefile

ifeq ($(OS),Windows_NT)
    uname_S := Windows
else
    uname_S := $(shell uname -s)
endif

ifeq ($(uname_S), Windows)
    target = app.exe
endif
ifeq ($(uname_S), Linux)
    target = app
endif
#ifeq ($(uname_S), .....) #See https://stackoverflow.com/a/27776822/938111
#    target = .....
#endif

%.o: %.c
    gcc  -c $< -I ../lib  -o $@
    # -c $<     => compile (-c) $< (first file after :) = main.c
    # -I ../lib => search headers (*.h) in directory ../lib
    # -o $@     => output file (-o) is $@ (target) = main.o

$(target): main.o
    gcc  $^  -L../lib  -lhello  -o $@
    # $^       => $^ (all files after the :) = main.o (here only one file)
    # -L../lib => look for libraries in directory ../lib
    # -lhello  => use shared library hello (libhello.so or hello.dll)
    # -o $@    => output file (-o) is $@ (target) = "app.exe" or "app"

अधिक जानने के लिए, cfi द्वारा इंगित स्वचालित चर दस्तावेज़ पढ़ें ।

स्रोत कोड

- lib/hello.h

#ifndef HELLO_H_
#define HELLO_H_

const char* hello();

#endif

- lib/hello.c

#include "hello.h"

const char* hello()
{
    return "hello";
}

- app/main.c

#include "hello.h" //hello()
#include <stdio.h> //puts()

int main()
{
    const char* str = hello();
    puts(str);
}

निर्माण

की कॉपी-पेस्ट को ठीक करें Makefile(प्रमुख स्थानों को एक सारणीकरण द्वारा बदलें)।

> sed  's/^  */\t/'  -i  */Makefile

makeआदेश दोनों प्लेटफ़ॉर्म पर ही है। दिए गए आउटपुट यूनिक्स जैसे OSes पर है:

> make -C lib
make: Entering directory '/tmp/lib'
gcc  -c hello.c  -fPIC  -o hello.o
# -c hello.c  => hello.c is first file after ':' => Compile hello.c
# -fPIC       => Position-Independent Code (required for shared lib)
# -o hello.o  => hello.o is the target => Output file (-o) is hello.o
gcc  hello.o  -shared  -o libhello.so
# hello.o        => hello.o is the first after ':' => Link hello.o
# -shared        => Generate shared library
# -o libhello.so => Output file (-o) is libhello.so (libhello.so or hello.dll)
make: Leaving directory '/tmp/lib'

> make -C app
make: Entering directory '/tmp/app'
gcc  -c main.c -I ../lib  -o main.o
# -c main.c => compile (-c) main.c (first file after :) = main.cpp
# -I ../lib => search headers (*.h) in directory ../lib
# -o main.o => output file (-o) is main.o (target) = main.o
gcc  main.o  -L../lib  -lhello  -o app
# main.o   => main.o (all files after the :) = main.o (here only one file)
# -L../lib => look for libraries in directory ../lib
# -lhello  => use shared library hello (libhello.so or hello.dll)
# -o app   => output file (-o) is app.exe (target) = "app.exe" or "app"
make: Leaving directory '/tmp/app'

दौड़

आवेदन के लिए यह जानना आवश्यक है कि साझा पुस्तकालय कहां है।

विंडोज पर, एक सरल समाधान यह है कि लाइब्रेरी को कॉपी किया जाए जहां आवेदन है:

> cp -v lib/hello.dll app
`lib/hello.dll' -> `app/hello.dll'

यूनिक्स जैसे OSes पर, आप LD_LIBRARY_PATHपर्यावरण चर का उपयोग कर सकते हैं :

> export LD_LIBRARY_PATH=lib

Windows पर कमांड चलाएँ:

> app/app.exe
hello

यूनिक्स की तरह OSes पर कमांड चलाएँ:

> app/app
hello

मैं आपके प्रयास की सराहना करता हूं, लेकिन मुख्य सवाल ऑपरेटिंग सिस्टम का पता लगाना था। आपका उदाहरण केवल लिनक्स का पता लगाता है और अन्यथा विंडोज को सही मानता है।
शाहबाज़ 16

हाय @ शहबाज। आप सही हैं, मेरा जवाब अन्य उत्तरों की तुलना में एक अलग दृष्टिकोण नहीं देता है। इसके अलावा, मेरी स्क्रिप्ट मानता है कि प्लेटफॉर्म विंडोज है जब unameलिनक्स नहीं है। मैं सिर्फ एक उदाहरण देता हूं जिसकी आपको आवश्यकता नहीं हो सकती है, लेकिन यह किसी को (वेब ​​पर) खोज करने में मदद कर सकता है Makefileदोनों प्लेटफार्मों के लिए लागू करने का एक तरीका ;-) मुझे अपने उत्तर में क्या बदलना चाहिए? चीयर्स
ओलिब्रे

अन्य ऑपरेटिंग सिस्टम को भी सही ढंग से पहचानने के तरीकों के साथ आने की कोशिश करें! लक्ष्य एक ऐसी विधि को खोजना है जो बहुत जटिल नहीं है, लेकिन अधिक महत्वपूर्ण बात बुलेट प्रूफ है। यही है, यह कोई बात नहीं क्या गलती नहीं होगी।
शाहबाज

1
@olibre विस्तृत उदाहरण के लिए धन्यवाद, बहुत सराहना की और मुझे जल्दी शुरू करने में मदद करता है। में lib/Makefileउदाहरण के लिए, targetके लिए प्रयोग किया जाता है .soबनाम .dll। अनुप्रयोग फ़ाइल नाम के लिए बनाम तुलना के लिए एक समानांतर उदाहरण app/makefileउपयोगी होगा । उदाहरण के लिए, मैं आमतौर पर यूनिक्स जैसे OSes पर नहीं देखता । ;-)empty string.exeapp.exe

1
LSF? LFS? लेखन त्रुटि है?
फ्रैंकलिन यू

19

मैं हाल ही में प्रयोग कर रहा था इस सवाल का जवाब देने के लिए मैं खुद से पूछ रहा था। यहाँ मेरे निष्कर्ष हैं:

चूंकि विंडोज में, आप यह सुनिश्चित नहीं कर सकते कि unameकमांड उपलब्ध है, आप उपयोग कर सकते हैं gcc -dumpmachine। यह संकलक लक्ष्य प्रदर्शित करेगा।

unameयदि आप कुछ क्रॉस-संकलन करना चाहते हैं तो उपयोग करते समय एक समस्या भी हो सकती है ।

यहाँ के संभावित उत्पादन की एक उदाहरण सूची है gcc -dumpmachine:

  • mingw32
  • i686-पीसी-cygwin
  • x86_64-redhat-linux

आप इस तरह से मेकफाइल में परिणाम की जांच कर सकते हैं:

SYS := $(shell gcc -dumpmachine)
ifneq (, $(findstring linux, $(SYS)))
 # Do Linux things
else ifneq(, $(findstring mingw, $(SYS)))
 # Do MinGW things
else ifneq(, $(findstring cygwin, $(SYS)))
 # Do Cygwin things
else
 # Do things for others
endif

इसने मेरे लिए अच्छा काम किया, लेकिन मुझे यकीन नहीं है कि यह सिस्टम प्रकार प्राप्त करने का एक विश्वसनीय तरीका है। कम से कम यह MinGW के बारे में विश्वसनीय है और यही सब मुझे चाहिए क्योंकि इसके लिए विंडोज में unameकमांड या MSYS पैकेज की आवश्यकता नहीं है ।

योग करने के लिए, unameआपको वह सिस्टम देता है जिस पर आप संकलन कर रहे हैं, और gcc -dumpmachineआपको वह प्रणाली प्रदान करता है जिसके लिए आप संकलन कर रहे हैं।


यह लाभप्रद है। हालांकि, वैसे भी नहीं unameआता MinGWहै? फिर भी, क्रॉस-संकलन के बारे में अतिरिक्त नोट महान है।
शाहबाज

2
@ शहबाज मिंजडब्ल्यू सेटअप एमएसवाईएस (जिसमें नाम शामिल है) स्थापित कर सकता है, लेकिन यह विकल्प है। यह अभी भी केवल MinGW gcc टूल्स के साथ सिस्टम ढूंढना संभव है
phsym

1
यह कहीं भी काम नहीं करता है क्लैंग डिफ़ॉल्ट संकलक है, जैसे ओएस एक्स और फ्रीबीएसडी।
मार्कस जे

@ एसबेस्टियनगोडलेट @MarcusJ एक आसान फिक्स है $(shell $(CC) -dumpmachine)। ओएस एक्स सिएरा के रूप में, -dumpmachine कमांड क्लैंग पर काम करता है।
वोर्टिको

पर ओएस एक्स 10.12.5 यह है x86_64-apple-darwin16.6.0और आप मौसम काम करता है इसे कहते है कि gcc, ccया clangनहीं, बल्किcl
MarcusJ

17

Git makefile कैसे बिना autoconf / automake, फिर भी अभी भी Unixy प्लेटफार्मों की एक भीड़ पर काम का प्रबंधन करने के कई उदाहरण हैं।


13
यह जानते हुए भी कि गित ऑटोफूल का उपयोग किसी तरह नहीं करती है, मुझे उनके प्रति घृणा का औचित्य साबित होता है ...
Dan Molding

11
"Autofools"? क्या वह जानबूझकर टाइपो था? :)
जेस्पर

6
ये था। लेकिन दूसरे विचार पर, मुझे लगता है कि मुझे "ऑटोस्टॉल्स" भी बेहतर लगता है। : डी
डैन मोल्डिंग

Btw, आप "उन्हें" से कौन मतलब था? गिट या ऑटोटूलस लोग? : डी
जेस्पर

8
अंग्रेजी एक ऐसी अभेद्य भाषा है। इसके बारे में कैसे: if (!usesAutotools(git)) aversionTo(autotools) = justified;मैं यह भी स्पष्ट कर दूंगा कि यह केवल वह उपकरण है जिससे मैं प्रभावित हूं। मुझे यकीन है कि ऑटोटूलस लोग अच्छे लोग हैं।
दान मोल्डिंग

11

अद्यतन: मैं अब इस उत्तर को अप्रचलित मानता हूं। मैंने आगे एक नया परफेक्ट सॉल्यूशन पोस्ट किया।

यदि आपका मेकफाइल गैर- Cygwin Windows पर चल रहा unameहो, तो उपलब्ध नहीं हो सकता है। यह अजीब है, लेकिन यह एक संभावित समाधान है। आपको इसे शासन करने के लिए पहले Cygwin की जांच करनी होगी, क्योंकि इसके PATHपर्यावरण चर में भी WINDOWS है।

ifneq (,$(findstring /cygdrive/,$(PATH)))
    UNAME := Cygwin
else
ifneq (,$(findstring WINDOWS,$(PATH)))
    UNAME := Windows
else
    UNAME := $(shell uname -s)
endif
endif

यह अब अच्छा है! क्या आप मुझे एक बात बता सकते हैं, हालांकि? मैं Cygwin का उपयोग नहीं करता, लेकिन मेरे पास PATH में बिन पथ के साथ MinGW स्थापित है। अगर मैं unameएक सामान्य cmd टर्मिनल से जारी करता हूं तो यह मुझे MINGW देता है। मेरा मतलब है, मैं अभी भी unameCygwin का उपयोग किए बिना है। मेरे पास गिट बैश भी है, लेकिन मैंने इस पर बिना नाम लिए कोशिश नहीं की है (अभी मैं लिनक्स में हूं)। क्या आप मुझे बता सकते हैं कि इन दोनों को आपके कोड में कैसे शामिल किया जा सकता है?
शाहबाज़

यदि आप सुनिश्चित हैं कि अनाम उपलब्ध है, तो यह सबसे अच्छा समाधान है। लेकिन मेरे वातावरण में, हर कोई विंडोज़ का उपयोग कर रहा है और कुछ लोगों के पास या तो साइबरविन या मिंगव स्थापित है, इसलिए मुझे कोई गारंटी नहीं है कि मानक के रूप में भी कुछ भी काम नहीं करेगा। मुझे वर्तमान में cmd ​​शेल में Make.exe के ऊपर कोड को चलाने में थोड़ी परेशानी हो रही है। विंडोज के साथ काम करने के लिए एक बहुत निराशाजनक मंच है।
केन जैक्सन

मेरे कहने का मतलब है कि पैट में विन्डोज़ के अस्तित्व के परीक्षण से पहले, आप सुनिश्चित करें कि आप साइबरविन के साथ काम नहीं कर रहे हैं, आप यह कैसे सुनिश्चित कर सकते हैं कि आप मिनगव के साथ काम नहीं कर रहे हैं? उदाहरण के लिए, क्या मेकफाइल में यह जांचना संभव है कि क्या कमांड चलाया जा सकता है, और अगर unameनहीं चलाया जा सकता है तो हम समझेंगे कि हम विंडोज में हैं?
शहबाज

मैं इस मिंगव / साइबरविन / शेल-या-सीएमडी / लिनक्स के साथ-साथ एक स्वच्छ समाधान खोजने के लिए संघर्ष कर रहा हूं। दिन के अंत में, कुछ नकली या सेमीक सबसे अच्छा विचार लगता है।
इसहाक नेक्विटेपास

यह अब सबसे अच्छा समाधान नहीं है। मैंने जो नया समाधान पोस्ट किया है, वह ''; 'की तलाश में देशी विंडोज को अलग करता है। पथ चर में, बिना शेल कॉल के।
केन जैक्सन

7

यही वह काम है जिसे जीएनयू का ऑटोमेटेक / ऑटोकॉन्फ़ हल करने के लिए डिज़ाइन किया गया है। आप उनकी जांच करना चाह सकते हैं।

वैकल्पिक रूप से आप अपने विभिन्न प्लेटफार्मों पर पर्यावरण चर सेट कर सकते हैं और आपको उनके खिलाफ मेकफाइल सशर्त बना सकते हैं।


11
मैं ऑटोमेट / ऑटोकॉन्फ़ का उपयोग करने के खिलाफ दृढ़ता से सलाह देता हूं। वे उपयोग करने के लिए थकाऊ हैं, आपकी फ़ाइलों के लिए बहुत सारे ओवरहेड जोड़ सकते हैं, अपने निर्माण समय के लिए। वे आमतौर पर बहुत कम प्रभाव (अभी भी सिस्टम के बीच कोई पोर्टेबिलिटी नहीं) के लिए जटिलता जोड़ते हैं।
जोहान्स ओवरमैन

1
मैंने अभी कुछ दिन बिताने के makeलिए जो मुझे चाहिए उसे करने के लिए सीख लिया । क्या मैं अब ऑटोमेटेक / ऑटोकॉन्फ़ में भी जाना चाहता हूँ? - नहीं। मेकफाइल में क्या किया जा सकता है, निश्चित रूप से मेकफाइल में किया जाना चाहिए, यदि केवल इतना है कि मेरे पास संकलन और लिंक में संशोधन के लिए हर बार कई स्टॉप-ऑफ बिंदु नहीं हैं।
इंजीनियर

आपके मेकफाइल्स को कितने प्लेटफॉर्म सपोर्ट करते हैं? जब आप कई प्लेटफार्मों के लिए पोर्टेबिलिटी चाहते हैं, तो स्वचालित और ऑटोकॉन्फ़ वास्तव में अपने आप में आ जाते हैं।
डगलस लीडर

2
मुझे बेकार निर्भरता की आवश्यकता नहीं है, और यह पता लगाने के लिए कि यह किस ओएस के लिए संकलित किया जा रहा है, बस अपने पूरे बिल्ड सिस्टम को बदल दें।
मार्कस जे

7

मैंने आखिरकार सही समाधान ढूंढ लिया जो मेरे लिए इस समस्या को हल करता है।

ifeq '$(findstring ;,$(PATH))' ';'
    UNAME := Windows
else
    UNAME := $(shell uname 2>/dev/null || echo Unknown)
    UNAME := $(patsubst CYGWIN%,Cygwin,$(UNAME))
    UNAME := $(patsubst MSYS%,MSYS,$(UNAME))
    UNAME := $(patsubst MINGW%,MSYS,$(UNAME))
endif

UNAME चर Linux, Cygwin, MSYS, Windows, FreeBSD, NetBSD (या संभवतः सोलारिस, डार्विन, ओपनबीएसडी, AIX, HP-UX), या अज्ञात पर सेट है। इसके बाद किसी भी OS-संवेदनशील चर और कमांड को अलग करने के लिए Makefile के शेष भाग में तुलना की जा सकती है।

कुंजी यह है कि विंडोज पैथ वेरिएबल में अलग-अलग रास्तों के लिए अर्धविराम का उपयोग करता है जबकि बाकी सभी कॉलन का उपयोग करते हैं। (नाम के साथ '?' नाम से लिनक्स निर्देशिका बनाना संभव है और इसे पाथ में जोड़ें, जो इसे तोड़ देगा, लेकिन कौन ऐसा काम करेगा?) यह देशी विंडोज का पता लगाने के लिए सबसे कम जोखिम भरा तरीका लगता है क्योंकि शेल कॉल की जरूरत नहीं है। इसलिए Cygwin और MSYS पथ का उपयोग कोलन uname उनके लिए कहा जाता है।

ध्यान दें कि विंडोज़ का पता लगाने के लिए ओएस पर्यावरण चर का उपयोग किया जा सकता है, लेकिन सिग्विन और देशी विंडोज के बीच अंतर करने के लिए नहीं। उद्धरणों की गूंज के लिए परीक्षण कार्य करता है, लेकिन इसके लिए शेल कॉल की आवश्यकता होती है।

दुर्भाग्य से, Cygwin के उत्पादन के लिए कुछ संस्करण जानकारी जोड़ता uname , तो मैं 'patsubst' कॉल जोड़ा सिर्फ 'Cygwin' के लिए इसे बदलने के लिए। इसके अलावा, MSYS के लिए uname वास्तव में MSYS या MINGW से शुरू होने वाले तीन संभावित आउटपुट हैं, लेकिन मैं सभी को सिर्फ 'MSYS' में बदलने के लिए भी patsubst का उपयोग करता हूं।

यदि पथ पर कुछ uname.exe के साथ और उसके बिना देशी विंडोज सिस्टम के बीच अंतर करना महत्वपूर्ण है, तो इस लाइन का उपयोग साधारण असाइनमेंट के बजाय किया जा सकता है:

UNAME := $(shell uname 2>NUL || echo Windows)

निश्चित रूप से सभी मामलों में जीएनयू मेक की आवश्यकता होती है, या एक अन्य मेक का उपयोग किया जाता है।


6

मैं आज इस समस्या में भाग गया और मुझे इसकी आवश्यकता सोलारिस पर पड़ी, इसलिए यहाँ POSIX मानक तरीका है (इसे कुछ बहुत ही करीब से)।

#Detect OS
UNAME = `uname`

# Build based on OS name
DetectOS:
    -@make $(UNAME)


# OS is Linux, use GCC
Linux: program.c
    @SHELL_VARIABLE="-D_LINUX_STUFF_HERE_"
    rm -f program
    gcc $(SHELL_VARIABLE) -o program program.c

# OS is Solaris, use c99
SunOS: program.c
    @SHELL_VARIABLE="-D_SOLARIS_STUFF_HERE_"
    rm -f program
    c99 $(SHELL_VARIABLE) -o program program.c

1
OSX पर त्रुटि हो रही है: "मेकफाइल: 22: *** लापता विभाजक। बंद करो।" इस लाइन पर: "- @ मेक $ (UNAME_S)"।
Czarek Tomczak

OSX संभावना आज्ञाकारी नहीं है, इसलिए इन्हें क्रम में आज़माएं। (1) सुनिश्चित करें कि आप लाइन पर पहले चरित्र के रूप में एक TAB का उपयोग कर रहे हैं (2) मेक के सामने "- @" निकालें (2a) यदि 2 काम किया है, तो एक वर्ण का प्रयास करें और फिर दूसरा (3) सुनिश्चित करें कि UNAME_S को परिभाषित किया गया है, इसके बजाय echo $ (UNAME_S) का प्रयास करें - @ make $ (UNAME_S)
Huckle

6

यहाँ एक सरल समाधान है जो यह जाँचता है कि क्या आप विंडोज या पॉज़िक्स-लाइकस (लिनक्स / यूनिक्स / साइगविन / मैक) वातावरण में हैं:

ifeq ($(shell echo "check_quotes"),"check_quotes")
   WINDOWS := yes
else
   WINDOWS := no
endif

यह इस तथ्य का लाभ उठाता है कि पॉज़िक्स-जैसे और विंडोज दोनों वातावरणों में गूंज मौजूद है, और विंडोज में शेल उद्धरणों को फ़िल्टर नहीं करता है।


1
क्योंकि असुरक्षित $PATHएक और echo(मेरा करता है ...) का उल्लेख कर सकता है
yyny

@YoYoYonnY आपका रास्ता किसी अन्य प्रतिध्वनि का संदर्भ क्यों देता है? एक बहुत ही असंभावित स्थिति की तरह लगता है।
शमूएल

1
वास्तव में नहीं, git इसे करता है, mingw करता है, cygwin करता है ... और मैंने व्यक्तिगत रूप से C: \ Windows \ System32 को मेरे पथ के नीचे रखा है।
yyny

1
यह "समाधान" सभी वातावरणों के लिए "काम करता है", लेकिन मेरा कहना यह है कि यह निश्चित रूप से सुरक्षित रूप से खिड़कियों का पता नहीं लगाता है। मैं एक सेट करना चाहते हैं -mwindowsझंडा या एक के बीच चुना .dllया .so, इस विफल हो जाएगा।
yyny

1
@YoYoYonnY स्पष्ट करने के लिए धन्यवाद। अपनी स्थिति में मैंने केवल तभी ध्यान रखा, जब मैं ओएस मैं था, बजाय सिग्विन या विंडोज या लिनक्स वातावरण में था, इसलिए यह मेरे लिए मददगार था। लगता है जैसे आपकी जरूरतें मेरी हैं उससे अलग हैं।
शमूएल

3

ध्यान दें कि Makefiles रिक्ति के लिए बेहद संवेदनशील हैं। यहाँ एक मेकफाइल का उदाहरण दिया गया है जो OS X पर एक अतिरिक्त कमांड चलाता है और जो OS X और Linux पर काम करता है। कुल मिलाकर, हालांकि, ऑटोकॉन्फ़ / ऑटोमेक सभी गैर-तुच्छ चीज़ों के लिए कुछ भी जाने का रास्ता है।

UNAME: = $ (शेल नाम -s)
सीपीपी = जी ++
CPPFLAGS = -pthread -ansi -Wall -errerr -pedantic -O0 -g3 -I / nexopia / शामिल
LDFLAGS = -pthread -L / nexopia / lib -lboost_system

HEADERS = data_structures.h http_client.h load.h lock.h search.h server.h thread.h उपयोगिता
OBJECTS = http_client.o load.o lock.o search.o server.o thread.o उपयोगिता.oor.o

सभी: vor

स्वच्छ:
    rm -f $ (OBJECTS) vor

vor: $ (OBJECTS)
    $ (CPP) $ (LDFLAGS) -o vor $ (OBJECTS)
ifeq ($ (UNAME), डार्विन)
    # बूस्ट लाइब्रेरी का स्थान निर्धारित करें
    install_name_tool -change libboost_system.dylib /nexopia/lib/libboost_system.dylib vor
अगर अंत

% .o:% .cpp $ (HEADERS) मेकफाइल
    $ (CPP) $ (CPPFLAGS) -c $

2

ऐसा करने का एक और तरीका "कॉन्फ़िगर" स्क्रिप्ट का उपयोग करना है। यदि आप पहले से ही अपने मेकफाइल के साथ एक का उपयोग कर रहे हैं, तो आप काम करने के लिए चीजों को प्राप्त करने के लिए अनाम और सेड के संयोजन का उपयोग कर सकते हैं। सबसे पहले, अपनी स्क्रिप्ट में, करें:

UNAME=uname

फिर, इसे अपने मेकफाइल में डालने के लिए, Makefile.in से शुरू करें, जिसमें कुछ ऐसा होना चाहिए

UNAME=@@UNAME@@

इस में।

UNAME=unameबिट के बाद अपनी कॉन्फ़िगर स्क्रिप्ट में निम्न sed कमांड का उपयोग करें ।

sed -e "s|@@UNAME@@|$UNAME|" < Makefile.in > Makefile

अब आपके मेकफाइल UNAMEको वांछित के रूप में परिभाषित किया जाना चाहिए । यदि / elif / अन्यथा कथन सभी शेष हैं!


क्या पहले समान नहीं होना चाहिए? UNAME = $ (uname)
केन जैक्सन

0

मेरे पास एक ऐसा मामला था जहां मुझे
inkscape के लिए कमांड-लाइन विकल्पों को ट्विक करने के लिए Fedora के दो संस्करणों के बीच अंतर का पता लगाना था: - Fedora 31 में, डिफ़ॉल्ट inkscape 1.0beta है जो उपयोग करता है --export-file
- Fedora <31 में, डिफ़ॉल्ट inkscape है 0.92 जो उपयोग करता है--export-pdf

मेरे Makefile में निम्नलिखित शामिल हैं

# set VERSION_ID from /etc/os-release

$(eval $(shell grep VERSION_ID /etc/os-release))

# select the inkscape export syntax

ifeq ($(VERSION_ID),31)
EXPORT = export-file
else
EXPORT = export-pdf
endif

# rule to convert inkscape SVG (drawing) to PDF

%.pdf : %.svg
    inkscape --export-area-drawing $< --$(EXPORT)=$@

यह काम करता है क्योंकि /etc/os-releaseइसमें एक रेखा होती है

VERSION_ID=<value>

इसलिए मेकफाइल में शेल कमांड स्ट्रिंग को लौटाता है VERSION_ID=<value>, तो eval कमांड मेकफाइल वेरिएबल को सेट करने के लिए इस पर कार्य करता है VERSION_ID। यह स्पष्ट रूप से अन्य OS के लिए निर्भर करता है कि मेटाडेटा कैसे संग्रहीत किया जाता है। ध्यान दें कि फेडोरा में एक डिफ़ॉल्ट वातावरण चर नहीं है जो ओएस संस्करण देता है, अन्यथा मैंने इसका उपयोग किया होता!

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.