OS détectant le makefile

250

Je travaille régulièrement sur plusieurs ordinateurs différents et plusieurs systèmes d'exploitation différents, qui sont Mac OS X, Linux ou Solaris. Pour le projet sur lequel je travaille, je tire mon code d'un dépôt git distant.

J'aime pouvoir travailler sur mes projets quel que soit le terminal où je suis. Jusqu'à présent, j'ai trouvé des moyens de contourner les modifications du système d'exploitation en changeant le makefile chaque fois que je change d'ordinateurs. Cependant, cela est fastidieux et provoque un tas de maux de tête.

Comment puis-je modifier mon makefile afin qu'il détecte le système d'exploitation que j'utilise et modifie la syntaxe en conséquence?

Voici le 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
samoz
la source

Réponses:

283

Il y a déjà beaucoup de bonnes réponses ici, mais je voulais partager un exemple plus complet que les deux:

  • ne suppose pas qu'il unameexiste sous Windows
  • détecte également le processeur

Les CCFLAGS définis ici ne sont pas nécessairement recommandés ou idéaux; ils sont exactement ce que le projet auquel j'ajoutais la détection automatique OS / CPU était en train d'utiliser.

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
Trevor Robinson
la source
8
Malheureusement, l' PROCESSOR_ARCHITECTUREenvvar semble être virtualisé selon que le processus est 32 bits ou 64 bits. Donc, si vous avez make32 bits et que vous essayez de créer une application 64 bits, cela échouera. L'utiliser en combinaison avec a PROCESSOR_ARCHITEW6432fonctionné pour moi (voir ceci et cela )
Thomas
4
Ce serait bien si l' makeéquipe ajoutait quelques variables magiques avec os et arch, probablement trop de problèmes.
Alex
6
@JanusTroelsen: peu importe qu'il OSsoit défini sur des systèmes non Windows. Rendre les friandises non réglées comme vides, ce qui provoquera un saut dans le unamebloc basé. Il vous suffit d'y ajouter un chèque FreeBSD.
Trevor Robinson
3
cela casse aussi sur osx. /bin/sh: -c: line 0: syntax error near unexpected token , Windows_NT '/ bin / sh: -c: ligne 0:ifeq (,Windows_NT)' make: *** [os] Error 2
k107
1
@kristi Il semble que vous ayez exécuté cela en tant que commandes shell et non dans le contexte des directives makefile.
phord
119

La commande uname ( http://developer.apple.com/documentation/Darwin/Reference/ManPages/man1/uname.1.html ) sans paramètres devrait vous indiquer le nom du système d'exploitation. Je l'utiliserais, puis ferais des conditions en fonction de la valeur de retour.

Exemple

UNAME := $(shell uname)

ifeq ($(UNAME), Linux)
# do something Linux-y
endif
ifeq ($(UNAME), Solaris)
# do something Solaris-y
endif
dbrown0708
la source
Juste pour être explicite, cette ligne va dans votre Makefile. Je viens d'essayer cette construction dans Makefiles dans Cygwin et OSX, et cela a fonctionné comme prévu. Quelque chose à essayer: tapez uname sur votre ligne de commande. Cela vous dira la valeur de ce système d'exploitation. OSX sera probablement "Darwin".
dbrown0708
Le projet GnuWin32 a à la fois uname et Gnu rend disponible en tant qu'applications Windows natives, ce qui rend cette technique portable pour MingW à une invite de commande ainsi que Cygwin sur Windows.
RBerteig
Il échoue sur ma machine Solaris lorsqu'elle se trouve dans le makefile. La commande uname est disponible sur ce système.
samoz
4
Notez que si vous mettez cela dans un Maketarget, il ne doit pas être mis en retrait.
nylund
4
La syntaxe ": =" n'est-elle pas spécifique à GNU Make?
Ankur Sethi
40

Détectez le système d'exploitation à l'aide de deux astuces simples:

  • D'abord la variable d'environnement OS
  • Ensuite, la unamecommande
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

Ou un moyen plus sûr, sinon sous Windows et unameindisponible:

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

Ken Jackson propose une alternative intéressante si vous souhaitez distinguer Cygwin / MinGW / MSYS / Windows. Voir sa réponse qui ressemble à ça:

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

Ensuite, vous pouvez sélectionner les éléments pertinents en fonction de 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

Remarques:

  • La commande unameest la même que uname -sparce que l'option -s( --kernel-name) est la valeur par défaut. Voyez pourquoi uname -sc'est mieux queuname -o .

  • L'utilisation de OS(au lieu de uname) simplifie l'algorithme d'identification. Vous pouvez toujours utiliser uniquement uname, mais vous devez gérer les if/elseblocs pour vérifier toutes les variations de MinGW, Cygwin, etc.

  • La variable d'environnement OSest toujours définie "Windows_NT"sur différentes versions de Windows (voir %OS%variable d'environnement sur Wikipedia ).

  • Une alternative à OSest la variable d'environnement MSVC(elle vérifie la présence de MS Visual Studio , voir l' exemple utilisant Visual C ++ ).


