第4章:构建系统入门:CMake 的安装与基本语法
说到跨平台开发,构建系统是绕不开的话题。我个人习惯用 CMake,原因很简单——它几乎成了事实标准。你想想看,从嵌入式到服务器,从桌面应用到移动端,CMake 都能搞定。今天我们就来聊聊它的安装和基本语法。
4.1 为什么是 CMake?
我记得刚入行那会儿,项目里用的是 Makefile。每个平台写一套,Windows 用 nmake,Linux 用 GNU Make,macOS 还得折腾 Xcode 的 project 文件。那叫一个痛苦。后来接触到 CMake,才发现原来构建可以这么清爽。
CMake 的核心思想很简单:一次编写,到处构建。你只需要写一份 CMakeLists.txt,它就能自动生成对应平台的构建文件。说白了,它是个「构建系统的生成器」。
核心优势:
- 跨平台:Windows、Linux、macOS、Android、iOS 全支持
- 跨编译器:GCC、Clang、MSVC、MinGW 无缝切换
- 生态丰富:几乎所有 C++ 库都提供 CMake 支持
- 可扩展:支持自定义模块和函数
4.2 安装 CMake
安装 CMake 其实没什么难度,但不同平台略有差异。我建议你直接装最新稳定版,别用系统自带的旧版本——我在项目中遇到过因为 CMake 版本太低导致某些特性用不了的尴尬。
Windows 平台
- 去 cmake.org/download/ 下载 .msi 安装包
- 安装时勾选「Add CMake to the system PATH」
- 安装完成后打开命令行,输入
cmake --version验证
小技巧:Windows 上我习惯同时装 CMake 和 CMake GUI。GUI 工具对新手友好,可以直观地看到所有配置选项。
Linux 平台
# Ubuntu/Debian
sudo apt update
sudo apt install cmake
# CentOS/RHEL
sudo yum install cmake
# 或者从源码编译(推荐)
wget https://github.com/Kitware/CMake/releases/download/v3.28.0/cmake-3.28.0.tar.gz
tar -xzf cmake-3.28.0.tar.gz
cd cmake-3.28.0
./bootstrap && make && sudo make install
macOS 平台
# 用 Homebrew 安装(最简单)
brew install cmake
# 或者下载 .dmg 安装包
# 从 cmake.org 下载后直接拖到 Applications 文件夹
注意:macOS 上如果遇到「cmake: command not found」,记得检查 PATH 是否包含 /usr/local/bin。我曾经在这上面浪费了半小时。
4.3 CMake 基本语法
CMake 的语法其实不复杂。它用的是自己的脚本语言,但核心概念就那么几个。我们从一个最简单的例子开始。
4.3.1 第一个 CMakeLists.txt
# CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(HelloWorld)
add_executable(hello main.cpp)
这三行干了什么?
cmake_minimum_required:指定最低 CMake 版本。嗯,这里要注意,版本号别写太高,否则别人用旧版 CMake 会报错。project:定义项目名称。这个名称会影响到后续的一些变量,比如PROJECT_NAME。add_executable:告诉 CMake 我们要生成一个可执行文件,源文件是main.cpp。
然后怎么用?
mkdir build
cd build
cmake ..
cmake --build .
为什么要有 build 目录?我个人习惯把构建产物和源码分开,这样 git clean 的时候不会误删源码。这叫「out-of-source build」,是 CMake 推荐的做法。
4.3.2 变量与缓存
CMake 里变量用 set() 来定义:
set(SOURCES main.cpp utils.cpp network.cpp)
add_executable(myapp ${SOURCES})
这里 ${SOURCES} 就是引用变量。你想想看,如果源文件有几十个,一个个列在 add_executable 里多痛苦?用变量管理就清爽多了。
还有一种特殊变量叫「缓存变量」,它可以在命令行里修改:
set(MY_VAR "default" CACHE STRING "Description of my var")
然后你可以这样覆盖:
cmake .. -DMY_VAR="custom_value"
我在项目中经常用这个来切换 Debug/Release 模式,或者指定不同的第三方库路径。
4.3.3 条件判断
跨平台开发免不了要判断操作系统:
if(WIN32)
message("Building on Windows")
add_definitions(-DWINDOWS)
elseif(APPLE)
message("Building on macOS")
add_definitions(-DMACOS)
else()
message("Building on Linux")
add_definitions(-DLINUX)
endif()
除了 WIN32、APPLE,常用的还有:
UNIX:所有 Unix-like 系统(包括 macOS)MSVC:Visual Studio 编译器CMAKE_BUILD_TYPE:构建类型(Debug/Release)
避坑指南:我曾经在 macOS 上用 if(UNIX) 来判断 Linux,结果发现 macOS 也被包含进去了。后来才搞清楚,UNIX 在 CMake 里包括 macOS、Linux、BSD 等所有类 Unix 系统。要精确判断 Linux,得用 if(CMAKE_SYSTEM_NAME STREQUAL "Linux")。
4.3.4 循环与列表操作
有时候你需要批量处理文件:
set(FILES file1.cpp file2.cpp file3.cpp)
foreach(F ${FILES})
message("Processing: ${F}")
endforeach()
列表操作也很常用:
list(APPEND SOURCES new_file.cpp)
list(REMOVE_ITEM SOURCES old_file.cpp)
list(LENGTH SOURCES len)
message("Source count: ${len}")
4.4 核心知识体系
下面这张图总结了 CMake 的核心概念和它们之间的关系:
4.5 实战:一个跨平台的小项目
光说不练假把式。我们写一个完整的 CMakeLists.txt,支持跨平台编译:
cmake_minimum_required(VERSION 3.10)
project(CrossPlatformDemo VERSION 1.0.0 LANGUAGES CXX)
# 设置 C++ 标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 收集源文件
file(GLOB SOURCES "src/*.cpp")
# 根据平台添加不同的源文件
if(WIN32)
list(APPEND SOURCES "src/platform/win32.cpp")
add_definitions(-DPLATFORM_WINDOWS)
elseif(APPLE)
list(APPEND SOURCES "src/platform/macos.mm")
add_definitions(-DPLATFORM_MACOS)
else()
list(APPEND SOURCES "src/platform/linux.cpp")
add_definitions(-DPLATFORM_LINUX)
endif()
# 创建可执行文件
add_executable(${PROJECT_NAME} ${SOURCES})
# 添加头文件路径
target_include_directories(${PROJECT_NAME} PRIVATE include)
# 链接第三方库(如果有)
# find_package(OpenCV REQUIRED)
# target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS})
小提示:file(GLOB ...) 虽然方便,但 CMake 官方不推荐在大型项目中使用,因为它不会自动检测新增文件。我个人的做法是:小项目用 GLOB,大项目手动列出源文件。
4.6 常见问题与避坑
最后分享几个我踩过的坑:
- 路径中的空格:Windows 上 Program Files 有空格,记得用双引号包起来,或者用
file(TO_CMAKE_PATH ...)转换。 - 大小写敏感:CMake 命令不区分大小写,但变量名区分。我习惯全小写命令,全大写变量。
- 缓存问题:修改了 CMakeLists.txt 后,记得重新运行
cmake ..,有时候缓存没更新会导致奇怪的问题。我一般直接删掉 build 目录重新来。
嗯,CMake 的基本用法就这些。掌握了这些,你已经能应付大部分跨平台构建场景了。记住,CMake 的文档非常完善,遇到问题先查官方文档,比在网上乱搜高效得多。