C++跨平台编译的核心难点在于不同操作系统使用的编译工具链、库路径、编译参数存在差异,比如Windows常用MSVC编译器,Linux常用GCC,macOS常用Clang,手动为每个平台编写构建脚本效率极低。CMake通过抽象构建流程,让开发者只需要编写一份统一的配置文件,就能自动生成对应平台的构建文件,比如Windows的Visual Studio工程、Linux的Makefile、macOS的Xcode工程。

CMake基础概念
CMake本身不是编译器,而是一个构建系统生成器,它的核心配置文件是CMakeLists.txt,开发者在这个文件中定义项目的源码、依赖、编译选项等信息,CMake会根据当前平台生成对应的原生构建文件,再调用对应平台的编译器完成编译。
核心术语说明
- 项目(Project):通过
project()命令定义,指定项目名称和支持的编程语言 - 目标(Target):可以是可执行文件或者库,通过
add_executable()或add_library()定义 - 属性(Property):目标的编译参数、包含目录、链接库等配置,通过
target_*系列命令设置
基础CMake配置示例
下面以一个最简单的单文件C++项目为例,演示基础的CMake配置流程,项目结构如下:
project_root/ ├── CMakeLists.txt └── main.cpp
单文件项目配置
main.cpp的内容如下:
#include <iostream>
int main() {
std::cout << "Hello Cross Platform" << std::endl;
return 0;
}
对应的CMakeLists.txt配置如下:
# 指定CMake最低版本要求 cmake_minimum_required(VERSION 3.10) # 定义项目名称和支持的语言 project(hello_cross_platform CXX) # 设置C++标准 set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 添加可执行文件目标,指定源码文件 add_executable(hello_main main.cpp)
在Linux或macOS平台,可以在项目根目录执行以下命令完成编译:
mkdir build cd build cmake .. make
在Windows平台,执行cmake ..后会生成Visual Studio工程文件,打开工程编译即可,不需要修改任何配置。
多文件多目录项目配置
实际项目通常会包含多个源码文件和目录,下面演示一个包含工具库的项目配置,项目结构如下:
project_root/
├── CMakeLists.txt
├── main.cpp
└── utils/
├── CMakeLists.txt
├── str_utils.h
└── str_utils.cpp
子目录库配置
utils目录下的str_utils.h内容:
#ifndef STR_UTILS_H #define STR_UTILS_H #include <string> std::string get_greet_msg(const std::string& name); #endif
utils目录下的str_utils.cpp内容:
#include "str_utils.h"
std::string get_greet_msg(const std::string& name) {
return "Hello " + name;
}
utils目录下的CMakeLists.txt配置,用于生成静态库:
# 添加静态库目标
add_library(str_utils STATIC str_utils.cpp)
# 设置库的公开头文件目录,其他目标引用该库时可以自动找到头文件
target_include_directories(str_utils PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
根目录配置
根目录的CMakeLists.txt需要添加子目录并链接库:
cmake_minimum_required(VERSION 3.10) project(multi_file_project CXX) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 添加子目录,CMake会自动处理子目录的CMakeLists.txt add_subdirectory(utils) # 添加可执行文件目标 add_executable(app_main main.cpp) # 链接子目录生成的库到可执行文件 target_link_libraries(app_main PRIVATE str_utils)
根目录的main.cpp内容:
#include <iostream>
#include "str_utils.h"
int main() {
std::string msg = get_greet_msg("CMake User");
std::cout << msg << std::endl;
return 0;
}
跨平台差异处理
不同平台可能存在接口差异,CMake提供了条件判断语法来处理平台特有的逻辑,比如Windows和Linux的线程库差异:
# 判断当前平台
if(WIN32)
# Windows平台链接系统线程库
target_link_libraries(app_main PRIVATE pthread)
elseif(UNIX)
# Linux/macOS平台链接pthread库
target_link_libraries(app_main PRIVATE pthread)
endif()
也可以通过target_compile_definitions添加平台宏,在代码中做条件编译:
if(WIN32)
target_compile_definitions(app_main PRIVATE PLATFORM_WINDOWS)
elseif(UNIX)
target_compile_definitions(app_main PRIVATE PLATFORM_UNIX)
endif()
对应的C++代码可以这样写:
#include <iostream>
int main() {
#ifdef PLATFORM_WINDOWS
std::cout << "Running on Windows" << std::endl;
#elif defined(PLATFORM_UNIX)
std::cout << "Running on Unix-like system" << std::endl;
#endif
return 0;
}
常用CMake命令总结
| 命令 | 作用 |
|---|---|
| cmake_minimum_required | 指定项目所需的最低CMake版本 |
| project | 定义项目名称和编程语言 |
| add_executable | 添加可执行文件构建目标 |
| add_library | 添加库构建目标,支持静态库、动态库 |
| add_subdirectory | 添加子目录,处理子目录的CMake配置 |
| target_include_directories | 设置目标的头文件搜索目录 |
| target_link_libraries | 设置目标需要链接的库 |
| target_compile_options | 设置目标的编译参数 |
掌握以上基础配置后,就可以应对大部分C++项目的跨平台编译需求,CMake还支持依赖查找、安装规则配置、测试配置等高级功能,可以根据项目需求进一步扩展。