Ci-dessous, je fournis un exemple complet en utilisant makeet gccpour construire une bibliothèque partagée: *.soou en *.dllfonction de la plateforme. L'exemple est aussi simple que possible pour être plus compréhensible.

Pour installer makeet gccsur Windows, voir Cygwin ou MinGW .

Mon exemple est basé sur cinq fichiers

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

Rappel: Makefile est mis en retrait à l'aide de la tabulation . Attention lors du copier-coller sous les exemples de fichiers.

Les deux Makefilefichiers

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"

Pour en savoir plus, lisez la documentation sur les variables automatiques comme indiqué par cfi .

Le code source

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

Corrigez le copier-coller de Makefile(remplacez les espaces de tête par une tabulation).

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

La makecommande est la même sur les deux plateformes. La sortie donnée est sur des OS de type 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 course

L'application nécessite de savoir où se trouve la bibliothèque partagée.

Sous Windows, une solution simple consiste à copier la bibliothèque où se trouve l'application:

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

Sur les OS de type Unix, vous pouvez utiliser la LD_LIBRARY_PATHvariable d'environnement:

> export LD_LIBRARY_PATH=lib

Exécutez la commande sous Windows:

> app/app.exe
hello

Exécutez la commande sur les systèmes d'exploitation de type Unix:

> app/app
hello
olibre
la source
J'apprécie vos efforts, mais la principale question était de détecter le système d'exploitation. Votre exemple ne détecte que Linux et suppose carrément Windows.
Shahbaz
Salut @Shahbaz. Vous avez raison, ma réponse ne donne pas une approche différente des autres réponses. De plus, mon script suppose que la plate-forme est Windows lorsqu'elle unamen'est pas Linux. Je donne juste un exemple dont vous n'avez peut-être pas besoin, mais cela peut aider quelqu'un à chercher (sur le Web) un moyen d'implémenter un Makefilepour les deux plates-formes ;-) Que dois-je changer dans ma réponse? Vive
olibre
essayez également de trouver des moyens d'identifier correctement les autres systèmes d'exploitation! Le but est de trouver une méthode qui n'est pas trop compliquée, mais qui est surtout à l'épreuve des balles. Autrement dit, il ne ferait aucune erreur quoi qu'il arrive.
Shahbaz
1
@olibre Merci pour l'exemple détaillé, très apprécié et m'aide à démarrer rapidement. Dans l' lib/Makefileexemple, targetest utilisé pour .sovs .dll. Un exemple parallèle pour le app/makefileserait utile pour la comparaison empty stringvs .exepour le nom de fichier de l'application. Par exemple, je ne vois généralement pas app.exesur les systèmes d'exploitation de type Unix. ;-)
1
LSF? LFS? Faute de frappe?
Franklin Yu
19

J'expérimentais récemment pour répondre à cette question que je me posais. Voici mes conclusions:

Étant donné que dans Windows, vous ne pouvez pas être sûr que la unamecommande est disponible, vous pouvez utiliser gcc -dumpmachine. Cela affichera la cible du compilateur.

Il peut également y avoir un problème lors de l'utilisation unamesi vous souhaitez effectuer une compilation croisée.

Voici un exemple de liste de sortie possible de gcc -dumpmachine:

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

Vous pouvez vérifier le résultat dans le makefile comme ceci:

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

