Cmake 语法与实战入门
语法
1指定cmake最小版本
cmake_minimum_required(VERSION 3.4.1)
2设置项目名称
project(demo)
它会引入两个变量 demo_BINARY_DIR 和 demo_SOURCE_DIR,
同时,cmake 自动定义了两个等价的变量 PROJECT_BINARY_DIR 和 PROJECT_SOURCE_DIR。
3设置编译类型
add_executable(demo demo.cpp) # 生成可执行文件 add_library(common STATIC util.cpp) # 生成静态库 add_library(common SHARED util.cpp) # 生成动态库或共享库
add_library 默认生成是静态库,通过以上命令生成文件名字,
在 Linux 下是:demo libcommon.a libcommon.so
在 Windows 下是:demo.exe common.lib common.dll
4指定编译包含的源文件
4- 1明确指出包含哪些源文件
add_library(demo demo.cpp test.cpp util.cpp)
4-2搜索所有的cpp文件
aux_source_directory(dir VAR) 发现一个目录(dir)下所有的源代码文件并将列表存储在一个变量(VAR)中。
aux_source_directory(. SRC_LIST) # 搜索当前目录下的所有.cpp文件 add_library(demo ${SRC_LIST})
4-3自定义搜索规则
#1file模式 搜索同目录+protocol目录所有的cpp文件 file(GLOB SRC_LIST "*.cpp" "protocol/*.cpp") add_library(demo ${SRC_LIST}) # 2file模式 分开目录搜索添加 file(GLOB SRC_LIST "*.cpp")#单独搜索本目录所有cpp 存放变量SRC_LIST file(GLOB SRC_PROTOCOL_LIST "protocol/*.cpp")#单独搜索protocol目录所有cpp 存放变量SRC_PROTOCOL_LIST add_library(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST}) # 3 aux模式 aux_source_directory(. SRC_LIST)##单独搜索本目录所有cpp 存放变量SRC_LIST aux_source_directory(protocol SRC_PROTOCOL_LIST)#单独搜索protocol目录所有cpp 存放变量SRC_PROTOCOL_LIST add_library(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST})
5-1设置包含的目录
如果src/math.cpp和include/math.h不在同一个文件夹,math.cpp中引用math.h头文件
模式1 使用相对路径 include/math.h
模式2 使用直接路径math.h 但是camke要指定包含include文件夹
include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include )
5-2添加一个子目录并构建该子目录
add_subdirectory (source_dir [binary_dir] [EXCLUDE_FROM_ALL])
source_dir
必选参数。该参数指定一个子目录,子目录下应该包含CMakeLists.txt
文件和代码文件。子目录可以是相对路径也可以是绝对路径,如果是相对路径,则是相对当前目录的一个相对路径。-
binary_dir
可选参数。该参数指定一个目录,用于存放输出文件。可以是相对路径也可以是绝对路径,如果是相对路径,则是相对当前输出目录的一个相对路径。如果该参数没有指定,则默认的输出目录使用source_dir
。 -
EXCLUDE_FROM_ALL
可选参数。当指定了该参数,则子目录下的目标不会被父目录下的目标文件包含进去,父目录的CMakeLists.txt
不会构建子目录的目标文件,必须在子目录下显式去构建。例外情况:当父目录的目标依赖于子目录的目标,则子目录的目标仍然会被构建出来以满足依赖关系(例如使用了target_link_libraries)
。 - 例子

