Makefile di rilevamento del sistema operativo


249

Lavoro regolarmente su diversi computer e diversi sistemi operativi, che sono Mac OS X, Linux o Solaris. Per il progetto a cui sto lavorando, estraggo il mio codice da un repository git remoto.

Mi piace essere in grado di lavorare sui miei progetti indipendentemente dal terminale in cui mi trovo. Finora, ho trovato il modo di aggirare le modifiche del sistema operativo modificando il makefile ogni volta che cambio computer. Tuttavia, questo è noioso e provoca un sacco di mal di testa.

Come posso modificare il mio makefile in modo che rilevi quale sistema operativo sto usando e modifica la sintassi di conseguenza?

Ecco il makefile:

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

Risposte:


282

Ci sono già molte buone risposte qui, ma volevo condividere un esempio più completo che entrambi:

  • non presuppone che unameesista su Windows
  • rileva anche il processore

I CCFLAGS qui definiti non sono necessariamente consigliati o ideali; sono proprio quello che stava usando il progetto a cui stavo aggiungendo il rilevamento automatico 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
Purtroppo, PROCESSOR_ARCHITECTUREenvvar sembra essere virtualizzato a seconda che il processo sia a 32 o 64 bit. Quindi, se il tuo makeè a 32 bit e stai cercando di creare un'applicazione a 64 bit, fallirà. Usandolo in combinazione con PROCESSOR_ARCHITEW6432lavorato per me (vedi questo e quello )
Thomas,

4
Sarebbe bello se il maketeam aggiungesse un paio di variabili magiche con os e arch, probabilmente troppi problemi.
Alex,

6
@JanusTroelsen: non dovrebbe importare se OSè impostato su sistemi non Windows. Fai in modo che gli ossequi non siano impostati come vuoti, il che causerà un salto al unameblocco basato su. Devi solo aggiungere un controllo FreeBSD lì.
Trevor Robinson,

3
questo si rompe anche su osx. /bin/sh: -c: line 0: syntax error near unexpected token , Windows_NT '/ bin / sh: -c: linea 0:ifeq (,Windows_NT)' make: *** [os] Error 2
k107

1
@kristi Sembra che tu l'abbia eseguito come comandi shell e non nel contesto delle direttive makefile.
phord

119

Il comando uname ( http://developer.apple.com/documentation/Darwin/Reference/ManPages/man1/uname.1.html ) senza parametri dovrebbe indicare il nome del sistema operativo. Lo userei, quindi creerei condizionali in base al valore restituito.

Esempio

UNAME := $(shell uname)

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

Giusto per essere esplicito, quella linea va nel tuo Makefile. Ho appena provato quel costrutto in Makefile in Cygwin e OSX, e ha funzionato come previsto. Qualcosa da provare: digitare uname sulla riga di comando. Questo ti dirà il valore per quel sistema operativo. OSX sarà probabilmente "Darwin".
dbrown0708,

Il progetto GnuWin32 ha sia uname che Gnu resi disponibili come applicazioni Windows native, rendendo questa tecnica portabile su MingW al prompt dei comandi e su Cygwin su Windows.
RBerteig

Non riesce sulla mia macchina Solaris quando si trova all'interno del makefile. Il comando uname è disponibile su quel sistema.
samoz,

4
Nota che se lo metti all'interno di un Maketarget non deve essere rientrato.
nylund,

4
La sintassi ": =" non è specifica di GNU Make?
Ankur Sethi,

40

Rileva il sistema operativo utilizzando due semplici trucchi:

  • Innanzitutto la variabile d'ambiente OS
  • Quindi il unamecomando
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

O un modo più sicuro, se non su Windows e unamenon disponibile:

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

Ken Jackson propone un'alternativa interessante se si desidera distinguere Cygwin / MinGW / MSYS / Windows. Vedi la sua risposta che assomiglia a quella:

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

Quindi è possibile selezionare gli elementi pertinenti in base a 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

Appunti:

  • Il comando unameè uguale a uname -sperché option -s( --kernel-name) è l'impostazione predefinita. Scopri perché uname -sè meglio diuname -o .

  • L'uso di OS(anziché uname) semplifica l'algoritmo di identificazione. Puoi ancora usare esclusivamente uname, ma devi gestire i if/elseblocchi per controllare tutte le variazioni di MinGW, Cygwin, ecc.

  • La variabile d'ambiente OSè sempre impostata "Windows_NT"su diverse versioni di Windows (vedi %OS%variabile d'ambiente su Wikipedia ).

  • Un'alternativa di OSè la variabile d'ambiente MSVC(controlla la presenza di MS Visual Studio , vedi esempio usando Visual C ++ ).


