前言
本博客是在 CMake 保姆级教程 文章的学习上进行的总结,把常用CMake命令总结如下。
CMake基本命令
CMake 使用 #
进行行注释,使用 #[[ ]]
形式进行块注释。
# 行注释#[[块注释
]]
以下三个命令是使用CMake构建最简单的一个项目所需要的命令。
cmake_minimum_required
:指定使用的 CMake 的最低版本;
project
:定义工程名称,并可指定工程的版本、工程描述等;
add_executable
:将指定的源码编译生成为一个可执行程序。
cmake_minimum_required(VERSION 3.0)
project(CALC)
add_executable(app add.c div.c main.c mult.c sub.c)
指定使用的 C++ 标准,set(CMAKE_CXX_STANDARD 11)
使用 set
定义变量
在 CMake 中,变量的值始终是字符串类型,且区分大小写。
set(<variable> <value>... [PARENT_SCOPE])
设置一个普通变量,<variable>
表示变量名,<value>...
表示一个或多个参数,例如:
# 将 add.c div.c main.c mult.c sub.c 存储到 SRC 变量中
set(SRC add.c div.c main.c mult.c sub.c)# 取变量 SRC 的值
add_executable(app ${SRC})
使用 ${<variable>}
的形式取变量的值。
指定输出路径
程序的输出可能是一个可执行文件、可能是制作的共享库,可以通过以下命令设置指定的输出路径。
# 将输出路径指定为 /xxx/xxx
set(EXECUTABLE_OUTPUT_PATH /xxx/xxx)
# or
set(RUNTIME_OUTPUT_DIRECTORY /xxx/xxx)
EXECUTABLE_OUTPUT_PATH
和 RUNTIME_OUTPUT_DIRECTORY
是预定义的宏,当设置了 RUNTIME_OUTPUT_DIRECTORY
时,EXECUTABLE_OUTPUT_PATH
就失效了。
搜索文件
在 CMake 中,可以使用 aux_source_directory
命令或者 file
命令 搜索项目中的头文件或源文件。
aux_source_directory(<dir> <variable>)
将 <dir>
目录下的源文件存储到 <variable>
变量中。
file
命令具有很多功能,这里介绍搜索文件的功能。
file(GLOB <variable> [LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS] [<globbing-expressions>...])
file(GLOB_RECURSE <variable> [FOLLOW_SYMLINKS] [LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS] [<globbing-expressions>...])
<globbing-expressions>...
搜索的表达式,可以是指定目录,指定目录下的某种文件,理解为一种正则表达式就好了;GLOB
非递归搜索;GLOB_RECURSE
递归搜索;<variable>
搜索结果保存的变量名
上面时 CMake 文档中给出的命令示例,常用的形式如下:
# 非递归搜索 /xxx/xxx 下的 *.cpp 源文件
file(GLOB SRC /xxx/xxx/*.cpp)# 递归搜索 /xxx/xxx 下的所有 *.h 头文件
file(GLOB_RECURSE HEADER /xxx/xxx/*.h)
包含头文件
指定源文件对应的头文件,include_directories(/xxx/include)
,源文件对应的头文件指定在 /xxx/include
目录下。
制作动态库和静态库
以如下示例进行实验。
.
├── CMakeLists.txt
├── build
├── include
│ └── head.h
├── main.cpp
└── src├── add.cpp├── divi.cpp├── mul.cpp└── sub.cpp
制作静态库
CMakeLists.txt
内容如下
cmake_minimum_required(VERSION 3.0)
project(CALC)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
# 制作静态库的命令
add_library(calc STATIC ${SRC_LIST})
步骤:
- 首先切换到项目更目录下,即顶层 CMakeLists.txt 文件所在的目录;
cd build
切换到 build 目录下,build 目录用来存放 cmake 生成的 makefile 以及其他一些文件;- 执行
cmake ..
命令,即根据 CMakeLists.txt 文件生成 makefile 文件; - 依然保持在 build 目录下,执行 make 命令,即运行 makefile 文件,编译项目,生成静态库,默认生成的静态库在 build 目录下。若想要指定静态库的输出路径,可以使用
set(LIBRARY_OUTPUT_PATH /xxx/xxx)
命令设置输出路径。LIBRARY_OUTPUT_PATH
宏用来指定构建的共享库的存放路径。
Linux 下生成的静态库默认是不具有执行权限的,如下所示。因此在指定静态库生成的路径时,不能使用 EXECUTABLE_OUTPUT_PATH
和 RUNTIME_OUTPUT_DIRECTORY
宏。
$ ls -l libcalc.a
-rw-r--r-- 1 root root 5254 Dec 3 18:04 libcalc.a
制作动态库
CMakeLists.txt
内容如下:
cmake_minimum_required(VERSION 3.0)
project(CALC)
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})
和制作静态库的步骤相同。
同时生成动态库和静态库
当需要同时生成动态库和静态库时,不能如下所示简单的将上述的命令拼在一起,这样会导致静态库和动态库名字相同的冲突。
cmake_minimum_required(VERSION 3.0)
project(calc)
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(${PROJECT_NAME} SHARED ${SRC_LIST})
# 生成静态库
add_library(${PROJECT_NAME} STATIC ${SRC_LIST})# output:
# CMake Error at CMakeLists.txt:10 (add_library):
# add_library cannot create target "calc" because another target with the
# same name already exists. The existing target is a shared library created
# in source directory "/workspace/cppCode/demo03". See documentation for
# policy CMP0002 for more details.
一种解决方案是,使用 set_target_properties
命令修改最终生成的静态库和动态库的名字,如下所示。
cmake_minimum_required(VERSION 3.0)
project(calc)
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(${PROJECT_NAME}_shared SHARED ${SRC_LIST})
# 生成静态库
add_library(${PROJECT_NAME}_static STATIC ${SRC_LIST})# 修改生成的动态库和静态库的名称
set_target_properties(${PROJECT_NAME}_shared PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
set_target_properties(${PROJECT_NAME}_static PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
set_target_properties(target1 target2 ...PROPERTIES prop1 value1prop2 value2 ...)
将目标名称 target1
的 prop1
属性设置为 value1
;将目标名称 target2
的 prop2
属性设置为 value2
;
链接静态库和动态库
以上述制作的静态库和动态库为例,程序代码结构如下所示:
.
├── CMakeLists.txt
├── build
├── include
│ └── head.h
├── lib
│ ├── libcalc.a
│ └── libcalc.so
├── main.cpp
链接静态库
链接静态库需要的命令如下:
# 指定静态库的路径,<lib path> 表示静态库的路径
link_directories(<lib path>)# 链接静态库的命令,<static lib> 表示静态库的名称,可以是全名 libxxx.a,或掐头去尾 xxx
link_libraries(<static lib> [<static lib>...])
CMakeLists.txt 内容如下,编译通过。
cmake_minimum_required(VERSION 3.0)
project(calc)
include_directories(${PROJECT_SOURCE_DIR}/include)
# 指定静态库的路径
link_directories(${PROJECT_SOURCE_DIR}/lib)
# 链接静态库
link_libraries(calc)
add_executable(main main.cpp)
链接动态库
链接动态库使用 target_link_libraries
命令指定动态库,和链接静态库相似,直接看 CMakeLists.txt 内容:
cmake_minimum_required(VERSION 3.0)
project(calc)
include_directories(${PROJECT_SOURCE_DIR}/include)
# 指定动态库的路径
link_directories(${PROJECT_SOURCE_DIR}/lib)add_executable(main main.cpp)# 链接动态库
target_link_libraries(main calc)
需要注意的一个点是,链接动态库的命令 target_link_libraries
需要在 add_executable
命令后面,理由很简单:如上示例所示,add_executable(main main.cpp)
只有“生成”了 main 可执行文件之后,才能去加载动态库。
CMake构建项目案例(待补充…)
参考链接:
https://cmake.org/cmake/help/latest/
https://subingwen.cn/cmake/CMake-primer/
https://subingwen.cn/cmake/CMake-advanced/