【学习笔记】使用CMake构建项目

CMake构建可执行文件


一、CMakeLists.txt命令编写

CMakeLists.txt必须添加的三个命令

cmake_minimum_required: 指定使用的CMake的最低版本(选填)。

project: 定义工程名称(必填),指定工程版本、工程描述、web主页地址、支持语言(默认支持所有语言)。

xml 复制代码
# PROJECT 指令语法:
project(<PROJECT-NAME> [<language-name>...])
project(<PROJECT-NAME>
       [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
       [DESCRIPTION <project-description-string>]
       [HOMEPAGE_URL <url-string>]
       [LANGUAGES <language-name>...])

add_executable: 命名可执行程序及使用的源文件,与project中的项目名无关联。

csharp 复制代码
# 样式1
add_executable(app add.c div.c main.c mult.c sub.c)
# 样式2
add_executable(app add.c;div.c;main.c;mult.c;sub.c)

常用操作

  1. 搜索源文件
bash 复制代码
# 方法1:搜索某路径下的所有源文件
aux_source_directory(< dir > < variable >)
​
# 方法2:按条件搜索文件,按文件名生成列表存储到自定义的变量中
file(GLOB/GLOB_RECURSE 变量名 要搜索的文件路径和文件类型)
    # --GLOB 搜索指定目录
    # --GLOB_RECURSE 递归搜索指定目录,包括子目录
    
# 用例:
file(GLOB MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
file(GLOB MAIN_HEAD ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h)
    # CMAKE_CURRENT_SOURCE_DIR宏表示当前访问的CMakeLists.txt文件所在的路径。
  1. 包含头文件
bash 复制代码
include_directories(${PROJECT_SOURCE_DIR}/include)
  1. 自定义宏
scss 复制代码
add_definitions(-D宏名称) # 通过自定义宏来控制程序中的某些代码
  1. 定义变量命令
  • set命令:存储文件名对应的字符串
css 复制代码
# set语法
set(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
# VAR: 变量名,VALUE: 变量值,[]中的内容为可选参数。
# 使用格式为 ${VAR}
​
# 用例:
set(SRC_LIST add.c  div.c   main.c  mult.c  sub.c)
add_executable(app  ${SRC_LIST})
  • 使用set设置C++程序版本标准:
ini 复制代码
# 方法1:在CMakeLists.txt中设置-std=c++11
set(CMAKE_CXX_STANDARD 11)
​
# 方法2:在cmake命令中设置
cmake CMakeLists.txt文件路径 -DCMAKE_CXX_STANDARD=17
  • 使用set指定可执行程序的输出路径:
bash 复制代码
set(HOME /home/robin/Linux/Sort) # 应使用绝对路径
set(EXECUTABLE_OUTPUT_PATH ${HOME}/bin) # 该路径下的子目录不存在将自动创建

变量操作

  1. 使用set命令拼接字符串
bash 复制代码
set(变量名 ${子变量} 常量字符串 "Hello world" ...) # 子变量内存储字符串
  1. 使用list命令
xml 复制代码
# 追加字符串
list(APPEND 变量名 ${子变量1} ${子变量2} ...) 
# 删除list中某字符串
list(REMOVE_ITEM <listname> ${子变量1} ...) 
# 获取list中的指定索引的变量元素
list(GET <listname> <index>)
# 查找列表指定元素,存在返回索引号,不存在返回-1
list(FIND <list> <value> <output variable>)
# 指定索引位置插入元素
list(INSERT <list> <element_index> <element> [<element> ...])
# 列表排序
list (SORT <list> [COMPARE <compare>] [CASE <case>] [ORDER <order>])

CMake日志输出

css 复制代码
message([STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR] "message to display" ...)
  • (无) :重要消息
  • STATUS :非重要消息
  • WARNING:警告代码或配置问题,影响构建过程的错误,会继续执行
  • AUTHOR_WARNING:警告,用来提供建议信息,会继续执行
  • SEND_ERROR:错误,继续执行,但是会跳过生成的步骤
  • FATAL_ERROR:错误,终止所有处理过程

CMake常用预定义宏

宏名 功能
CMAKE_C_COMPILER 指定 C 编译器的路径
CMAKE_CXX_COMPILER 指定 C++ 编译器的路径
CMAKE_BUILD_TYPE 指定构建类型(如 DebugReleaseRelWithDebInfoMinSizeRel
CMAKE_INSTALL_PREFIX 指定安装目录的前缀路径
CMAKE_SOURCE_DIR 顶层 CMakeLists.txt 文件所在的路径或项目源代码的顶层目录
CMAKE_BINARY_DIR 构建目录的路径或项目构建的顶层目录
CMAKE_CURRENT_SOURCE_DIR 当前处理的 CMakeLists.txt 文件所在的路径或当前处理的源目录
CMAKE_CURRENT_BINARY_DIR 当前处理的构建目录的路径或当前处理的构建目录
CMAKE_MODULE_PATH 额外的模块查找路径或用于查找 CMake模块的路径
CMAKE_INCLUDE_PATH 查找头文件的路径
CMAKE_LIBRARY_PATH 查找库文件的路径
CMAKE_PREFIX_PATH 查找包的前缀路径或用于查找软件包的前缀路径
CMAKE_RUNTIME_OUTPUT_DIRECTORY 指定所有目标运行时文件的输出目录
CMAKE_LIBRARY_OUTPUT_DIRECTORY 指定所有目标库文件的输出目录
CMAKE_ARCHIVE_OUTPUT_DIRECTORY 指定所有目标存档文件的输出目录
CMAKE_C_FLAGS 为 C 编译器设置的编译选项或C 编译器的默认编译选项
CMAKE_CXX_FLAGS 为 C++ 编译器设置的编译选项或C++ 编译器的默认编译选项
CMAKE_EXE_LINKER_FLAGS 为生成可执行文件设置的链接选项或可执行文件链接的默认链接选项
CMAKE_SHARED_LINKER_FLAGS 为生成共享库设置的链接选项或共享库链接的默认链接选项
CMAKE_MODULE_LINKER_FLAGS 为生成模块库设置的链接选项或模块库链接的默认链接选项
CMAKE_POSITION_INDEPENDENT_CODE 指定是否生成位置无关代码 (ONOFF)
CMAKE_EXPORT_COMPILE_COMMANDS 生成用于编译的 JSON 数据库 (compile_commands.json) 文件
CMAKE_SYSTEM_NAME 指定目标系统的名称或目标系统的名称
CMAKE_SYSTEM_VERSION 指定目标系统的版本或目标系统版本

二、控制台执行CMake命令

  1. 一般在build文件夹内,使用编写好的CMakeLists.txt文件,在命令行中执行CMake命令。
java 复制代码
$ cmake (CMakeLists.txt文件所在路径)
  1. 生成了Makefile文件后,执行Make命令。

三、CMakeList.txt

bash 复制代码
# 目录结构:
~/root/***/yourprogram$ tree
.
├── build
├── CMakeLists.txt
├── include
│   └── *.h
└── src
    ├── *.cpp
bash 复制代码
cmake_minimum_required(VERSION 3.15)
project(test)
set(CMAKE_CXX_STANDARD 11)
​
# 指定项目所需源文件
file(GLOB_RECURSE SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
​
# 包含头文件
include_directories(${PROJECT_SOURCE_DIR}/include)
​
# 指定可执行程序输出路径
set(EXECUTABLE_OUTPUT_PATH ${HOME}/***/***) 
​
# 命名程序,添加其使用的源文件
add_excutable(test ${SRC})

CMake制作动态库和静态库

动态库 静态库
Linux libname.so libname.a
Windows name.dll name.lib

一、制作命令:

scss 复制代码
# 制作静态库:
add_library(静态库名称 STATIC 源文件...)
​
# 制作动态库:
add_library(静态库名称 SHARED 源文件...)

制作静态库CMakeLists.txt文件的编写逻辑,与制作源文件相同,只需将add_excutable()命令替换成add_library()命令既可。

在Linux中,库名字分为三部分:lib+库名字+库后缀 ,此处只需要指定出库的名字就可以了,另外两部分在生成该文件的时候会自动填充;在Windows中虽然库名和Linux格式不同,但也只需指定出名字即可。

二、指定生成库文件的路径:

bash 复制代码
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
# 不指定路径则生成到当前构建目录中

三、完整CMakeLists.txt文件

scss 复制代码
cmake_minimum_required(VERSION 3.15)
project(mylib)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
​
# 设置动态库/静态库生成路径
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
​
# 生成动态库
add_library(calc SHARED ${SRC_LIST})
# 生成静态库
add_library(calc STATIC ${SRC_LIST})
​

在程序中链接动态库和静态库


将目标(可执行文件或库)链接静态库或动态库,链接库之前必须生成可执行文件。

vbnet 复制代码
target_link_libraries(
    <target>  
    <PRIVATE|PUBLIC|INTERFACE> <item>...                                                    [<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
    
# target:链接库的目标,目标可以是可执行文件、源文件或库。
# PRIVATE|PUBLIC|INTERFACE:库访问权限,用于控制库的可见性和传播性。
# item:使用的库名称
  • 库链接权限参数说明:
关键字 作用范围 用途
PRIVATE 当前目标内部使用,依赖目标不继承 当库或选项仅在当前目标内部使用时使用
PUBLIC 当前目标和所有依赖目标可见和使用 当库或选项需要传播到所有依赖目标时使用
INTERFACE 当前目标可使用和传递,但不包括实现细节 当库或选项仅为传播用途时使用

链接多个库用例:

scss 复制代码
# 生成静态/动态库
add_library(mylibrary STATIC/SHARED mylibrary.cpp)
# 设置链接库目录
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/lib)
# 生成可执行文件
add_executable(my_executable main.cpp)
# 链接动态库到可执行文件
target_link_libraries(my_executable PRIVATE mylibrary)

指定链接库文件的目录:

bash 复制代码
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/lib)

嵌套CMake分层构建项目

为树状项目在CMake中建立父子关系:

ini 复制代码
add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
    # source_dir:指定CMakeLists.txt源文件及代码路径,即指定子目录
    # binary_dir:指定输出文件路径,可忽略
    # EXCLUDE_FROM_ALL:指定source_dir子目录是否被排除默认构建之外,不填写该参数则子目录参与构建
相关推荐
凌云行者2 天前
OpenGL入门009——漫反射在片段着色器中的应用
c++·cmake·openg
凌云行者2 天前
OpenGL入门008——环境光在片段着色器中的应用
c++·cmake·opengl
Coding-Prince12 天前
cmake报错The link interface of target “gRPC::grpc“ contains: OpenSSL::SSL 解决
ssl·cmake
凌云行者16 天前
OpenGL入门005——使用Shader类管理着色器
c++·cmake·opengl
凌云行者16 天前
OpenGL入门006——着色器在纹理混合中的应用
c++·cmake·opengl
赵民勇18 天前
cmake中execute_process详解
cmake
凌云行者19 天前
OpenGL入门004——使用EBO绘制矩形
c++·cmake·opengl
长弓聊编程21 天前
应该怎么理解CMakeLists.txt中一些指令的INTERFACE、PUBLIC和PRIVATE参数
cmake
凌云行者21 天前
OpenGL入门003——使用Factory设计模式简化渲染流程
c++·cmake·opengl
凌云行者22 天前
OpenGL入门002——顶点着色器和片段着色器
c++·cmake·opengl