CMake 的一个简单案例释义
案例
# CMakeLists.txt
cmake_minimum_required(VERSION 3.25)
project(main)
set(CMAKE_MAKE_PROGRAM "/usr/bin/make")
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED True)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/target/libs)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/target/libs)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/target)
set(BUILD_SHARED_LIBS ON)
set(SRC_LIST main.c)
add_library(sorting "libs/sorting.c")
add_library(utils "libs/utils.c")
add_library("string" "libs/string.c")
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_link_libraries("string" PUBLIC sorting utils)
target_link_libraries(${PROJECT_NAME} PUBLIC sorting utils "string")
-
cmake_minimum_required(VERSION 3.25)
。表示要求 CMake 程序的版本最低为3.25
,并设置CMAKE_MINIMUM_REQUIRED_VERSION
的值为3.25
。参见 cmake-minimum-required。[!note] 注意
CMake 文档建议在项目最顶级的CMakeLists.txt
文件 (因为这个文件是可以在子目录中再次配置的) 的最前面使用这个命令。并且建议要比project
命令 (见下) 要更早使用,且不要在某个function()
中调用此命令。 -
project(main)
。表示当前项目的名字。这个命令会设置当前CMakeLists.txt
文件所在范围内的PROJECT_NAME
变量。如果在顶级CMakeLists.txt
文件中使用,还会同时设置CMAKE_PROJECT_NAME
变量。其他一些用法比如设置项目描述信息、版本号等,参阅 project。 -
set(CMAKE_MAKE_PROGRAM "/usr/bin/make")
。首先set
命令用于手动设定一个变量的值,当需要将某个变量的值设置为空字符串时,可以使用set(<variable> "")
这样的写法。参见 set如果想要彻底清除一个变量,则需要使用
unset(<variable>)
命令,参见 unset其次,
CMAKE_MAKE_PROGRAM
表示需要在后续构建过程中使用的二进制程序名 (如果已经在PATH
环境变量中存在,就只需要二进制程序名,比如make
) 或者完整路径,比如/usr/bin/make
。参见 CMAKE_MAKE_PROGRAM。 -
set(CMAKE_C_STANDARD 11)
。表示将构建时使用的 C 语言标准设置为C11
。这个变量的值是添加构建目标 (target) 时对应C_STANDARD
属性的默认值。参见 CMAKE_C_STANDARD。 -
set(CMAKE_C_STANDARD_REQUIRED True)
。表示添加构建目标时需要设定C_STANDARD
属性,它常常与上一条的变量配合使用。参见 CMAKE_C_STANDARD_REQUIRED。 -
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/target/libs)
。CMAKE_ARCHIVE_OUTPUT_DIRECTORY
变量用于设定库构建目标的输出内容存放的位置,这里使用${CMAKE_BINARY_DIR}/target/libs
表示在项目根目录创建一个target/libs
的目录结构,用于存放相关构建产物。关于它与后面两项的区别,参见后文辨析CMAKE_LIBRARY_OUTPUT_DIRECTORY
、CMAKE_RUNTIME_OUTPUT_DIRECTORY
和CMAKE_ARCHIVE_OUTPUT_DIRECTORY
的部分。 -
set(BUILD_SHARED_LIBS ON)
。用于修改add_library()
命令的默认行为。默认情况下此命令会构建静态库,但是启用了这个变量后,默认会构建共享库。 -
set(SRC_LIST main.c)
。使用一个变量来代表源文件列表。这对于有多源文件复用或源文件很多的情况帮助较大。 -
add_library(sorting "libs/sorting.c")
等。定义一个名为sorting
的链接库。由于此前通过BUILD_SHARED_LIBS
开启了默认共享库构建,所以产物都是动态链接库。比如在 Windows 上,产物的名字是cygsorting.dll
。 -
add_executable(${PROJECT_NAME} ${SRC_LIST})
。这行命令的目的是定义程序的可执行文件生成目标。我们用项目名字 (早前使用project()
命令定义的名字) 为这个文件取名,然后通过变量SRC_LIST
表名需要使用的源文件清单。注意使用变量时需要使用${}
标记,这是与定义时不同的。 -
target_link_libraries("string" PUBLIC sorting utils)
。为某个构建目标指定依赖项。比如我们的string
库依赖sorting
和utils
,就需要这样定义。参见 target_link_libraries。
辨析
CMAKE_SOURCE_DIR
和 CMAKE_BINARY_DIR
默认情况下,这两个值是相同的,都是当前构建/树的顶级所在目录。如果没有使用 -S
和 -B
选项指定,也就是当采用了 in-source
模式,这两个值都是一样的。如果希望获取当前所在一级的构建树目录,应该使用 CMAKE_CURRENT_BINARY_DIR
变量;若是当前所在一级的源码树目录,则应该使用 CMAKE_CURRENT_SOURCE_DIR
变量。
参考:
CMAKE_LIBRARY_OUTPUT_DIRECTORY
、CMAKE_RUNTIME_OUTPUT_DIRECTORY
和 CMAKE_ARCHIVE_OUTPUT_DIRECTORY
这三个变量都是用来设置顶级 (全局) 构建产物 (buildsystem artifact) 的输出或存放位置的。
最容易判断的就是 CMAKE_RUNTIME_OUTPUT_DIRECTORY
,因为它一定是指构建产物中的 可执行文件 类型 (executable)。所谓可执行文件类型,具体分为两类:
- 常见的
.exe
可执行文件。对应的产物由add_executable()
命令来定义和产生; - 在 Windows 等 DLL 平台上,通过带有
SHARED
参数的add_library()
命令构建的所有共享库的可执行.dll
产物[1]。
其次 CMAKE_LIBRARY_OUTPUT_DIRECTORY
定义了 共享库 类型 (shared library) 构建产物的输出位置。共享库类型的产物可以通过以下方式定义:
- 通过带
MODULE
参数的add_library()
命令定义的所有可加载模块产物,如.so
或.lib
。 - 在 Linux、Unix、macOS 等非 DLL 平台上,通过带有
SHARED
参数的add_library()
命令构建的所有共享库的可执行.so
或.dylib
产物。
最后 CMAKE_LIBRARY_OUTPUT_DIRECTORY
定义了 归档 类型 (archive) 构建产物的输出位置。归档类型的产物可以通过以下方式定义:
- 通过带
STATIC
参数 (默认) 的add_library()
命令定义的所有静态链接库 (static library) 产物,如.a
或.lib
。 - 在 DLL 平台: 使用了
SHARED
选项的add_library()
命令定义的那些可供链接器导入的共享库目标 (如.lib
)。注意,只有当对应的库导出了至少一个非托管的符号 (unmanaged symbol) 时,才会生成对应的构建产物。 - 在 DLL 平台: 定义了
ENABLE_EXPORTS
属性的add_executable()
命令定义的那些可供链接器导入的文件 (比如.lib
)。 - 在 AIX 平台[2]: 定义了
ENABLE_EXPORTS
属性的add_executable()
命令定义的那些可供链接器导入的文件 (比如.imp
)。 - 在 macOS 平台,同时使用
SHARED
选项和ENABLE_EXPORTS
属性的add_library()
命令定义的那些可供链接器导入的文件 (比如.tbd
)。
参考: