cmake详解
project
project()
是 CMake 中的一个基本命令,用于设置和管理一个项目。
主要作用
- 定义项目名称:
MTSDKAll
就是你项目的名称。这个名称会被 CMake 用来生成项目文件(例如 Visual Studio 的.sln
文件或 Xcode 的.xcodeproj
文件)的名称,并且在内部的一些变量中也会使用。 - 设置变量:当
project()
命令被调用时,CMake 会自动设置一些有用的变量:PROJECT_NAME
:项目的名称,在这里就是MTSDKAll
。PROJECT_SOURCE_DIR
:项目根目录的完整路径。PROJECT_BINARY_DIR
:构建目录的完整路径。
- 启用默认语言:如果
project()
命令没有指定语言,它会自动启用 C 和 C++ 两种语言。如果你想只启用特定语言,可以这样写:project(MyProject LANGUAGES C CXX)
。
使用示例
通常,project()
命令会放在你的主 CMakeLists.txt
文件的第一行,因为它是定义项目最基本的步骤。
CMake
# 你的主 CMakeLists.txt 文件
cmake_minimum_required(VERSION 3.20)
project(MTSDKAll)# 告诉 CMake 在哪里找到头文件
include_directories(include)# 添加一个子目录
add_subdirectory(src)
在这个例子中,project(MTSDKAll)
告诉 CMake,这个项目叫做 MTSDKAll
,并且它将在这个目录下处理所有相关的构建工作。
CMAKE_CURRENT_SOURCE_DIR
CMAKE_CURRENT_SOURCE_DIR
是一个非常重要的 CMake 内置变量,它代表了 当前正在处理的 CMakeLists.txt
文件所在的目录的完整路径。
主要特点
- 动态性: 它的值会随着 CMake 处理不同的
CMakeLists.txt
文件而改变。- 在主项目根目录下的
CMakeLists.txt
中,CMAKE_CURRENT_SOURCE_DIR
的值就是项目的根目录路径。 - 在通过
add_subdirectory()
命令添加的子目录中的CMakeLists.txt
中,它的值就会变为该子目录的路径。
- 在主项目根目录下的
- 绝对路径: 它始终是一个绝对路径,而不是相对路径。这使得它在任何地方引用项目文件都非常安全和可靠,不会因为你从哪个目录运行
cmake
命令而受到影响。
使用场景举例
假设你的项目目录结构如下:
MyProject/
├── CMakeLists.txt
├── src/
│ ├── CMakeLists.txt
│ └── main.cpp
└── include/└── my_header.h
在 MyProject/CMakeLists.txt
中:
CMake
# 这里,CMAKE_CURRENT_SOURCE_DIR 的值为 /path/to/MyProject
add_subdirectory(src)
在 MyProject/src/CMakeLists.txt
中:
CMake
# 这里,CMAKE_CURRENT_SOURCE_DIR 的值为 /path/to/MyProject/src
add_executable(my_app main.cpp)# 如果你想引用 MyProject/include 目录下的头文件,你会这样做:
# 使用相对路径 (不推荐):
# include_directories(../include)# 使用 CMAKE_CURRENT_SOURCE_DIR (推荐):
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include)# 更好的做法是使用 CMAKE_SOURCE_DIR
# include_directories(${CMAKE_SOURCE_DIR}/include)
区别于 CMAKE_SOURCE_DIR
与 CMAKE_CURRENT_SOURCE_DIR
经常一起使用的另一个变量是 CMAKE_SOURCE_DIR
。
CMAKE_SOURCE_DIR
: 总是指向 整个项目的顶级源代码目录,即包含主CMakeLists.txt
文件的目录。它的值在整个 CMake 配置过程中都是固定的。CMAKE_CURRENT_SOURCE_DIR
: 动态地指向当前正在被处理的CMakeLists.txt
所在的目录。
一个简单的记忆方法:
CMAKE_SOURCE_DIR
是你项目的“家”(Home),永远不变。CMAKE_CURRENT_SOURCE_DIR
是你当前所在的“房间”(Current Room),会随着你进入子目录而改变。
在实践中,通常建议使用 CMAKE_SOURCE_DIR
来引用项目根目录下的文件或目录(比如许可证、顶层头文件目录等),而使用 CMAKE_CURRENT_SOURCE_DIR
来引用当前子目录中的文件。
intall
install()
是 CMake 中最重要和最常用的命令之一,它的核心作用是定义项目的安装规则。简单来说,它告诉 CMake 在用户执行 make install
(或 cmake --install .
) 命令时,应该将哪些文件或目录复制到什么位置。
为什么需要 install()
?
在软件开发中,构建和安装是两个不同的概念。
- 构建(Build):将源代码编译成可执行文件、库和目标文件,并将它们放在构建目录(通常是
build/
)中。 - 安装(Install):将构建好的文件(如可执行程序、动态库、头文件等)复制到系统或指定目录,以便其他人或程序可以使用它们。
install()
命令就是用来定义这个“安装”过程。
install()
的主要功能
install()
命令可以用来安装多种类型的文件,最常见的有以下几种:
-
目标(Targets):
- 可执行文件:将构建好的
.exe
或.bin
文件安装到指定目录。 - 库文件:将静态库(
.a
或.lib
)和动态库(.so
或.dll
)安装到指定目录。 - 目标:你可以直接指定一个由
add_executable()
或add_library()
创建的目标名,CMake 会自动处理它的所有相关文件。
示例:
CMake
# 将 my_app 可执行文件安装到 /usr/local/bin install(TARGETS my_app DESTINATION bin) # 将 my_lib 库安装到 /usr/local/lib install(TARGETS my_lib DESTINATION lib)
- 可执行文件:将构建好的
-
文件(Files):
- 将指定的源文件或数据文件安装到特定位置。这通常用于安装配置文件、文本文件或许可证文件。
示例:
CMake
# 将 LICENSE 文件安装到 /usr/local/share/my_project install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE"DESTINATION share/my_project)
-
目录(Directories):
- 将整个目录(及其内容)安装到指定位置。这通常用于安装头文件目录、数据目录或资源文件。
示例:
CMake
# 将 include 目录下的所有头文件安装到 /usr/local/include install(DIRECTORY include/ DESTINATION include)
关键参数
TARGETS
: 指定要安装的构建目标(可执行文件、库)。FILES
: 指定要安装的单个或多个文件。DIRECTORY
: 指定要安装的目录。DESTINATION
: 必选参数,指定文件或目录的安装路径。这个路径
foreach
foreach(p LIB BIN INCLUDE CMAKE) 这行 CMake 代码中的 p 是一个循环变量。
foreach 循环的工作原理
foreach 命令用于遍历一个列表。其基本语法是:
foreach(variable_name list_of_items)
… 循环体 …
endforeach()
variable_name: 这是一个临时的变量,在每次循环迭代时,它都会被赋予列表中的下一个值。
list_of_items: 你想要遍历的项的列表。
在你提供的代码中
foreach(p LIB BIN INCLUDE CMAKE)
p 就是这个临时的 循环变量。
LIB BIN INCLUDE CMAKE 是一个由四个字符串组成的列表。
在循环的第一次迭代中,p 的值是 “LIB”。在第二次迭代中,p 的值是 “BIN”,以此类推,直到遍历完列表中的所有项。
实际应用
这段代码通常用于简化 set 或 install 等命令,避免重复的代码。例如,你可能想为不同类型的文件设置不同的安装目录,并且这些目录的名称(如 lib, bin, include, cmake)与变量名相关。
一个简单的例子:
CMake
定义一个列表
set(types LIB BIN INCLUDE CMAKE)
遍历这个列表
foreach(p ${types})
打印当前循环变量的值
message(STATUS “Processing type: ${p}”)
endforeach()
这个循环会依次输出:
Processing type: LIB
Processing type: BIN
Processing type: INCLUDE
Processing type: CMAKE
TO_NATIVE_PATH
TO_NATIVE_PATH 是一个 CMake 命令,它的作用是将一个 CMake 风格的路径转换为当前操作系统所使用的原生路径格式。
为什么需要它?
CMake 在内部统一使用正斜杠 / 作为路径分隔符,这在所有操作系统上都能正常工作。但是,当 CMake 需要与外部工具或命令行程序交互时,这些程序可能只识别本系统自己的路径格式:
Windows:原生路径使用反斜杠 \(例如 C:\Users\user\file.txt)。
Linux/macOS:原生路径也使用正斜杠 /(例如 /home/user/file.txt)。
TO_NATIVE_PATH 命令就是为了解决这个问题。它会自动检测当前系统,并将变量中的路径转换为该系统所期望的格式。
语法和用法
TO_NATIVE_PATH(variable_name)
这个命令会直接修改传入的变量,而不是返回一个新值。
示例:
CMake
假设你在 Windows 上运行 CMake
CMAKE_SOURCE_DIR 的值为 C:/Users/user/my_project
set(MY_PATH “${CMAKE_SOURCE_DIR}/assets/image.png”)
在这里,MY_PATH 的值是 “C:/Users/user/my_project/assets/image.png”
使用 TO_NATIVE_PATH 转换路径
TO_NATIVE_PATH(MY_PATH)
现在,MY_PATH 的值已经被修改为 “C:\Users\user\my_project\assets\image.png”
常见应用场景
执行外部命令:当你使用 execute_process() 或 add_custom_command() 等命令来运行外部脚本或工具时,你需要确保传递给它们的路径是原生格式的。
使用脚本:将路径作为参数传递给 Python、Bash 或 PowerShell 脚本时。
虽然 CMake 的大多数内置命令都能自动处理路径,但当你需要与外部环境交互时,TO_NATIVE_PATH 是确保路径兼容性的可靠工具。