Détectez le système d'exploitation à l'aide de deux astuces simples:
- D'abord la variable d'environnement
OS
- Ensuite, la
uname
commande
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 uname
indisponible:
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 uname
est la même que uname -s
parce que l'option -s
( --kernel-name
) est la valeur par défaut. Voyez pourquoi uname -s
c'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/else
blocs pour vérifier toutes les variations de MinGW, Cygwin, etc.
La variable d'environnement OS
est toujours définie "Windows_NT"
sur différentes versions de Windows (voir %OS%
variable d'environnement sur Wikipedia ).
Une alternative à OS
est 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 make
et gcc
pour construire une bibliothèque partagée: *.so
ou en *.dll
fonction de la plateforme. L'exemple est aussi simple que possible pour être plus compréhensible.
Pour installer make
et gcc
sur 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 Makefile
fichiers
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 make
commande 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_PATH
variable 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_ARCHITECTURE
envvar semble être virtualisé selon que le processus est 32 bits ou 64 bits. Donc, si vous avezmake
32 bits et que vous essayez de créer une application 64 bits, cela échouera. L'utiliser en combinaison avec aPROCESSOR_ARCHITEW6432
fonctionné pour moi (voir ceci et cela )