构建项目时难免需要一些跟平台或环境相关的依赖文件或代码,这时候就需要在构建项目时能够识别出不同的环境。

检查操作系统

1
2
3
4
5
6
7
8
9
cmake_minimum_required(VERSION 3.20)

project(cmake2 LANGUAGES CXX)

if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
message(STATUS "configuring on/for Linux")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
message(STATUS "configuring on/for Windows")
endif()

例如CMakeLists.txt中这样几行代码,在执行cmake ..时,会打印出下面内容

1
2
3
4
-- Selecting Windows SDK version 10.0.22621.0 to target Windows 10.0.19045.
-- configuring on/for Windows
-- Configuring done (0.0s)
-- Generating done (0.0s)

其中就检测到了我当前的环境是windows环境,于是打印了对应的一句话。

工作原理

CMake中定义了CMAKE_SYSTEM_NAME变量,类Linux环境下如果有uname命令,可以看作是uname -s命令输出的内容,比如在ubuntu下就会输出Linux,Windows下不知道是哪个命令,不过从上面输出内容来看,应该会输出字符串Windows。

平台相关代码

如果main.cpp中有这样一段代码

1
2
3
4
5
6
7
8
9
10
int main() {

#ifdef IS_LINUX
cout << "hello, linux!\n";
#elif IS_WINDOWS
cout << "hello, windows!\n";
#endif

return 0;
}

然后在CMakeLists.txt中根据不同的操作系统定义了不同的宏,就可以使源码在不同环境下有不同的表现。

1
2
3
4
5
6
7
8
9
file(GLOB Src *.cpp)

add_executable(target ${Src})

if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_compile_definitions(target PUBLIC "IS_LINUX")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
target_compile_definitions(target PUBLIC "IS_WINDOWS")
endif()

这样如果在Windows环境下执行生成的target.exe,就会在终端中看到

1
hello, windows!

编译器相关代码

如果在当前环境下有多个编译器可供使用,我们可以指定使用某个编译器来执行当前的编译工作,在CMake中也定义了CMAKE_CXX_COMPILER_ID变量来区分不同的编译器,例如GNUIntel等,这样我们可以执行和上述类似的操作,使代码在不同的编译器中有不同的表现行为。

处理器体系架构

众所周知,处理器有32位和64位之分,如果代码对于不同架构要表现不同的行为的话,就需要能够识别出当前的处理器是多少位的,可以通过CMake中定义的CMAKE_SIZEOF_VOID_P变量来识别,这个变量的意思是空指针的字节大小,我们知道32位CPU的指针大小是4字节,而64位CPU的指针大小是8字节,通过比较变量CMAKE_SIZEOF_VOID_P和8是否相等,就能够区分处理器的体系架构。

CMake不止上述的几个变量,关于主机系统的信息几乎都会有对应的变量,需要时可以查找对应的变量来配置项目。