现代CMake高级教程 - 第 8 章:跨平台与编译器

双笙子佯谬老师的【公开课】现代CMake高级教程课程笔记

第 8 章:跨平台与编译器

在 CMake 中给 .cpp 定义一个宏

#include <cstdio>

int main()
{
#ifdef MY_MACRO
	printf("MY_MACRO defined! value: %d\n", MY_MACRO);
#else
	printf("MY_MACRO not defined!\n");
#endif
}

CMakeLists.txt

add_executable(main)
file(GLOB sources CONFIGURE_DEPENDS *.cpp *.h)
target_sources(main PUBLIC ${sources})
target_compile_definitions(main PUBLIC MY_MACRO=233)

编译运行结果:

MY_MACRO defined! value: 233

跨平台

根据不同的操作系统,把宏定义成不同的值:
main.cpp

#include <cstdio>

int main()
{
#ifdef MY_NAME 
	printf("Hello, %s\n", MY_NAME);
#else
	printf("I don't know your name!\n");
#endif
}

CMakeLists.txt

if (CMAKE_SYSTEM_NAME MATCHES "Windows")
	target_compile_definitions(main PUBLIC MY_NAME="Bill Gates")
elseif (CMAKE_SYSTEM_NAME MATCHES "Linux")
	target_compile_definitions(main PUBLIC MY_NAME="Linus Torvalds")
elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin")
	target_compile_definitions(main PUBLIC MY_NAME="Steve Jobs")
endif()

编译运行结果:

❯ ./build/main
Hello, Linus Torvalds

CMake 还提供了一些简写变量:WIN32, APPLE, UNIX, ANDROID, IOS 等

CMakeLists.txt

if (WIN32)
	target_compile_definitions(main PUBLIC MY_NAME="Bill Gates")
elseif (UNIX AND NOT APPLE)
	target_compile_definitions(main PUBLIC MY_NAME="Linus Torvalds")
elseif (APPLE)
	target_compile_definitions(main PUBLIC MY_NAME="Steve Jobs")
elseif (ANDROID)
    target_compile_definitions(main PUBLIC MY_NAME="Andy Rubin")
elseif (IOS)
    target_compile_definitions(main PUBLIC MY_NAME="Steve Jobs")
endif()

编译运行结果:

❯ ./build/main
Hello, Linus Torvalds

使用生成器表达式,简化成一条指令
语法:

$<$<类型:值>:为真时的表达式>

比如

$<$<PLATFORM_ID:Windows>:MY_NAME=”Bill Gates”>

在 Windows 平台上会变为 MY_NAME="Bill Gates",其他平台上则表现为空字符串。

target_compile_definitions(main PUBLIC
	$<$<PLATFORM_ID:Windows>:MY_NAME="Bill Gates">
	$<$<PLATFORM_ID:Linux>:MY_NAME="Linus Torvalds">
	$<$<PLATFORM_ID:Darwin>:MY_NAME="Steve Jobs">)

编译运行结果:

❯ ./build/main
Hello, Linus Torvalds

如需多个平台可以用逗号分割:

target_compile_definitions(main PUBLIC
	$<$<PLATFORM_ID:Windows>:MY_NAME="Dos-like">
	$<$<PLATFORM_ID:Linux,Darwin,FreeBSD>:MY_NAME="Unix-like">)

编译运行结果:

❯ ./build/main
Hello, Unix-like

多编译器

判断当前用的是哪一款 C++ 编译器

if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
	target_compile_definitions(main PUBLIC MY_NAME="gcc")
elseif (CMAKE_CXX_COMPILER_ID MATCHES "NVIDIA")
	target_compile_definitions(main PUBLIC MY_NAME="nvcc")
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
	target_compile_definitions(main PUBLIC MY_NAME="clang")
elseif (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
	target_compile_definitions(main PUBLIC MY_NAME="msvc")
endif ()

编译运行结果:

❯ ./build/main
Hello, gcc

也可以用生成器表达式判断编译器:

target_compile_definitions(main PUBLIC
	$<$<CXX_COMPILER_ID:GNU,Clang>:MY_NAME="Open-source">
	$<$<CXX_COMPILER_ID:MSVC,NVIDIA>:MY_NAME="Commercial">)

编译运行结果:

❯ ./build/main
Hello, Open-source!

生成器表达式也可以做复杂的逻辑判断:

target_compile_definitions(main PUBLIC
	$<$<AND:$<CXX_COMPILER_ID:GNU,Clang>,$<PLATFORM_ID:Linux,FreeBSD>>:MY_NAME="Open-source">)

编译运行结果:

❯ ./build/main
Hello, Open-source!
简写变量

CMake 还提供了一些简写变量:MSVC, CMAKE_COMPILER_IS_GNUCC

if (MSVC)
	target_compile_definitions(main PUBLIC MY_NAME="MSVC")
elseif (CMAKE_COMPILER_IS_GNUCC)
	target_compile_definitions(main PUBLIC MY_NAME="GCC")
else ()
	target_compile_definitions(main PUBLIC MY_NAME="Other compiler")
endif ()

编译运行结果:

❯ ./build/main
Hello, GCC
CMAKE_CXX_COMPILER_ID 直接作为字符串变量
target_compile_definitions(main PUBLIC MY_NAME="The ${CMAKE_CXX_COMPILER_ID} Compiler")

编译运行结果:

❯ ./build/main
Hello, The GNU Compiler
从命令行参数指定编译器
cmake -B build -DCMAKE_CXX_COMPILER="/usr/bin/clang++" -DCMAKE_C_COMPILER="/usr/bin/clang"

编译运行结果:

❯ ./build/main
Hello, The Clang Compile

也可以通过环境变量 CXX 指定

$ CXX='which clang' cmake -B build
CMAKE_GENERATOR
message("Generator: ${CMAKE_GENERATOR}")
message("C++ compiler: ${CMAKE_CXX_COMPILER}")
message("C compiler: ${CMAKE_C_COMPILER}")

生成结果:

Generator: Unix Makefiles
C++ compiler: /usr/bin/clang++
C compiler: /usr/bin/clang

vimrc 分享

小彭老师使用的 vimrc 分享:github.com/archibate/vimrc

" for cmake4vim:
let g:cmake_usr_args = '-GNinja'
let g:cmake_build_target = 'main'
let g:cmake_build_type = 'Release'
let g:cmake_compile_commands = 1
let g:cmake_build_path_pattern = ["/tmp/build/%s", "getcmd()"]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值