Di seguito fornisco un esempio completo utilizzando makee gccper creare una libreria condivisa: *.soo in *.dllbase alla piattaforma. L'esempio è il più semplice possibile per essere più comprensibile.

Per installare makee gccsu Windows vedi Cygwin o MinGW .

Il mio esempio si basa su cinque file

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

Promemoria: Makefile è rientrato usando la tabulazione . Attenzione quando si copia e incolla sotto i file di esempio.

I due Makefilefile

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"

Per saperne di più, leggi la documentazione sulle variabili automatiche come indicato da cfi .

Il codice sorgente

- 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);
}

La build

Correggi il copia-incolla di Makefile(sostituisci gli spazi iniziali con una tabulazione).

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

Il makecomando è lo stesso su entrambe le piattaforme. L'output dato è su SO simili a Unix:

> 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'

La corsa

L'applicazione richiede di sapere dove si trova la libreria condivisa.

Su Windows, una soluzione semplice è quella di copiare la libreria in cui si trova l'applicazione:

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

Su sistemi operativi simili a Unix, è possibile utilizzare la LD_LIBRARY_PATHvariabile di ambiente:

> export LD_LIBRARY_PATH=lib

Esegui il comando su Windows:

> app/app.exe
hello

Esegui il comando su sistemi operativi simili a Unix:

> app/app
hello

Apprezzo il tuo impegno, ma la domanda principale era rilevare il sistema operativo. Il tuo esempio rileva solo Linux e altrimenti presuppone Windows.
Shahbaz,

Ciao @Shahbaz. Hai ragione, la mia risposta non dà un approccio diverso rispetto alle altre risposte. Inoltre, il mio script presuppone che la piattaforma sia Windows quando unamenon è Linux. Faccio solo un esempio di cui potresti non avere bisogno, ma questo può aiutare qualcuno a cercare (sul web) un modo per implementare un Makefileper entrambe le piattaforme ;-) Cosa devo cambiare nella mia risposta? Saluti
olibre,

prova a trovare modi per identificare correttamente anche altri sistemi operativi! L'obiettivo è trovare un metodo non troppo complicato, ma soprattutto a prova di proiettile. Cioè, non farebbe alcun errore, qualunque cosa accada.
Shahbaz,

1
@olibre Grazie per l'esempio dettagliato, molto apprezzato e mi aiuta a iniziare rapidamente. Nel lib/Makefileesempio, targetviene utilizzato per la .sovs .dll. Un esempio parallelo per il app/makefilesarebbe utile per il confronto empty stringvs .exeper il nome file dell'app. Ad esempio, di solito non vedo app.exesu sistemi operativi simili a Unix. ;-)

1
LSF? LFS? Errore di battitura?
Franklin Yu,

19

Recentemente stavo sperimentando per rispondere a questa domanda che mi ponevo. Ecco le mie conclusioni:

Dato che in Windows, non puoi essere sicuro che il unamecomando sia disponibile, puoi usarlo gcc -dumpmachine. Questo visualizzerà la destinazione del compilatore.

Potrebbe esserci anche un problema durante l'utilizzo unamese si desidera eseguire una compilazione incrociata.

Ecco un elenco di esempio di possibili output di gcc -dumpmachine:

  • mingw32
  • i686-pc-cygwin
  • x86_64-redhat-linux

Puoi controllare il risultato nel makefile in questo modo:

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

Ha funzionato bene per me, ma non sono sicuro che sia un modo affidabile per ottenere il tipo di sistema. Almeno è affidabile su MinGW e questo è tutto ciò di cui ho bisogno in quanto non richiede di avere il unamecomando o il pacchetto MSYS in Windows.

