cmake用法
# 语法
- 官方文档:https://cmake.org/cmake/help/v3.14/ (opens new window)
- 设置和使用变量 https://cloud.tencent.com/developer/ask/121477
set(MyString "Some Text")
set(MyStringWithVar "Some other Text: ${MyString}")
2
从cmake命令行传入变量 -D
CMakeLists.txt:
set(aa 123)
MESSAGE(aa= ${aa})
MESSAGE(bb= ${bb})
2
3
执行cmake
mkdir -p build
cd build
cmake .. -Dbb=456
2
3
输出:
aa=123
bb=456
2
# 非常好用的CMakeLists.txt模板
假设项目文件夹名为cmake_demo,其包含了test1、test2两个(即两个子文件夹)。
首先在根目录下创建CMakeLists.txt:
CMAKE_MINIMUM_REQUIRED (VERSION 3.0)
cmake_policy(VERSION 3.0)
# 创建项目,相当于vs中创建了cmake_demo.sln
PROJECT (cmake_demo)
# 添加C++版本支持
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# * CMAKE_SOURCE_DIR 是最上层CMakeLists.txt所在的文件夹 (注意:子目录中用了project()后,该变量就是porject所在的文件夹了!!!)
# * CMAKE_CURRENT_SOURCE_DIR 当前CMakeLists.txt所在的文件夹
# * CMAKE_CURRENT_BINARY_DIR 是执行cmake时会拷贝当前CMakeLists.txt到build里对应的文件夹
# * CMAKE_BINARY_DIR 就是执行cmake的文件夹,一般是build文件夹
# 假设CMakeLists.txt位于项目根目录`rootdir`,设置lib的生成目录为`rootdir/lib`,
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)
# 设置可执行文件的生成目录为build/../bin
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
# 设置编译flag,debug和release, 不指定CMAKE_BUILD_TYPE时,默认release版本
# 编译debug版本: cmake -D CMAKE_BUILD_TYPE=debug .. 或者在CMakeLists设置set(CMAKE_BUILD_TYPE "debug")
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wformat=0 -Wno-sign-compare -Wno-unused-variable" )
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -g -O0 -DDEBUG" )
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -O2 -DNDEBUG" )
# (根据需要)添加宏定义 "_GNU_SOURCE" 和 "_DEFAULT_SOURCE"
add_definitions("-D_GNU_SOURCE -D_DEFAULT_SOURCE")
# 添加git版本相关的宏定义
# 程序中打印: printf("%s\n", "version: git_tag=" GIT_TAG ", commit_it=" COMMIT_ID);
execute_process(COMMAND git describe --tag --always --dirty
OUTPUT_VARIABLE GIT_TAG
OUTPUT_STRIP_TRAILING_WHITESPACE
)
message(git_tag = ${GIT_TAG})
execute_process(COMMAND git rev-parse HEAD
OUTPUT_VARIABLE COMMIT_ID
OUTPUT_STRIP_TRAILING_WHITESPACE
)
message(commit_id = ${COMMIT_ID})
add_definitions(-DGIT_TAG="${GIT_TAG}")
add_definitions(-DCOMMIT_ID="${COMMIT_ID}")
# 添加头文件搜索路径(.h) 当前文件夹和include
include_directories(. include)
# 添加库文件搜索路径(.lib, .a, .so)
link_directories(lib)
# 创建可执行文件some_test
add_executable(some_test some_test.cpp)
# 链接libdl.so 和 libm.so
target_link_libraries(some_test dl m)
#添加test1和test2两个子文件夹,windows下相当于vs中的sln添加了两个project。
add_subdirectory(test1)
add_subdirectory(test2)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
test1文件夹下的CMakeLists.txt, 添加一个可执行文件test
# 将该目录下的所有源文件名加入到变量DIR_SRCS中。这是偷懒的做法,最好把具体文件列出来
aux_source_directory(. DIR_SRCS)
# 将上面得到的${DIR_SRCS}这些源文件作为source,编译出可执行文件test或者test.exe
add_executable(test1 ${DIR_SRCS})
# 如果需要链接外部的动态库文件,则在 add_executable 后面加,比如test1要链接到libtrace.so:
target_link_libraries(test1 trace)
2
3
4
5
6
7
8
test2文件夹下的CMakeLists.txt, 添加一个lib
# 子项目test2也可以用cmake中的project(test2) 最好不要用。
# 创建LIB_SOURCE_FILES变量,存储一些文件名
SET(LIB_SOURCE_FILES aaa.cpp bbb.cpp ccc.cpp)
# 生成库,地位等同于 add_executable(). SHARED表示生成动态库,linux下会生成libtest2.so, windows应该会生成test2.dll
add_library(test2 SHARED ${LIB_SOURCE_FILES})
# 复制生成的so文件到lib文件夹,路径可能有问题需要调整
IF (WIN32)
MESSAGE(STATUS "###########################OS is windows###########################")
ELSEIF (UNIX)
MESSAGE(STATUS "###########################OS is UNIX-like OS's.###########################")
FILE(COPY libtest2.so DESTINATION lib)
ENDIF ()
2
3
4
5
6
7
8
9
10
11
12
13
14
这样在windows下编译出的vs2017工程为cmake_demo.sln,它包含了test1.vcxproj、test2.vcxproj两个project。
在linux下会生成Makefile, 可以用make编译。
# 先在build文件夹中生成项目文件, 然后执行编译
先创建build文件夹,用cmake在build文件夹下生成项目文件,再编译
cd cmake_demo
mkdir build
cd build
cmake ..
cmake --build .
2
3
4
5
对于linux,最后一句 cmake --build .
等同于 make
对于windows,最后一句相当于是调用visual studio编译。
windows下生成工程时指定vs版本:
cmake .. -G "Visual Studio 15 2017 Win64"
cmake .. -G "Visual Studio 15 2017" -A x64
cmake .. -G "Visual Studio 16 2019 Win32"
cmake --build . --config Debug
2
3
4
5
- -G是generator, -A是generator支持的platform
- 参考cmake官方文档 https://cmake.org/cmake/help/v3.18/generator/Visual%20Studio%2015%202017.html
- vs2017对应的-A可以加 Win32 x64 ARM ARM64
# cmake中常用的变量
https://gitlab.kitware.com/cmake/community/-/wikis/doc/cmake/Useful-Variables (opens new window)
- CMAKE_SOURCE_DIR 是最上层CMakeLists.txt所在的文件夹 (用了project()可能是porject所在的文件夹了)
- CMAKE_CURRENT_SOURCE_DIR 当前CMakeLists.txt所在的文件夹
- CMAKE_BINARY_DIR 就是执行cmake的文件夹,一般是build文件夹
- CMAKE_CURRENT_BINARY_DIR 是执行cmake时会拷贝当前CMakeLists.txt到build里对应的文件夹
# 上面添加了git版本相关的宏定义,程序中用法如下:
main.cpp:
#include<stdio.h>
#ifndef GIT_TAG
#define GIT_TAG "no_git_tag"
#endif
#ifndef COMMIT_ID
#define COMMIT_ID "no_commit_id"
#endif
int main() {
// 下面写法的好处是 strings a.out | grep version 即可得到commit_id
printf("%s\n", "version: git_tag=" GIT_TAG ", commit_it=" COMMIT_ID);
}
2
3
4
5
6
7
8
9
10
11
12
13
# 指定编译器路径
cmake -DCMAKE_CXX_COMPILER=/path/to/your/g++
# 设置build type
命令行中指定build type: cmake -DCMAKE_BUILD_TYPE=Debug ..
CMakeLists.txt中指定build type
set(CMAKE_BUILD_TYPE "Debug")
CMakeLists.txt中配置不同的编译选项
# 设置不同build type对应的编译选项
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -pthread -g " )
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -pthread -DNDEBUG " )
set(CMAKE_C_FLAGS_DEBUG "-O0 -pthread " )
set(CMAKE_C_FLAGS_RELEASE "-O2 -pthread -DNDEBUG " )
# 如果不用build type, 则不要对应的type
set(CMAKE_CXX_FLAGS "-O2 -pthread" )
set(CMAKE_C_FLAGS_DEBUG "-O2 -pthread" )
2
3
4
5
6
7
8
9
10
# find_package用法
https://github.com/BrightXiaoHan/CMakeTutorial/tree/master/FindPackage
通过Find<LibaryName>
.cmake 模块,找到相关的路径。
每一个模块都会定义以下几个变量:
<LibaryName>
_FOUND<LibaryName>
_INCLUDE_DIRS or<LibaryName>
_INCLUDES<LibaryName>
_LIBRARYS or<LibaryName>
_LIBRARIES
你可以通过<LibaryName>
_FOUND 来判断模块是否被找到,如果没有找到,可给出提醒或者中止编译。
如果<LibaryName>
_FOUND 为真,则加入头文件目录,链接库文件。
find_package(CURL)
add_executable(curltest curltest.cc)
if(CURL_FOUND)
include_directories(clib PRIVATE ${CURL_INCLUDE_DIRS})
target_link_libraries(curltest ${CURL_LIBRARYS})
else(CURL_FOUND)
message(FATAL_ERROR ”CURL library not found”)
endif(CURL_FOUND)
2
3
4
5
6
7
8
# windows生成动态链接库时导出接口
一种方法是自动导出所有的函数
# 可选在windows上生成dll时导出所有的函数,这样不用写def之类的了。 set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) # 添加动态链接库文件 nanomsg.dll, nanomsg.so target_link_libraries(test nanomsg)
1
2
3
4
5另一种是利用cmake的函数GENERATE_EXPORT_HEADER自动生成辅助头文件
其他就是不用cmake,直接手写__declspec(dllexport)
# 添加boost库
set(BOOST_ROOT /usr/local/src/boost_1_76_0)
find_package(Boost REQUIRED)
include_directories(${Boost_INCLUDE_DIRS})
MESSAGE( STATUS "Boost_INCLUDE_DIRS = ${Boost_INCLUDE_DIRS}.")
2
3
4