Cela a bien fonctionné pour moi, mais je ne suis pas sûr que ce soit un moyen fiable d'obtenir le type de système. Au moins, il est fiable à propos de MinGW et c'est tout ce dont j'ai besoin car il ne nécessite pas d'avoir la unamecommande ou le package MSYS dans Windows.

Pour résumer, unamevous donne le système sur lequel vous compilez et gcc -dumpmachinevous donne le système pour lequel vous compilez.

phsym
la source
C'est un bon point. Cependant, ne unamevient pas de MinGWtoute façon? Néanmoins, la note supplémentaire concernant la compilation croisée est excellente.
Shahbaz
2
La configuration de @Shahbaz MinGW peut installer MSYS (qui contient uname) mais elle est optionnelle. Il est toujours possible de trouver des systèmes avec uniquement des outils gcc MinGW
phsym
1
Cela ne fonctionne pas partout où Clang est le compilateur par défaut, comme OS X et FreeBSD.
MarcusJ
@SebastianGodelet @MarcusJ Une solution simple est $(shell $(CC) -dumpmachine). Depuis OS X Sierra, la commande -dumpmachine fonctionne sur Clang.
Vortico
Sur OS X 10.12.5 il est x86_64-apple-darwin16.6.0et que les travaux castrés vous l' appelez gcc, ccou clang, mais pascl
MarcusJ
17

Le makefile git contient de nombreux exemples de gestion sans autoconf / automake, tout en fonctionnant sur une multitude de plates-formes unixy.

JesperE
la source
13
Savoir que Git n'utilise pas les Autofools me fait me sentir justifié dans mon aversion pour eux ...
Dan Moulding
11
"Autofools"? Était-ce une faute de frappe délibérée? :)
JesperE
6
C'était. Mais après coup, je pense que j'aime encore mieux "Autostools". : D
Dan Moulding
Btw, qui vouliez-vous dire par "eux"? Les gens de Git ou Autotools? : D
JesperE
8
L'anglais est une langue tellement imprécise. Que diriez-vous de cela: if (!usesAutotools(git)) aversionTo(autotools) = justified;je préciserai également que ce ne sont que les outils auxquels je suis opposé. Je suis sûr que les gens Autotools sont des gens sympas.
Dan Moulding
11

Mise à jour: je considère maintenant cette réponse comme obsolète. J'ai posté une nouvelle solution parfaite plus bas.

Si votre makefile s'exécute sur des fenêtres non Cygwin, unamepeut ne pas être disponible. C'est gênant, mais c'est une solution potentielle. Vous devez d'abord vérifier Cygwin pour l'exclure, car il a aussi WINDOWS dans sa PATHvariable d'environnement.

ifneq (,$(findstring /cygdrive/,$(PATH)))
    UNAME := Cygwin
else
ifneq (,$(findstring WINDOWS,$(PATH)))
    UNAME := Windows
else
    UNAME := $(shell uname -s)
endif
endif
Ken Jackson
la source
C'est bon maintenant! Pouvez-vous me dire une chose, cependant? Je n'utilise pas Cygwin, mais j'ai installé MinGW avec son chemin bin dans PATH. Si unamej'émets à partir d'un terminal cmd normal, cela me donne MINGW. Ce que je veux dire, c'est que j'ai toujours unamesans utiliser Cygwin. J'ai aussi git bash, mais je n'ai pas essayé uname (en ce moment je suis sous Linux). Pouvez-vous me dire comment ces deux peuvent être incorporés dans votre code?
Shahbaz
Si vous êtes sûr que l'uname est disponible, c'est la meilleure solution. Mais dans mon environnement, tout le monde utilise Windows et peu de gens ont installé cygwin ou mingw , donc je n'ai aucune garantie que quoi que ce soit, aussi standard qu'uname, fonctionnera. Je rencontre actuellement des difficultés avec le code ci-dessus exécutant make.exe dans un shell cmd. Windows est une plateforme très frustrante avec laquelle travailler.
Ken Jackson
Ce que je veux dire, c'est qu'avant de tester l'existence de WINDOWS dans PATH, vous vous assurez que vous ne traitez pas avec cygwin, comment pouvez-vous vous assurer que vous ne traitez pas avec MinGW? Par exemple, est-il possible dans Makefile de tester si une commande peut être exécutée, et si unameelle ne pouvait pas être exécutée, nous comprendrions que nous sommes dans Windows?
Shahbaz
J'ai du mal à trouver une solution propre à ce Mingw / cygwin / shell-or-cmd / Linux également. À la fin de la journée, quelque chose comme prémake ou cmake semble être la meilleure idée.
Isaac Nequittepas
Ce n'est plus la meilleure solution. La nouvelle solution que j'ai publiée distingue Windows natif en recherchant ';' dans la variable PATH, sans appel shell.
Ken Jackson
7