Per riassumere, unameti dà il sistema su cui stai compilando e gcc -dumpmachineti dà il sistema per cui stai compilando.


Questo è un buon punto. Tuttavia, non unamevieni MinGWcomunque? Tuttavia, la nota aggiuntiva relativa alla compilazione incrociata è eccezionale.
Shahbaz,

2
L'installazione di @Shahbaz MinGW può installare MSYS (che contiene uname) ma è opzionale. È ancora possibile trovare sistemi con solo strumenti MinGW gcc
phsym,

1
Non funziona da nessuna parte Clang è il compilatore predefinito, come OS X e FreeBSD.
MarcusJ,

@SebastianGodelet @MarcusJ Una soluzione semplice è $(shell $(CC) -dumpmachine). A partire da OS X Sierra, il comando -dumpmachine funziona su Clang.
Vortico,

Su OS X 10.12.5 è x86_64-apple-darwin16.6.0e che le opere Sia che lo chiamano gcc, cco clang, ma noncl
MarcusJ

17

Il makefile di git contiene numerosi esempi di come gestire senza autoconf / automake, ma funziona ancora su una moltitudine di piattaforme unixy.


13
Sapere che Git non usa in qualche modo gli Autofool mi fa sentire giustificato nella mia avversione per loro ...
Dan Molding,

11
"Autofools"? Era un errore intenzionale? :)
JesperE,

6
Era. Ma ripensandoci, penso che mi piaccia ancora di più "Autostools". : D
Dan Molding,

A proposito, chi intendevi per "loro"? Le persone Git o Autotools? : D
JesperE,

8
L'inglese è una lingua così imprecisa. Che ne dici di questo: if (!usesAutotools(git)) aversionTo(autotools) = justified;chiarirò anche che sono solo gli strumenti a cui sono contrario. Sono sicuro che le persone degli Autotools sono brave persone.
Dan Molding,

11

Aggiornamento: ora considero questa risposta obsoleta. Ho pubblicato una nuova soluzione perfetta più in basso.

Se il tuo makefile potrebbe essere in esecuzione su Windows non Cygwin, unamepotrebbe non essere disponibile. È imbarazzante, ma questa è una potenziale soluzione. Devi prima verificare che Cygwin lo escluda, perché ha anche WINDOWS nella sua PATHvariabile di ambiente.

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

Questo è buono per ora! Puoi dirmi una cosa, però? Non uso Cygwin, ma ho MinGW installato con il suo percorso bin in PATH. Se unameemetto da un normale terminale cmd mi dà MINGW. Quello che voglio dire è che ho ancora unamesenza usare Cygwin. Ho anche git bash, ma non ci ho provato su uname (al momento sono su Linux). Puoi dirmi come questi due possono essere incorporati nel tuo codice?
Shahbaz,

Se sei sicuro che uname sia disponibile, questa è la soluzione migliore. Ma nel mio ambiente, tutti usano Windows e poche persone hanno installato cygwin o mingw , quindi non ho alcuna garanzia che tutto ciò che è standard come uname funzionerà. Attualmente sto riscontrando delle difficoltà con il codice sopra che esegue make.exe in una shell cmd. Windows è una piattaforma molto frustrante con cui lavorare.
Ken Jackson,

Quello che voglio dire è che, prima di testare l'esistenza di WINDOWS in PATH, ti assicuri di non avere a che fare con Cygwin, come puoi assicurarti di non avere a che fare con MinGW? Ad esempio, in Makefile è possibile verificare se è possibile eseguire un comando e se unamenon fosse possibile capire che ci troviamo in Windows?
Shahbaz,

Sto lottando per trovare una soluzione pulita a questo Mingw / cygwin / shell-o-cmd / Linux. Alla fine della giornata, qualcosa come premake o cmake sembra l'idea migliore.
Isaac Nequittepas,

Questa non è più la soluzione migliore. La nuova soluzione che ho pubblicato distingue Windows nativo cercando ";" nella variabile PATH, senza una chiamata shell.
Ken Jackson,

