Jak zidentyfikować platformę / kompilator na podstawie makr preprocesora?

115

Piszę kod wieloplatformowy, który powinien być kompilowany pod linuxem, Windows, Mac OS. W systemie Windows muszę obsługiwać Visual Studio i mingw.

Jest kilka fragmentów kodu specyficznego dla platformy, które powinienem umieścić w #ifdef .. #endifśrodowisku. Na przykład tutaj umieściłem kod specyficzny dla win32:

#ifdef WIN32
#include <windows.h>
#endif

Ale jak rozpoznać Linuksa i Mac OS? Jakie są nazwy definicji (lub itp.), Których powinienem użyć?

Arenim
źródło
Duplikat ma znacznie lepiej akceptowaną odpowiedź.
rubenvb
1
Sugerowany duplikat NIE jest tym samym pytaniem. To pytanie dotyczy tylko identyfikacji systemu operacyjnego, podczas gdy to pytanie dotyczy również identyfikacji kompilatora, a to zupełnie inna sprawa.
JBentley
@JBentley jednak przyjęta odpowiedź nie wspomina nawet o kompilatorach, a jedynie mówi o systemach operacyjnych (i jednej „platformie”). Nie wspominając o tym, że jest to okropna odpowiedź w stosunku do tego, co ma do zaoferowania oszust.
rubenvb
1
@rubenvb Następnie połącz inne pytanie jako komentarz. Tylko dlatego, że ma lepszą odpowiedź, nie czyni jej duplikatem. Pytanie brzmi, co decyduje o tym, czy jest to duplikat, a nie odpowiedzi. Zamknięcie tego tylko gwarantuje, że nigdy nie uzyskamy dobrej odpowiedzi na część pytania dotyczącą kompilatora, na którą tak zwany „duplikat” nie może nigdy odpowiedzieć.
JBentley,

Odpowiedzi:

133

W przypadku systemu Mac OS :

#ifdef __APPLE__

Dla MinGW w systemie Windows:

#ifdef __MINGW32__

W systemie Linux :

#ifdef __linux__

Dla innych kompilatorów Windows sprawdzić ten wątek i to przez kilka innych kompilatorów i architektur.

karlphillip
źródło
2
Czy __APPLE__rozróżnia OSX i iOS?
gman
14
__APPLE__jest ustawiony na OS X i iOS. Możesz w #include <TargetConditionals.h>środku #ifdef __APPLE__, co następnie daje TARGET_OS_IPHONE #define.
Ted Mielczarek
2
__MINGW64__jest również dostępny, gdy używa się mingw64
scones
2
Ponieważ __MINGW64__jest _MSC_VERprzywoływany, warto wspomnieć o systemie Windows / MSVC (którego można również użyć do sprawdzenia wersji MSVC).
ideasman42
Przepraszam, ale ta odpowiedź jest dość niepoprawna na wszystkich kontach i nawet nie odpowiada na pytanie.
rubenvb
59

Zobacz: http://predef.sourceforge.net/index.php

Ten projekt zawiera dość obszerną listę wstępnie zdefiniowanych #definesdla wielu systemów operacyjnych, kompilatorów, standardów językowych i platform oraz bibliotek standardowych.

John Bartholomew
źródło
5
Od wersji 1.55 Predef jest teraz uwzględniony w bibliotekach Boost C ++ .
rvalue
Wiem, że zasady były inne, kiedy to opublikowałeś, ale będę musiał poprosić Cię o edycję tego posta, aby zawierał bardziej odpowiednie szczegóły. Teraz dni tylko odpowiedzi z linkami są zdecydowanie odradzane i chciałbym zaoferować Ci możliwość zapisania tego posta przed jego usunięciem.
Mick MacCallum
1
Ponieważ jest to jedyna odpowiedź, która faktycznie odpowiada na pytanie zawarte w tytule, a pytanie jest bardzo ogólne i istotne, zdecydowanie odradzam jej usuwanie. Nie nazwałbym tego również odpowiedzią „tylko łącze”.
hobb
2
@ 0x7fffffff: Jaką potencjalną korzyść dla każdego przyniosłoby skopiowanie treści innych odpowiedzi do tej? Jeśli uważasz, że naprawdę ważna jest jedna ostateczna odpowiedź, być może powinieneś sam stworzyć taką odpowiedź (nie powinno to być trudne: po prostu sklej istniejące odpowiedzi w rozsądnej kolejności). Osobiście mam lepsze rzeczy do roboty, ale jako moderator najwyraźniej SO jest dla ciebie ważniejsze niż dla mnie.
John Bartholomew
47

Oto czego używam:

#ifdef _WIN32 // note the underscore: without it, it's not msdn official!
    // Windows (x64 and x86)
#elif __unix__ // all unices, not all compilers
    // Unix
#elif __linux__
    // linux
#elif __APPLE__
    // Mac OS, not sure if this is covered by __posix__ and/or __unix__ though...
#endif

EDYCJA: Chociaż powyższe może działać w przypadku podstaw, pamiętaj, aby zweryfikować, jakiego makra chcesz sprawdzić, patrząc na strony odniesienia Boost.Predef . Lub po prostu użyj Boost.Predef bezpośrednio.

rubenvb
źródło
4
zamiast tego użyj __linux __, linux nie jest zdefiniowany podczas kompilacji z GCC z wyłączonymi rozszerzeniami GNU (tj. -std = c ++ 0x)
Erbureth mówi Reinstate Monica
1
@Erbureth Naprawiono, ale naprawdę należy używać predef.sourceforge.net/index.php, jak w najwyżej ocenianej odpowiedzi.
rubenvb
@rubenvb: rzeczywiście. I chyba za mało głosów, myślę, że :) ... Tyle razy odwiedzałem ich stronę.
0xC0000022L,
Dla spójności (być może trochę pedantycznej): pierwsze #ifpytanie, jeśli jest zdefiniowane, pozostałe sprawdzają wartość. #elif defined(__unix__) Myślę, że jeśli byłoby to bardziej konsekwentne , itp.
leonbloy
20

Jeśli piszesz w C ++, nie mogę wystarczająco mocno polecać korzystania z bibliotek Boost .

Najnowsza wersja (1.55) zawiera nową bibliotekę Predef, która obejmuje dokładnie to, czego szukasz , a także dziesiątki innych makr do rozpoznawania platformy i architektury.

#include <boost/predef.h>

// ...

#if BOOST_OS_WINDOWS

#elif BOOST_OS_LINUX

#elif BOOST_OS_MACOS

#endif
wartość r
źródło
Biorąc pod uwagę, że jest to przyspieszenie, to rozwiązanie będzie działać na różnych platformach / systemach operacyjnych ORAZ różnych kompilatorach.
Trevor Boyd Smith
3
„Nie mogę wystarczająco mocno polecać korzystania z bibliotek Boost…” - trzykrotnie oceniałem Boost. To nie może przejść oceny ... Większość zgłoszonych błędów miała szczęście, jeśli zostały potwierdzone. Brak uznania wskazuje na głębsze problemy w procesie inżynieryjnym. Uważam, że makra preprocesora i wbudowane biblioteki standardowe C ++ są bezpieczniejszym wyborem.
jww