6-1查找指定的库文件
find_library(VAR name path)查找到指定的预编译库,并将它的路径存储在变量中。
默认的搜索路径为 cmake 包含的系统库,因此如果是 NDK 的公共库只需要指定库的name 即可(不需path)。
find_library(log-lib,log)
类似的命令还有 find_file()、find_path()、find_program()、find_package()。
6-2设置target需要链接的库
target_link_libraries( # 目标库 demo # 目标库需要链接的库 ${log-lib} )
在 Windows 下,系统会根据链接库目录,搜索xxx.lib 文件,Linux 下会搜索 xxx.so 或者 xxx.a 文件,如果都存在会优先链接动态库(so 后缀)。
6-2-1指定链接动态库或静态库
target_link_libraries(demo libface.a) # 链接libface.a target_link_libraries(demo libface.so) # 链接libface.so
2. 指定全路径
target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.a) target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.so)
3. 指定链接多个库
target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.a boost_system.a boost_thread pthread)
7设置变量
set 直接设置变量的值
set(SRC_LIST main.cpp test.cpp) add_executable(demo ${SRC_LIST})
set 追加设置变量的值
set(SRC_LIST main.cpp) set(SRC_LIST ${SRC_LIST} test.cpp) add_executable(demo ${SRC_LIST})
常用变量
PROJECT_SOURCE_DIR:工程的根目录
PROJECT_BINARY_DIR:运行cmake命令的目录,通常为${PROJECT_SOURCE_DIR}/build
PROJECT_NAME:返回通过 project 命令定义的项目名称
CMAKE_CURRENT_SOURCE_DIR:当前处理的 CMakeLists.txt 所在的路径
CMAKE_CURRENT_BINARY_DIR:target 编译目录
CMAKE_CURRENT_LIST_DIR:CMakeLists.txt 的完整路径
EXECUTABLE_OUTPUT_PATH:重新定义目标二进制可执行文件的存放位置
LIBRARY_OUTPUT_PATH:重新定义目标链接库文件的存放位置
测试例程
例子1 文件包含模式-非库引用
CMakeLists.txt
# 父目录下的CMakeLists.txt cmake_minimum_required(VERSION 3.10.2) project(test) #1手动设置指定文件 set(Current_LIST main.cpp ) set(SRC_LIST src/API_Cout.cpp) #不需要指定头文件 #2自动搜所文件目录 #aux_source_directory(. Current_LIST) # 搜索当前.目录下的所有.cpp文件 #aux_source_directory(./src SRC_LIST) # 搜索src目录下的所有.cpp文件 add_executable(demo ${Current_LIST} ${SRC_LIST})
main.cpp
#ifndef MAIN_CPP #define MAIN_CPP #include "src/API_Cout.h" #include <iostream> int main(int argc, char** argv) { std::cout << "In main..." << std::endl; test("hello, world!"); return 0; } #endif MAIN_CPP
API_Cout.h
#ifndef COUT_H #define COUT_H #include <string> void test(std::string str); #endif
API_Cout.cpp
#ifndef COUT_CPP #define COUT_CPP #include "API_Cout.h" #include <iostream> void test(std::string str) { std::cout << str << std::endl; } #endif
编译运行结果
直接命令行
cd build camke .. make
vscode-View-terminal
例子2 文件包含模式-打包库引用
同例子1样的代码
打包成库参与引用
src多了一个cmakelist.txt
注意事项
1所有的cmaklist中涉及到的变量不能同名
2 代码用的是相对路径引用
#include "src/API_Cout.h"
例子3 文件包含模式-打包库引用
正常模式1 使用了相对路径引用,不需要include_directories包含引用文件路径
正常模式2 不使用了相对路径引用,需要include_directories包含引用文件路径
主函数采用非相对引用
#include "API_Cout.h" //关键地方 不是相对引用 src/API_Cout.h
cmake需要包含文件路劲
include_directories(src)#关键 不是相对引用 需要单独制定包含
include_directories命令使得不使用相对路径也可以包含引用文件。
缺点,但是不建议这么干,代码逻辑混乱
优点,可能一些复杂的工程借助于此,编辑样例的时候省去了一堆相对路径查找和包含。
例子4 -1多项目,各自工程独立文件夹编译
CMakeLists.txt
# 父目录下的CMakeLists.txt cmake_minimum_required(VERSION 3.10.2) project(test) add_subdirectory("v1_Test") add_subdirectory("v2_Test") add_subdirectory("v3_Test")
CMakeLists.txt
#1手动设置指定文件 set(Current_LIST main.cpp ) set(SRC_LIST src/API_Cout.cpp) #不需要指定头文件 #2自动搜所文件目录 #aux_source_directory(. Current_LIST) # 搜索当前.目录下的所有.cpp文件 #aux_source_directory(./src SRC_LIST) # 搜索src目录下的所有.cpp文件 add_executable(demo1 ${Current_LIST} ${SRC_LIST})
#1手动设置指定文件 set(Current_LIST main.cpp ) set(SRC_LIST src/API_Cout.cpp) #不需要指定头文件 #2自动搜所文件目录 #aux_source_directory(. Current_LIST) # 搜索当前.目录下的所有.cpp文件 #aux_source_directory(./src SRC_LIST) # 搜索src目录下的所有.cpp文件 add_executable(demo2 ${Current_LIST} ${SRC_LIST})
#1手动设置指定文件 set(Current_LIST main.cpp ) set(SRC_LIST src/API_Cout.cpp) #不需要指定头文件 #2自动搜所文件目录 #aux_source_directory(. Current_LIST) # 搜索当前.目录下的所有.cpp文件 #aux_source_directory(./src SRC_LIST) # 搜索src目录下的所有.cpp文件 add_executable(demo3 ${Current_LIST} ${SRC_LIST})
编译
cd build camke .. make
例子4 -2多项目,各自工程使用共同文件夹编译
CMakeLists.txt
cmake_minimum_required(VERSION 2.6) project(tcp) #自动连接模式 #1将文件夹下全部文件链接到 src #aux_source_directory(. src) #将src里面的所有文件链接用于生成可执行文件 #add_executable(project1 ${src}) #手动添加模式 #1测试-生成可执行文件main add_executable(main src/main.cpp) add_executable(client src/client.cpp) add_executable(Server src/Server.cpp) add_executable(http_client src/http_client.cpp) #设置可执行文件的输出目录 SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
src源码地址
可执行文件夹