7

Questo è il lavoro che GNU automake / autoconf è progettato per risolvere. Potresti voler indagare su di loro.

In alternativa è possibile impostare variabili di ambiente su piattaforme diverse e rendere Makefile condizionato a esse.


11
Consiglio vivamente di non utilizzare automake / autoconf. Sono noiosi da usare, aggiungono un sacco di sovraccarico ai tuoi file, ai tuoi tempi di costruzione. Aggiungono semplicemente complessità per un effetto generalmente molto scarso (ancora nessuna portabilità tra i sistemi).
Johannes Overmann,

1
Ho appena trascorso un paio di giorni ad imparare makea fare quello che voglio. Ora voglio entrare anche in automake / autoconf? - NO. Ciò che può essere fatto nel makefile, certamente dovrebbe essere fatto nel makefile, anche solo per non avere più punti di interruzione ogni volta che voglio modificare compilazione e collegamento.
Ingegnere

Quante piattaforme supportano i tuoi makefile? automake e autoconf diventano davvero unici quando si desidera la portabilità su molte piattaforme.
Douglas Leeder,

2
Non avrò bisogno di dipendenze inutili e cambierò il mio intero sistema di build solo per scoprire per quale sistema operativo è stato compilato.
MarcusJ,

7

Alla fine ho trovato la soluzione perfetta che risolve questo problema per me.

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

La variabile UNAME è impostata su Linux, Cygwin, MSYS, Windows, FreeBSD, NetBSD (o presumibilmente Solaris, Darwin, OpenBSD, AIX, HP-UX) o Sconosciuto. Può quindi essere confrontato per tutto il resto del Makefile per separare eventuali variabili e comandi sensibili al sistema operativo.

La chiave è che Windows usa i punti e virgola per separare i percorsi nella variabile PATH mentre tutti gli altri usano i due punti. (È possibile creare una directory Linux con un ';' nel nome e aggiungerla a PATH, il che potrebbe interrompere questo, ma chi farebbe una cosa del genere?) Questo sembra essere il metodo meno rischioso per rilevare Windows nativo perché non ha bisogno di una chiamata shell. Il PERCORSO Cygwin e MSYS usano due punti in modo da chiamarli uname .

Si noti che la variabile di ambiente del sistema operativo può essere utilizzata per rilevare Windows, ma non per distinguere tra Cygwin e Windows nativo. Il test per l'eco delle virgolette funziona, ma richiede una chiamata shell.

Sfortunatamente, Cygwin aggiunge alcune informazioni sulla versione all'output di uname , quindi ho aggiunto le chiamate "patsubst" per cambiarle in "Cygwin". Inoltre, uname per MSYS ha in realtà tre possibili output che iniziano con MSYS o MINGW, ma utilizzo anche patsubst per trasformare tutto in "MSYS".

Se è importante distinguere tra i sistemi Windows nativi con e senza uname.exe sul percorso, questa riga può essere utilizzata al posto della semplice assegnazione:

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

Ovviamente in tutti i casi è richiesto GNU make o un altro make che supporti le funzioni utilizzate.


6

Ho riscontrato questo problema oggi e ne avevo bisogno su Solaris, quindi ecco un modo POSIX standard per fare questo (qualcosa di molto vicino).

#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
Ottenere errore su OSX: "Makefile: 22: *** mancante separatore. Stop.". Su questa riga: "- @ make $ (UNAME_S)".
Czarek Tomczak,

OSX probabilmente non è conforme, quindi prova questi in ordine. (1) Assicurati di utilizzare un TAB come primo carattere sulla linea (2) Rimuovi il "- @" davanti alla marca (2a) Se 2 ha funzionato, prova un personaggio e poi l'altro (3) Assicurati che UNAME_S è definito, prova echo $ (UNAME_S) invece di - @ make $ (UNAME_S)
Huckle

6

Ecco una semplice soluzione che controlla se sei in un ambiente Windows o simile a posix (Linux / Unix / Cygwin / Mac):

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

