Cmake使用
- 注释使用#
- 多行注释使用#[[注释内容]]
常用内容
cmake_minimum_required(VERSION 3.0)#设置最低版本
project(CALC) #设置项目名称
#[[add_executable(可执行程序名 源文件名称)]]
add_executable(app add.c div.c main.c mult.c sub.c) #定义工程生成的可执行文件
#指定可执行程序的输出的路径
set(HOME /home/robin/Linux/Sort)
set(EXECUTABLE_OUTPUT_PATH ${HOME}/bin)
# 设置c++标准
#增加-std=c++11
set(CMAKE_CXX_STANDARD 11)
#搜索源文件,存储到变量中
#法一
#[aux_source_directory(路径 变量名)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src SRC_LIST)
# [搭配使用:add_executable(app ${SRC_LIST})
#法二
file(GLOB MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
file(GLOB_RECURSE MAIN_HEAD ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h)
#GLOB搜索 GLOB_RECURSE递归搜索
#设置头文件路径
include_directories(headpath)
- 使用cmake执行CMakeLists.txt 中的内容,通常在CMakeLists.txt的同级目录下新建build文件夹,执行cmake …,这样可以将cmake生成的中间文件放在build文件夹中。
举例子
目录结构:
$ tree
.
├── build
├── CMakeLists.txt
├── include
│ └── head.h
└── src
├── add.cpp
├── div.cpp
├── main.cpp
├── mult.cpp
└── sub.cpp
3 directories, 7 files
cmake_minimum_required(VERSION 3.0)
project(CALC)
set(CMAKE_CXX_STANDARD 11)
set(HOME /home/robin/Linux/calc)
set(EXECUTABLE_OUTPUT_PATH ${HOME}/bin/)
# PROJECT_SOURCE_DIR是cmake后面跟的路径
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
add_executable(app ${SRC_LIST})
定义变量
- 通过set设置变量
# SET 指令的语法是:
# [] 中的参数为可选项, 如不需要可以不写
SET(变量名 [变量值] [CACHE TYPE DOCSTRING [FORCE]])
- 变量值中涉及多个文件可以通过空格或;分割
set(SRC_LIST add.c;div.c;main.c;mult.c;sub.c)
add_executable(app ${SRC_LIST})
# 当源文件不在同一个目录时,使用set可以进行拼接
set(变量名1 ${变量名1} ${变量名2} ...)
file(GLOB SRC_1 ${PROJECT_SOURCE_DIR}/src1/*.cpp)
file(GLOB SRC_2 ${PROJECT_SOURCE_DIR}/src2/*.cpp)
# 追加(拼接)
set(SRC_1 ${SRC_1} ${SRC_2} ${TEMP})
#当源文件中有不需要的,通过list删除
file(GLOB SRC_1 ${PROJECT_SOURCE_DIR}/*.cpp)
# 移除前日志
message(STATUS "message: ${SRC_1}")
# 移除 main.cpp,注意file搜索的时候是带绝对路径的,因此删除的时候也要带上绝对路径
list(REMOVE_ITEM SRC_1 ${PROJECT_SOURCE_DIR}/main.cpp)
# 移除后日志
message(STATUS "message: ${SRC_1}")
制作动态库和静态库
有些时候我们编写的源代码并不需要将他们编译生成可执行程序,而是生成一些静态库或动态库提供给第三方使用。
# 制作静态库
add_library(库名称 STATIC 源文件1 源文件2 ...)
# 制作动态库
add_library(库名称 SHARED 源文件1 [源文件2] ...)
#设置生成的库的路径
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
使用库
#静态库
# 包含静态库路径
link_directories(${PROJECT_SOURCE_DIR}/lib)
# 链接静态库
link_libraries(calc)
#动态库,动态库具有链接性 A链接了B,C,D链接了A时使用
#指定动态库位置
link_directories(${PROJECT_SOURCE_DIR}/lib)
target_link_libraries(A B C)
target_link_libraries(D A)
- 静态库会在生成可执行程序的链接阶段被打包到可执行程序中,所以可执行程序启动,静态库就被加载到内存中了。
- 动态库在生成可执行程序的链接阶段不会被打包到可执行程序中,当可执行程序被启动并且调用了动态库中的函数的时候,动态库才会被加载到内存
因此,在cmake
中指定要链接的动态库的时候,应该将命令写到生成了可执行文件之后
常使用的宏
宏 | 功能 |
---|---|
PROJECT_SOURCE_DIR | 使用cmake命令后紧跟的目录,一般是工程的根目录 |
PROJECT_BINARY_DIR | 执行cmake命令的目录 |
CMAKE_CURRENT_SOURCE_DIR | 当前处理的CMakeLists.txt所在的路径 |
CMAKE_CURRENT_BINARY_DIR | target 编译目录 |
EXECUTABLE_OUTPUT_PATH | 重新定义目标二进制可执行文件的存放位置 |
LIBRARY_OUTPUT_PATH | 重新定义目标链接库文件的存放位置 |
PROJECT_NAME | 返回通过PROJECT指令定义的项目名称 |
CMAKE_BINARY_DIR | 项目实际构建路径,假设在build 目录进行的构建,那么得到的就是这个目录的路径 |
嵌套Cmake
如果项目很大,或者项目中有很多的源码目录,在通过CMake管理项目的时候如果只使用一个CMakeLists.txt
,那么这个文件相对会比较复杂,有一种化繁为简的方式就是给每个源码目录都添加一个CMakeLists.txt
文件(头文件目录不需要),这样每个文件都不会太复杂,而且更灵活,更容易维护。
$ tree
.
├── build
├── calc
│ ├── add.cpp
│ ├── CMakeLists.txt
│ ├── div.cpp
│ ├── mult.cpp
│ └── sub.cpp
├── CMakeLists.txt
├── include
│ ├── calc.h
│ └── sort.h
├── sort
│ ├── CMakeLists.txt
│ ├── insert.cpp
│ └── select.cpp
├── test1
│ ├── calc.cpp
│ └── CMakeLists.txt
└── test2
├── CMakeLists.txt
└── sort.cpp
-
include 目录
:头文件目录 -
calc 目录
:目录中的四个源文件对应的加、减、乘、除算法
- 对应的头文件是
include
中的calc.h
- 对应的头文件是
-
sort 目录
:目录中的两个源文件对应的是插入排序和选择排序算法
- 对应的头文件是
include
中的sort.h
- 对应的头文件是
-
test1 目录
:测试目录,对加、减、乘、除算法进行测试 -
test2 目录
:测试目录,对排序算法进行测试
嵌套Cmake的节点关系
- 根节点
CMakeLists.txt
中的变量全局有效 - 父节点
CMakeLists.txt
中的变量可以在子节点中使用 - 子节点
CMakeLists.txt
中的变量只能在当前节点中使用
# 为cmake添加一个子节点cmake
add_subdirectory(子目录 [binary_dir] [EXCLUDE_FROM_ALL])
binary_dir
:指定了输出文件的路径,一般不需要指定,忽略即可。EXCLUDE_FROM_ALL
:在子路径下的目标默认不会被包含到父路径的ALL
目标里,并且也会被排除在IDE工程文件之外。用户必须显式构建在子路径下的目标。
根目录
cmake_minimum_required(VERSION 3.0)
project(test)
# 定义变量
# 静态库生成的路径
set(LIB_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib)
# 测试程序生成的路径
set(EXEC_PATH ${CMAKE_CURRENT_SOURCE_DIR}/bin)
# 头文件目录
set(HEAD_PATH ${CMAKE_CURRENT_SOURCE_DIR}/include)
# 静态库的名字
set(CALC_LIB calc)
set(SORT_LIB sort)
# 可执行程序的名字
set(APP_NAME_1 test1)
set(APP_NAME_2 test2)
# 添加子目录
add_subdirectory(calc)
add_subdirectory(sort)
add_subdirectory(test1)
calc目录
cmake_minimum_required(VERSION 3.0)
project(CALCLIB)
aux_source_directory(./ SRC)
include_directories(${HEAD_PATH})
set(LIBRARY_OUTPUT_PATH ${LIB_PATH})
add_library(${CALC_LIB} STATIC ${SRC})
- 第3行
aux_source_directory
:搜索当前目录(calc目录)下的所有源文件 - 第4行
include_directories
:包含头文件路径,HEAD_PATH
是在根节点文件中定义的 - 第5行
set
:设置库的生成的路径,LIB_PATH
是在根节点文件中定义的 - 第6行
add_library
:生成静态库,静态库名字CALC_LIB
是在根节点文件中定义的
sort 目录
cmake_minimum_required(VERSION 3.0)
project(SORTLIB)
aux_source_directory(./ SRC)
include_directories(${HEAD_PATH})
set(LIBRARY_OUTPUT_PATH ${LIB_PATH})
add_library(${SORT_LIB} SHARED ${SRC})
test1 目录
test1 目录中的 CMakeLists.txt
文件内容如下:
CMAKE
cmake_minimum_required(VERSION 3.0)
project(CALCTEST)
aux_source_directory(./ SRC)
include_directories(${HEAD_PATH})
# include_directories(${HEAD_PATH})
link_libraries(${CALC_LIB})
set(EXECUTABLE_OUTPUT_PATH ${EXEC_PATH})
add_executable(${APP_NAME_1} ${SRC})
- 第4行
include_directories
:指定头文件路径,HEAD_PATH
变量是在根节点文件中定义的 - 第6行
link_libraries
:指定可执行程序要链接的静态库
,CALC_LIB
变量是在根节点文件中定义的 - 第7行
set
:指定可执行程序生成的路径,EXEC_PATH
变量是在根节点文件中定义的 - 第8行
add_executable
:生成可执行程序,APP_NAME_1
变量是在根节点文件中定义的
test2 目录
test2 目录中的 CMakeLists.txt
文件内容如下:
CMAKE
cmake_minimum_required(VERSION 3.0)
project(SORTTEST)
aux_source_directory(./ SRC)
include_directories(${HEAD_PATH})
set(EXECUTABLE_OUTPUT_PATH ${EXEC_PATH})
# link_directories(${LIB_PATH})
add_executable(${APP_NAME_2} ${SRC})
target_link_libraries(${APP_NAME_2} ${SORT_LIB})
- 第四行
include_directories
:包含头文件路径,HEAD_PATH
变量是在根节点文件中定义的 - 第五行
set
:指定可执行程序生成的路径,EXEC_PATH
变量是在根节点文件中定义的 - 第六行
link_directories
:指定可执行程序要链接的动态库的路径,LIB_PATH
变量是在根节点文件中定义的 - 第七行
add_executable
:生成可执行程序,APP_NAME_2
变量是在根节点文件中定义的 - 第八行
target_link_libraries
:指定可执行程序要链接的动态库的名字
在生成可执行程序的时候,动态库不会被打包到可执行程序内部。当可执行程序启动之后动态库也不会被加载到内存,只有可执行程序调用了动态库中的函数的时候,动态库才会被加载到内存中,且多个进程可以共用内存中的同一个动态库,所以动态库又叫共享库。