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
PROCESSOR_ARCHITECTUREenvvar semble être virtualisé selon que le processus est 32 bits ou 64 bits. Donc, si vous avezmake32 bits et que vous essayez de créer une application 64 bits, cela échouera. L'utiliser en combinaison avec aPROCESSOR_ARCHITEW6432fonctionné pour moi (voir ceci et cela )