1. 程式人生 > >區分編譯器不同版本、不同作業系統的巨集

區分編譯器不同版本、不同作業系統的巨集

在編寫跨平臺的程式碼時,我們往往需要用到條件編譯的巨集,以便讓同一套程式碼相容編譯器不同版本、不同作業系統,下面就介紹下這些巨集。

區分編譯器不同版本的巨集

每個編譯器都會自帶一些預定義巨集,以下拿gcc和VC++舉例:

在編譯器眾多的預定義巨集中,肯定有一個是用於標識編譯器版本的巨集定義:

  • GCC編譯器:__GNUC__
  • Visual C++編譯器:_MSC_VER

__GNUC__是用來定義gcc編譯器的版本,我們可以使用如下程式碼來進行條件編譯:

/* Test for GCC > 3.2.0 */
#if __GNUC__ > 3 || \
    (__GNUC__ == 3 && (__GNUC_MINOR__ > 2 || \
                       (__GNUC_MINOR__ == 2 && \
                        __GNUC_PATCHLEVEL__ > 0))

Another approach is to use the predefined macros to calculate a single number, then compare that against a threshold:

#define GCC_VERSION (__GNUC__ * 10000 \
                     + __GNUC_MINOR__ * 100 \
                     + __GNUC_PATCHLEVEL__)

/* Test for GCC > 3.2.0 */
#if GCC_VERSION > 30200

_MSC_VER是微軟公司推出的C/C++編譯器在ANSI/ISO C99標準之外擴充套件的巨集定義,用來定義當前微軟公司自己的編譯器的主版本。下面是一些編譯器版本的_MSC_VER值:

MSVC++ 14.1 _MSC_VER == 1910 (Visual Studio 2017)
MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)
MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)
MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012)
MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010)
MSVC++ 9.0  _MSC_VER == 1500 (Visual Studio 2008)
MSVC++ 8.0  _MSC_VER == 1400 (Visual Studio 2005)
MSVC++ 7.1  _MSC_VER == 1310 (Visual Studio 2003)
MSVC++ 7.0  _MSC_VER == 1300
MSVC++ 6.0  _MSC_VER == 1200
MSVC++ 5.0  _MSC_VER == 1100

其中MS VC++ 14.0表示Visual C++的版本為14.0,後面括號中的Visual Studio 2015,表明該VC++包含在微軟開發工具Visual Studio 2015中。

/* Test for MSVC++ > Microsoft Visual Studio 2010 */
#if _MSC_VER > 1600

區分不同作業系統的巨集

可以參考QtCore/qsystemdetection.h檔案:

    #ifndef QSYSTEMDETECTION_H
    #define QSYSTEMDETECTION_H

    /*
       The operating system, must be one of: (Q_OS_x)
         DARWIN   - Any Darwin system
         MAC      - OS X and iOS
         OSX      - OS X
         IOS      - iOS
         MSDOS    - MS-DOS and Windows
         OS2      - OS/2
         OS2EMX   - XFree86 on OS/2 (not PM)
         WIN32    - Win32 (Windows 2000/XP/Vista/7 and Windows Server 2003/2008)
         WINCE    - WinCE (Windows CE 5.0)
         WINRT    - WinRT (Windows 8 Runtime)
         CYGWIN   - Cygwin
         SOLARIS  - Sun Solaris
         HPUX     - HP-UX
         ULTRIX   - DEC Ultrix
         LINUX    - Linux [has variants]
         FREEBSD  - FreeBSD [has variants]
         NETBSD   - NetBSD
         OPENBSD  - OpenBSD
         BSDI     - BSD/OS
         IRIX     - SGI Irix
         OSF      - HP Tru64 UNIX
         SCO      - SCO OpenServer 5
         UNIXWARE - UnixWare 7, Open UNIX 8
         AIX      - AIX
         HURD     - GNU Hurd
         DGUX     - DG/UX
         RELIANT  - Reliant UNIX
         DYNIX    - DYNIX/ptx
         QNX      - QNX [has variants]
         QNX6     - QNX RTP 6.1
         LYNX     - LynxOS
         BSD4     - Any BSD 4.4 system
         UNIX     - Any UNIX BSD/SYSV system
         ANDROID  - Android platform
         HAIKU    - Haiku
       The following operating systems have variants:
         LINUX    - both Q_OS_LINUX and Q_OS_ANDROID are defined when building for Android
                  - only Q_OS_LINUX is defined if building for other Linux systems
         QNX      - both Q_OS_QNX and Q_OS_BLACKBERRY are defined when building for Blackberry 10
                  - only Q_OS_QNX is defined if building for other QNX targets
         FREEBSD  - Q_OS_FREEBSD is defined only when building for FreeBSD with a BSD userland
                  - Q_OS_FREEBSD_KERNEL is always defined on FreeBSD, even if the userland is from GNU
    */
#if defined(__APPLE__) && (defined(__GNUC__) || defined(__xlC__) || defined(__xlc__)) # define Q_OS_DARWIN # define Q_OS_BSD4 # ifdef __LP64__ # define Q_OS_DARWIN64 # else # define Q_OS_DARWIN32 # endif #elif defined(ANDROID) # define Q_OS_ANDROID # define Q_OS_LINUX #elif defined(__CYGWIN__) # define Q_OS_CYGWIN #elif !defined(SAG_COM) && (!defined(WINAPI_FAMILY) || WINAPI_FAMILY==WINAPI_FAMILY_DESKTOP_APP) && (defined(WIN64) || defined(_WIN64) || defined(__WIN64__)) # define Q_OS_WIN32 # define Q_OS_WIN64 #elif !defined(SAG_COM) && (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)) # if defined(WINCE) || defined(_WIN32_WCE) # define Q_OS_WINCE # elif defined(WINAPI_FAMILY) # if defined(WINAPI_FAMILY_PHONE_APP) && WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP # define Q_OS_WINPHONE # define Q_OS_WINRT # elif WINAPI_FAMILY==WINAPI_FAMILY_APP # define Q_OS_WINRT # else # define Q_OS_WIN32 # endif # else # define Q_OS_WIN32 # endif #elif defined(__sun) || defined(sun) # define Q_OS_SOLARIS #elif defined(hpux) || defined(__hpux) # define Q_OS_HPUX #elif defined(__ultrix) || defined(ultrix) # define Q_OS_ULTRIX #elif defined(sinix) # define Q_OS_RELIANT #elif defined(__native_client__) # define Q_OS_NACL #elif defined(__linux__) || defined(__linux) # define Q_OS_LINUX #elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) # ifndef __FreeBSD_kernel__ # define Q_OS_FREEBSD # endif # define Q_OS_FREEBSD_KERNEL # define Q_OS_BSD4 #elif defined(__NetBSD__) # define Q_OS_NETBSD # define Q_OS_BSD4 #elif defined(__OpenBSD__) # define Q_OS_OPENBSD # define Q_OS_BSD4 #elif defined(__bsdi__) # define Q_OS_BSDI # define Q_OS_BSD4 #elif defined(__sgi) # define Q_OS_IRIX #elif defined(__osf__) # define Q_OS_OSF #elif defined(_AIX) # define Q_OS_AIX #elif defined(__Lynx__) # define Q_OS_LYNX #elif defined(__GNU__) # define Q_OS_HURD #elif defined(__DGUX__) # define Q_OS_DGUX #elif defined(__QNXNTO__) # define Q_OS_QNX #elif defined(_SEQUENT_) # define Q_OS_DYNIX #elif defined(_SCO_DS) /* SCO OpenServer 5 + GCC */ # define Q_OS_SCO #elif defined(__USLC__) /* all SCO platforms + UDK or OUDK */ # define Q_OS_UNIXWARE #elif defined(__svr4__) && defined(i386) /* Open UNIX 8 + GCC */ # define Q_OS_UNIXWARE #elif defined(__INTEGRITY) # define Q_OS_INTEGRITY #elif defined(VXWORKS) /* there is no "real" VxWorks define - this has to be set in the mkspec! */ # define Q_OS_VXWORKS #elif defined(__HAIKU__) # define Q_OS_HAIKU #elif defined(__MAKEDEPEND__) #else # error "Qt has not been ported to this OS - see http://www.qt-project.org/" #endif #if defined(Q_OS_WIN32) || defined(Q_OS_WIN64) || defined(Q_OS_WINCE) || defined(Q_OS_WINRT) # define Q_OS_WIN #endif #if defined(Q_OS_DARWIN) # define Q_OS_MAC # if defined(Q_OS_DARWIN64) # define Q_OS_MAC64 # elif defined(Q_OS_DARWIN32) # define Q_OS_MAC32 # endif # include <TargetConditionals.h> # if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE # define Q_OS_IOS # elif defined(TARGET_OS_MAC) && TARGET_OS_MAC # define Q_OS_OSX # define Q_OS_MACX // compatibility synonym # endif #endif #if defined(Q_OS_WIN) # undef Q_OS_UNIX #elif !defined(Q_OS_UNIX) # define Q_OS_UNIX #endif #ifdef Q_OS_DARWIN # include <Availability.h> # include <AvailabilityMacros.h> # # ifdef Q_OS_OSX # if !defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_6 # undef __MAC_OS_X_VERSION_MIN_REQUIRED # define __MAC_OS_X_VERSION_MIN_REQUIRED __MAC_10_6 # endif # if !defined(MAC_OS_X_VERSION_MIN_REQUIRED) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6 # undef MAC_OS_X_VERSION_MIN_REQUIRED # define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_6 # endif # endif # # // Numerical checks are preferred to named checks, but to be safe # // we define the missing version names in case Qt uses them. # # if !defined(__MAC_10_7) # define __MAC_10_7 1070 # endif # if !defined(__MAC_10_8) # define __MAC_10_8 1080 # endif # if !defined(__MAC_10_9) # define __MAC_10_9 1090 # endif # if !defined(__MAC_10_10) # define __MAC_10_10 101000 # endif # if !defined(__MAC_10_11) # define __MAC_10_11 101100 # endif # if !defined(MAC_OS_X_VERSION_10_7) # define MAC_OS_X_VERSION_10_7 1070 # endif # if !defined(MAC_OS_X_VERSION_10_8) # define MAC_OS_X_VERSION_10_8 1080 # endif # if !defined(MAC_OS_X_VERSION_10_9) # define MAC_OS_X_VERSION_10_9 1090 # endif # if !defined(MAC_OS_X_VERSION_10_10) # define MAC_OS_X_VERSION_10_10 101000 # endif # if !defined(MAC_OS_X_VERSION_10_11) # define MAC_OS_X_VERSION_10_11 101100 # endif # # if !defined(__IPHONE_4_3) # define __IPHONE_4_3 40300 # endif # if !defined(__IPHONE_5_0) # define __IPHONE_5_0 50000 # endif # if !defined(__IPHONE_5_1) # define __IPHONE_5_1 50100 # endif # if !defined(__IPHONE_6_0) # define __IPHONE_6_0 60000 # endif # if !defined(__IPHONE_6_1) # define __IPHONE_6_1 60100 # endif # if !defined(__IPHONE_7_0) # define __IPHONE_7_0 70000 # endif # if !defined(__IPHONE_7_1) # define __IPHONE_7_1 70100 # endif # if !defined(__IPHONE_8_0) # define __IPHONE_8_0 80000 # endif # if !defined(__IPHONE_8_1) # define __IPHONE_8_1 80100 # endif # if !defined(__IPHONE_8_2) # define __IPHONE_8_2 80200 # endif # if !defined(__IPHONE_8_3) # define __IPHONE_8_3 80300 # endif # if !defined(__IPHONE_8_4) # define __IPHONE_8_4 80400 # endif # if !defined(__IPHONE_9_0) # define __IPHONE_9_0 90000 # endif #endif #ifdef __LSB_VERSION__ # if __LSB_VERSION__ < 40 # error "This version of the Linux Standard Base is unsupported" # endif #ifndef QT_LINUXBASE # define QT_LINUXBASE #endif #endif #endif // QSYSTEMDETECTION_H