1. cmake检测平台架构及编译器的原理
cmake在检测编译器的时候,用了一种很暴力的方法。可以在不运行实际代码的情况下直接知道目标平台的信息。做法是这样的。
首先生成一个.cpp文件,包含一些平台检测的#ifdef
/* Identify known platforms by name. */
#if defined(__linux) || defined(__linux__) || defined(linux)
# define PLATFORM_ID "Linux"
#elif defined(__CYGWIN__)
# define PLATFORM_ID "Cygwin"
#elif defined(__MINGW32__)
# define PLATFORM_ID "MinGW"
#elif defined(__APPLE__)
# define PLATFORM_ID "Darwin"
#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
# define PLATFORM_ID "Windows"
以及架构检测的#ifdef
#if defined(_WIN32) && defined(_MSC_VER)
# if defined(_M_IA64)
# define ARCHITECTURE_ID "IA64"
# elif defined(_M_X64) || defined(_M_AMD64)
# define ARCHITECTURE_ID "x64"
# elif defined(_M_IX86)
# define ARCHITECTURE_ID "X86"
# elif defined(_M_ARM)
# if _M_ARM == 4
# define ARCHITECTURE_ID "ARMV4I"
# elif _M_ARM == 5
# define ARCHITECTURE_ID "ARMV5I"
# else
之后,定义两个char const*常量
char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]";
char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]";
然后把这个cpp编译成二进制。你以为要运行它?不是的。对于交叉编译的情况来说,目标平台的二进制是没法在编译平台上运行的。所以cmake用了一招更狠的,直接打开二进制文件,搜索字符串。比如在Windows x64平台上,刚才那两个常量就会被编译INFO:platform[Windows]和INFO:arch[x64]。而这样的字符串,一定存在于二进制文件里的。所以只要搜INFO:platform,后面[]里的就是平台;搜索INFO:arch,后面[]里的就是架构。同理,cmake里还有对编译器和编译器版本等信息的检测,都是这么来的。
C++ 如何跨平台判断操作系统是32位还是64位? - 知乎
CMake/CMakePlatformId.h.in at 989ca432e4d842e50f07a1ff05dc4a65fc9881cb · Kitware/CMake · GitHub
2. 相关变量
CMAKE_MAJOR_VERSION:cmake 主版本号,比如 3.4.1 中的 3
CMAKE_MINOR_VERSION:cmake 次版本号,比如 3.4.1 中的 4
CMAKE_PATCH_VERSION:cmake 补丁等级,比如 3.4.1 中的 1
CMAKE_SYSTEM:系统名称,比如 Linux-2.6.22
CMAKE_SYSTEM_NAME:不包含版本的系统名,比如 Linux
CMAKE_SYSTEM_VERSION:系统版本,比如 2.6.22
CMAKE_SYSTEM_PROCESSOR:处理器名称,比如 i686
UNIX:在所有的类 UNIX 平台下该值为 TRUE,包括 OS X 和 cygwin
WIN32:在所有的 win32 平台下该值为 TRUE,包括 cygwin
CMAKE_HOST_SYSTEM_NAME:上面那个是交叉编译的目标系统,这个是主机
交叉编译的话系统名也可以自己在xxx.cmake中设置,如:
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
toolchains/aarch64-linux-gnu-c.toolchain.cmake · 腾讯开源/ncnn - Gitee.com
3. 代码实例
if(ANDROID OR IOS OR NCNN_SIMPLESTL OR CMAKE_CROSSCOMPILING)
option(NCNN_DISABLE_RTTI "disable rtti" ON)
option(NCNN_BUILD_TOOLS "build tools" OFF)
option(NCNN_BUILD_EXAMPLES "build examples" OFF)
else()
option(NCNN_DISABLE_RTTI "disable rtti" OFF)
option(NCNN_BUILD_TOOLS "build tools" ON)
option(NCNN_BUILD_EXAMPLES "build examples" ON)
endif()
if(ANDROID OR IOS OR LINUX OR NCNN_SIMPLESTL)
option(NCNN_DISABLE_EXCEPTION "disable exception" ON)
else()
option(NCNN_DISABLE_EXCEPTION "disable exception" OFF)
endif()
CMakeLists.txt · 腾讯开源/ncnn - Gitee.com