C'est le travail que l' automake / autoconf de GNU est conçu pour résoudre. Vous voudrez peut-être les enquêter.

Alternativement, vous pouvez définir des variables d'environnement sur vos différentes plates-formes et rendre votre Makefile conditionnel par rapport à celles-ci.

Douglas Leeder
la source
11
Je déconseille fortement d'utiliser automake / autoconf. Ils sont fastidieux à utiliser, ajoutent beaucoup de frais généraux à vos fichiers, à votre temps de génération. Ils ajoutent simplement de la complexité pour généralement très peu d'effet (toujours pas de portabilité entre les systèmes).
Johannes Overmann
1
Je viens de passer quelques jours à apprendre makeà faire ce que je veux. Est-ce que je veux maintenant entrer aussi dans automake / autoconf? - NON. Ce qui peut être fait dans le makefile, devrait certainement être fait dans le makefile, ne serait-ce que pour ne pas avoir plusieurs points d'arrêt à chaque fois que je souhaite modifier la compilation et le lien.
Ingénieur
Combien de plateformes vos makefiles prennent-ils en charge? automake et autoconf prennent tout leur sens lorsque vous souhaitez la portabilité vers de nombreuses plates-formes.
Douglas Leeder
2
Je ne vais pas avoir besoin de dépendances inutiles, et changer tout mon système de build juste pour savoir pour quel OS il est compilé.
MarcusJ
7

J'ai finalement trouvé la solution parfaite qui résout ce problème pour moi.

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 variable UNAME est définie sur Linux, Cygwin, MSYS, Windows, FreeBSD, NetBSD (ou probablement Solaris, Darwin, OpenBSD, AIX, HP-UX) ou Unknown. Il peut ensuite être comparé dans le reste du Makefile pour séparer toutes les variables et commandes sensibles au système d'exploitation.

