跳转至

关于CMakeLists文件

CMakeLists.txt文件是CMake的编译配置文件,它定义了一个C++如何编译源代码,如何链接库文件,以及如何生成可执行文件。

最简单的CMakeLists.txt文件

对于简单的、依赖关系明确的项目,文件中最少需要包含下面三行

CMake
1
2
3
4
5
cmake_minimum_required(VERSION 3.1.0) # CMake版本要求

project(myproject) # 项目名称

add_executable(myproject main.cpp) # 生成的可执行文件名称 与 用到的源代码文件名(可以多个,空格隔开)

常用变量

工程名

在用project()定义工程名后,${PROJECT_NAME}会指向该工程名,后续文件中可以用${PROJECT_NAME}来引用工程名。

CMake
1
2
3
project(myproject)

add_executable(${PROJECT_NAME} main.cpp) # ${PROJECT_NAME}会被替换为myproject

工程根路径

PROJECT_SOURCE_DIR/CMAKE_SOURCE_DIR/_SOURCE_DIR为包含project()命令的最近一个CMakeLists.txt文件所在的文件夹路径。

CMake
set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/dependencies/opencv-4.11.0/build)
find_package(OpenCV 4.11.0 REQUIRED)

工程构建目录

PROJECT_BINARY_DIR/CMAKE_BINARY_DIR/_BINARY_DIR为运行cmake命令的目录,即工程编译发生的路径,一般是build文件夹。

最终可执行文件的生成路径

EXECUTABLE_OUTPUT_PATH用于指定最终的可执行文件的位置。

CMake
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

库文件的生成路径

CMake
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) 

以上两个变量在新版本中已被CMAKE_RUNTIME_OUTPUT_DIRECTORYCMAKE_ARCHIVE_OUTPUT_DIRECTORY代替。

在系统环境中查找指定依赖

当项目中包含第三方库(源码不在工程目录下的库)时,需要添加查找命令。

对于全局安装且环境变量配置正确的库,CMake会自动找到。

CMake
1
2
3
4
5
6
7
find_package(OpenCV) # 如果找不到该库,报错但是继续编译

find_package(OpenCV REQUIRED) # 如果找不到该库,报错并停止编译

find_package(OpenCV QUIET) # 静默模式,找不到该库时不报错

find_package(OpenCV 4.2) # 指定版本,找不到该版本时报错

如果无法自动识别,可以手动指定查找路径。

CMake
find_package(SomeLib REQUIRED
    PATHS "/path/to/somelib" 
          "/another/path")      # 在查找命令后面直接指定

set(SomeLib_DIR "/path/to/somelib/cmake")  # 指定查找目录
find_package(SomeLib REQUIRED)             # 然后再查找

set(CMAKE_PREFIX_PATH 
    "/path/to/custom/libs;/another/path")  # 指定全局查找路径
find_package(SomeLib REQUIRED)             # 然后再查找
参考博客:CMake 中配置 find_package 的搜索路径

指定头文件搜索路径

在C++项目中一般会将头文件和源文件分开存放,此时需要我们指定包含头文件的目录名。

CMake
1
2
3
4
include_directories(
    include/
    ${OpenCV_INCLUDE_DIRS}  # 正确执行find_package(OpenCV)后该变量会自动指向OpenCV的头文件目录
)

使用存储匹配文件列表的变量名

例如项目中存在大量的源文件,需要都添加到add_executable()命令中,一个一个输入将非常麻烦。

此时可以将所有的源文件存储到一个变量中,然后再添加到add_executable()命令里面。

CMake
1
2
3
4
5
6
7
# GLOB表示从根目录开始全局查找,SOURCES是变量名,后面跟着要匹配的文件,可以多个,空格隔开,*号是通配符
file(GLOB SOURCES src/*.cpp) 

add_executable(${PROJECT_NAME} 
    ${SOURCES} 
    ui/widget.ui include/widget.hpp
)

潜在问题

使用file(GLOB ···)生成构建文件后,在make编译时不会自动检测匹配的源文件的增减和改动,因此在添加或删除源文件后,需要手动重新运行 CMake 然后再make编译才会更新。

链接库文件到指定目标

当项目中引入了第三库时,不仅需要寻找依赖库来让编译器知道相关代码如何编译,往往还需要将生成的可执行文件和引用的库文件(例如Linux系统中的以.so为后缀名的动态链接库)链接起来,这样才能运行。

CMake
1
2
3
4
target_link_libraries(${PROJECT_NAME}      # 可执行文件(目标)名
    Qt5::Widgets Qt5::Core Qt5::Gui     # 需要链接的库名
    ${OpenCV_LIBS}  # 正确执行find_package(OpenCV)后该变量会自动指向OpenCV的库文件
)