Sfrutta il fatto che l'eco esiste sia in ambiente simile a posix che in ambiente Windows e che in Windows la shell non filtra le virgolette.


1
Abbastanza pericoloso poiché $PATHpotrebbe riferirsi a un altro echo(il mio fa ...)
yyny

@YoYoYonnY Perché il tuo percorso fa riferimento a un'altra eco? Sembra una situazione molto improbabile.
Samuel,

1
non proprio, git lo fa, mingw lo fa, cygwin lo fa ... E io personalmente inserisco C: \ Windows \ System32 in fondo al mio percorso.
yyny,

1
Questa "soluzione" "funziona" per tutti gli ambienti, ma il mio punto è che questo non rileva definitivamente le finestre in modo sicuro. Se voglio impostare una -mwindowsbandiera o scegliere tra un .dllo .so, questo fallirebbe.
yyny,

1
@YoYoYonnY Grazie per il chiarimento. Nella mia situazione mi importava solo se mi trovavo in un ambiente Cygwin o Windows o Linux piuttosto che in quale sistema operativo mi trovavo, quindi questo mi è stato utile. Sembra che i tuoi bisogni siano diversi da quelli dei miei.
Samuel,

3

Si noti che i Makefile sono estremamente sensibili alla spaziatura. Ecco un esempio di Makefile che esegue un comando aggiuntivo su OS X e che funziona su OS X e Linux. Nel complesso, tuttavia, autoconf / automake è la strada da percorrere per qualsiasi cosa non banale.

UNAME: = $ (shell uname -s)
CPP = g ++
CPPFLAGS = -pthread -ansi -Wall -Werror -pedantic -O0 -g3 -I / nexopia / include
LDFLAGS = -pthread -L / nexopia / lib -lboost_system

HEADERS = data_structures.h http_client.h load.h lock.h search.h server.h thread.h utility.h
OGGETTI = http_client.o load.o lock.o search.o server.o thread.o utility.o vor.o

tutto: vor

pulito:
    rm -f $ (OGGETTI) vor

vor: $ (OGGETTI)
    $ (CPP) $ (LDFLAGS) -o vor $ (OGGETTI)
ifeq ($ (UNAME), Darwin)
    # Imposta la posizione della libreria Boost
    install_name_tool -change libboost_system.dylib /nexopia/lib/libboost_system.dylib vor
finisci se

% .o:% .cpp $ (HEADERS) Makefile
    $ (CPP) $ (CPPFLAGS) -c $

2

Un altro modo per farlo è usare uno script "configura". Se ne stai già usando uno con il tuo makefile, puoi usare una combinazione di uname e sed per far funzionare le cose. Innanzitutto, nella tua sceneggiatura, esegui:

UNAME=uname

Quindi, per metterlo nel tuo Makefile, inizia con Makefile.in che dovrebbe avere qualcosa di simile

UNAME=@@UNAME@@

dentro.

Utilizzare il seguente comando sed nello script di configurazione dopo il UNAME=unamebit.

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

Ora il tuo makefile avrebbe dovuto essere UNAMEdefinito come desiderato. Se le istruzioni / elif / else sono tutto ciò che resta!


Il primo non dovrebbe essere questo? UNAME = $ (uname)
Ken Jackson

0

Ho avuto un caso in cui dovevo rilevare la differenza tra due versioni di Fedora, per modificare le opzioni della riga di comando per inkscape:
- in Fedora 31, l'inkscape predefinito è 1.0beta che utilizza --export-file
- in Fedora <31, l'inkscape predefinito è 0.92 che utilizza--export-pdf

Il mio Makefile contiene quanto segue

# 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)=$@

Questo funziona perché /etc/os-releasecontiene una linea

VERSION_ID=<value>

così il comando shell nel Makefile restituisce la stringa VERSION_ID=<value>, quindi il comando eval agisce su questo per impostare la variabile Makefile VERSION_ID. Questo può ovviamente essere modificato per altri sistemi operativi a seconda della modalità di memorizzazione dei metadati. Nota che in Fedora non esiste una variabile d'ambiente predefinita che fornisce la versione del sistema operativo, altrimenti l'avrei usata!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.