La clé est que Windows utilise des points-virgules pour séparer les chemins dans la variable PATH tandis que tout le monde utilise des deux-points. (Il est possible de créer un répertoire Linux avec un ';' dans le nom et de l'ajouter à PATH, ce qui casserait cela, mais qui ferait une telle chose?) Cela semble être la méthode la moins risquée pour détecter Windows natif car il n'a pas besoin d'un appel shell. Le Cygwin et MSYS PATH utilisent des deux-points, donc uname est appelé pour eux.

Notez que la variable d'environnement OS peut être utilisée pour détecter Windows, mais pas pour faire la distinction entre Cygwin et Windows natif. Le test de l'écho des citations fonctionne, mais il nécessite un appel shell.

Malheureusement, Cygwin ajoute des informations de version à la sortie de uname , j'ai donc ajouté les appels «patsubst» pour le changer en «Cygwin». De plus, uname for MSYS a en fait trois sorties possibles commençant par MSYS ou MINGW, mais j'utilise aussi patsubst pour tout transformer en juste 'MSYS'.

S'il est important de distinguer les systèmes Windows natifs avec et sans uname.exe sur le chemin, cette ligne peut être utilisée à la place de l'affectation simple:

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

Bien sûr, dans tous les cas, GNU make est requis, ou une autre marque qui prend en charge les fonctions utilisées.

Ken Jackson
la source
6

J'ai rencontré ce problème aujourd'hui et j'en avais besoin sur Solaris alors voici une façon standard POSIX de faire (quelque chose de très proche) cela.

#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
Huckle
la source
1
Erreur sur OSX: "Makefile: 22: *** séparateur manquant. Arrêtez.". Sur cette ligne: "- @ make $ (UNAME_S)".
Czarek Tomczak
OSX n'est probablement pas conforme, essayez-les dans l'ordre. (1) Assurez-vous que vous utilisez un TAB comme premier caractère sur la ligne (2) Retirez le "- @" devant la marque (2a) Si 2 a fonctionné, essayez un caractère puis l'autre (3) Assurez-vous que UNAME_S est défini, essayez echo $ (UNAME_S) au lieu de - @ make $ (UNAME_S)
Huckle
6

Voici une solution simple qui vérifie si vous êtes dans un environnement Windows ou de type posix (Linux / Unix / Cygwin / Mac):

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

Il profite du fait que l'écho existe à la fois dans les environnements de type posix et Windows, et que dans Windows, le shell ne filtre pas les guillemets.

Samuel
la source
1
Assez dangereux car $PATHpourrait faire référence à un autre echo(le mien le fait ...)
yyny
@YoYoYonnY Pourquoi votre chemin fait-il référence à un autre écho? Cela semble être une situation très improbable.
Samuel
1
pas vraiment, git le fait, mingw le fait, cygwin le fait ... Et j'ai personnellement mis C: \ Windows \ System32 en bas de mon chemin.
yyny
1
Cette "solution" "fonctionne" pour tous les environnements, mais mon point est que cela ne détecte définitivement pas les fenêtres en toute sécurité. Si je veux définir un -mwindowsindicateur ou choisir entre un .dllou .so, cela échouera.
yyny
1
@YoYoYonnY Merci d'avoir clarifié. Dans ma situation, je ne me souciais que si j'étais dans un environnement Cygwin ou Windows ou Linux plutôt que dans le système d'exploitation dans lequel j'étais, donc cela m'a été utile. On dirait que vos besoins sont différents des miens.
Samuel
3

Notez que les Makefiles sont extrêmement sensibles à l'espacement. Voici un exemple de Makefile qui exécute une commande supplémentaire sur OS X et qui fonctionne sur OS X et Linux. Dans l'ensemble, cependant, autoconf / automake est la voie à suivre pour tout ce qui n'est pas trivial.

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
OBJETS = http_client.o load.o lock.o search.o server.o thread.o utility.o vor.o

tous: vor

nettoyer:
    rm -f $ (OBJECTS) vor

vor: $ (OBJETS)
    $ (CPP) $ (LDFLAGS) -o vor $ (OBJETS)
ifeq ($ (UNAME), Darwin)
    # Définir l'emplacement de la bibliothèque Boost
    install_name_tool -change libboost_system.dylib /nexopia/lib/libboost_system.dylib vor
fin si

% .o:% .cpp $ (HEADERS) Makefile
    $ (CPP) $ (CPPFLAGS) -c $
ChrisInEdmonton
la source
2

Une autre façon de procéder consiste à utiliser un script "configure". Si vous en utilisez déjà un avec votre makefile, vous pouvez utiliser une combinaison de uname et sed pour faire avancer les choses. Tout d'abord, dans votre script, faites:

UNAME=uname

Ensuite, afin de mettre cela dans votre Makefile, commencez avec Makefile.in qui devrait avoir quelque chose comme

UNAME=@@UNAME@@

en elle.

Utilisez la commande sed suivante dans votre script de configuration après le UNAME=unamebit.

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

Maintenant, votre makefile devrait avoir UNAMEdéfini comme vous le souhaitez. Si les instructions / elif / else sont tout ce qui reste!

Sean
la source
Le premier ne devrait-il pas être le même? UNAME = $ (uname)
Ken Jackson
0

J'ai eu un cas où j'ai dû détecter la différence entre deux versions de Fedora, pour modifier les options de ligne de commande pour inkscape:
- dans Fedora 31, l'inkscape par défaut est 1.0beta qui utilise --export-file
- dans Fedora <31, l'inkscape par défaut est 0.92 qui utilise--export-pdf

Mon Makefile contient les éléments suivants

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

Cela fonctionne car /etc/os-releasecontient une ligne

VERSION_ID=<value>

de sorte que la commande shell dans le Makefile renvoie la chaîne VERSION_ID=<value>, puis la commande eval agit sur cela pour définir la variable Makefile VERSION_ID. Cela peut évidemment être modifié pour d'autres systèmes d'exploitation en fonction de la façon dont les métadonnées sont stockées. Notez que dans Fedora, il n'y a pas de variable d'environnement par défaut qui donne la version du système d'exploitation, sinon j'aurais utilisé ça!

Patrick B Warren
la source