cmake 学习笔记
1. cmake 文件中的库具体路径是什么? 比如说 ${CURL_INCLUDE_DIR}。 这个其实是 /usr/share/cmake-3.10/Modules/ 下面的 FindXXX.cmake 去寻找相应的具体目录,可以通过命令查看,当前的cmake 支持哪些库的寻找。
ll -th /usr/share/cmake-3.10/Modules/ | grep Find
cmake --help-module FindCURL
上面这条命令可以看到 cmake 关于 curl 具体能找到哪些东西,可以用于 CMakeLists.txt 的编写。
参考: https://blog.csdn.net/haluoluo211/article/details/80559341
2. ninja 安装
sudo apt install ninja-build
3. cmake 简单示例
CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
add_executable(hello-world main.c)
main.c:
#include <stdio.h>
int main(char argc, char *argv[])
{
printf("Hello world\n");
return 0;
}
mkdir build && cd build && cmake .. && make && cd .. && build/hello-world
常用命令:
include_directories(dir):指定包含的头文件目录 dir
add_subdirectory(subdir):包含的子目录 subdir,subdir 中也必须存在 CMakeLists.txt
aux_source_directory(dir var):将 dir 目录下的所有源文件赋值给变量 var
add_library(target src):用变量 src 指定的源文件生成目标文件 target,目标文件为一个库文件
target_link_libraries(target lib):链接 lib 到 target
${PROJECT_NAME} 指的是最近的 project(name) 里面的 name.
参考: https://zhuanlan.zhihu.com/p/87283287
4. cmake 设置当前项目用的环境变量
# Set Environment Variable
# 这个环境变量只对当前cmake工程有效,对外界是无效的。
set(ENV{<variable>} [<value>])
# 找到所有dir目录下的源文件(不会递归遍历子文件夹),源文件是.c文件(也就是makefile中可以生成.o的文件)
aux_source_directory(<dir> <variable>)
参考: https://zhuanlan.zhihu.com/p/93895403
5. ${PROJECT_NAME}
和 ${CMAKE_PROJECT_NAME}
这个需要大写。 小写的话,就认为是自定义的,大写的才能对应到 project() 之类的。
6. target_link_libraries 里面的库,需要先通过 link_directories 指定位置。头文件的包含,需要 include_directories 来指定目录。
7. 简单 CMake 文件,包含对外部库的链接。
#注意:如果工程有依赖库的话,ADD_EXECUTABLE指令要放在LINK_DIRECTORIES指令之后,
# 不然会报错:Linking C executable main
# /usr/bin/ld: cannot find -lhello
# collect2: ld 返回 1
#1) 设置 cmake 的最低版本
cmake_minimum_required(VERSION 3.10)
#2) 设置 project 名称
project(ffmpeg_test)
#3) 设置代码源文件列表
set(SRC_LIST main.cpp)
#4) 增加头文件搜索路径,解决编译期间找不到头文件的问题
#COMMAND: INCLUDE_DIRECTORIES([AFTER|BEFORE] [SYSTEM] dire1 dire2 ...)
#定义:向工程添加多个特定的头文件搜索路径,路径之间用空格分开,
# 如果路径中包含空格,可以使用双引号括起来
# 默认是追加到当前的头文件搜索路径之后,你可以用2种方式控制搜索路径的添加>方式
# 1)CMAKE_INCLUDE_DIRECTORIES_BEFORE 通过SET设置其为on,使用前置模式
# 2)通过AFTER或BEFORE参数,控制追加还是置前
include_directories("/usr/include/x86_64-linux-gnu")
#5) 增加库文件: 解决链接期间找不到调用外部接口的问题
#main.cpp:(.text+0x5): undefined reference to `HelloFunc()'
#collect2: error: ld returned 1 exit status
#6) 增加库文件搜索路径:解决链接期间找不到库文件的问题
#COMMAND: LINK_DIRECTORIES(dir1 dir2 ...)
#定义:添加非标准的共享库搜索路径
#/usr/bin/ld: cannot find -lhello
#collect2: error: ld returned 1 exit status
#好像相对路径会找不到库文件
link_directories("/usr/lib/x86_64-linux-gnu")
#7) 生成二进制文件
add_executable(ffmpeg_test ${SRC_LIST})
#8) 链接库
#COMMAND: TARGET_LINK_LIBRARIES(target library1
# <debug | optimized> library2
# ...)
#定义:用来为target添加需要链接的共享库
#TARGET_LINK_LIBRARIES(${PROJECT_NAME} hello) #链接动态库指令
#TARGET_LINK_LIBRARIES(${PROJECT_NAME} libhello.a) #链接静态库指令
target_link_libraries(${PROJECT_NAME} PRIVATE avutil avcodec avformat swscale)
参考: https://www.cnblogs.com/jacklikedogs/p/3780064.html https://blog.csdn.net/yangbing1113/article/details/8036707 https://cloud.tencent.com/developer/ask/115652 https://blog.csdn.net/laibowon/article/details/103746594 https://www.cnblogs.com/xianghang123/p/3556425.html https://blog.csdn.net/turbock/article/details/90034787 https://blog.csdn.net/arackethis/article/details/43488177
8. so 的库文件,后缀名必须是 .so,才能被 cmake 添加进去,如果是 .so.57 这样的,就添加不进去。
9. cmake 变量 参考: https://cmake.org/cmake/help/latest/manual/cmake-variables.7.html
cmake 命令 参考: https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html cmake 教程 参考: https://cmake.org/cmake/help/v3.16/guide/tutorial/index.html
10. cmake 多层目录如下:
.
├── CMakeLists.txt
├── CMakeLists.txt.bak
├── common.c
├── common.h
├── compile.sh
├── json
│ ├── cJSON.c
│ ├── cJSON.h
│ ├── CJsonObject.cpp
│ ├── CJsonObject.hpp
│ └── CMakeLists.txt
├── main.cpp
├── main.h
├── run.sh
├── sa_in.txt
├── token.c
└── token.h
顶层 CMakeLists.txt :
cmake_minimum_required(VERSION 3.10)
project(sentiment_analysis)
find_package(CURL REQUIRED)
include_directories(${CURL_INCLUDE_DIR})
add_subdirectory(json)
add_executable(${PROJECT_NAME} main.cpp common.c token.c)
target_link_libraries(${PROJECT_NAME} ${CURL_LIBRARY} json_binary)
下层 CMakeLists.txt :
project(json_binary)
add_library(${PROJECT_NAME} cJSON.c CJsonObject.cpp)
target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR})
参考: https://www.cnblogs.com/svenzhang9527/p/10704777.html
11. 设置 C++ 标准为 C++11
set(CMAKE_CXX_STANDARD 11)
参考: https://www.cnblogs.com/svenzhang9527/p/10704718.html https://blog.csdn.net/justidle/article/details/105240822
12.
PROJECT(projectname [CXX] [C] [JAVA])
用于指定工程名字,[]为可选内容,默认表示支持所有语言。注意这条指令还隐式定义了另外两个变量<projectName>_BINARY_DIR
和<projectName>_SOURCE_DIR
。我们这里的project定义为了hello,所以这两个变量就是${hello_BINARY_DIR}
和 ${hello_SOURCE_DIR}
。什么意思呢,可以用message命令打印出来看看他的值。
${hello_BINARY_DIR}
:就是cmake要(构建)编译我们的项目(main.c)的具体路径。这里当然就是build。
${hello_SOURCE_DIR}
:就是我们项目的源码的具体路径,这里当然是项目的根目录。
如果采用的是内部构建的方式,即直接在项目根目录下运行cmake,那这两个变量的值是一样的。不过一般很少使用这两个变量。大家都比较喜欢用 ${CMAKE_SOURCE_DIR}
和 ${CMAKE_BINARY_DIR}
.
参考: https://blog.csdn.net/Tommy_wxie/article/details/77675895
13. 编译报错:
interpreter_builder.cc:(.text+0x394): undefined reference to `dlopen'
interpreter_builder.cc:(.text+0x3a4): undefined reference to `dlsym'
在链接库里面添加 ${CMAKE_DL_LIBS}
即可
target_link_libraries(${PROJECT_NAME} PRIVATE tensorflow-lite ${CMAKE_DL_LIBS})
参考: https://bl.ocks.org/kwk/3595733
14. 编译报错:
thread_pool.cc:(.text+0x228): undefined reference to `pthread_create'
thread_pool.cc:(.text+0x238): undefined reference to `pthread_create'
在链接库里面添加 pthread
即可
target_link_libraries(${PROJECT_NAME} PRIVATE tensorflow-lite pthread ${CMAKE_DL_LIBS})
参考: https://stackoverflow.com/questions/956640/linux-c-error-undefined-reference-to-dlopen
15. opencv
#opencv 4.+需要c++11以上版本的编译器
set(CMAKE_CXX_FLAGS "-std=c++11")
# 引入Opencv包
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
# 注意use_opencv.cpp是我源代码文件名,你需要改成你源代码名
add_executable(use_opencv use_opencv.cpp)
# 链接OpenCV库
target_link_libraries(use_opencv ${OpenCV_LIBS})
参考: https://blog.csdn.net/varyshare/article/details/94162064
16. 当子文件夹需要使用第三方的 静态库 的时候,有三种方法:
1. 直接把静态库编译到子文件夹里面,这样 顶层 cmake 不需要关心这个第三方库。
#link_directories("./lib")
add_library(${PROJECT_NAME} ${ALL_SOURCE_LIST} ./lib/libtensorflow-lite.a)
target_link_libraries(${PROJECT_NAME} PUBLIC ${CMAKE_DL_LIBS})
上面这种方法,不需要 link_directories
来链接第三方库,只需要生成子文件库的时候,指明需要添加进去的库即可,这样第三方库变为子文件库二进制文件的一部分,所以对于上层来说,只要不直接调用第三方库的 API,那么就不需要添加第三方库的库文件夹路径和头文件夹路径。
2. 不把静态库编译到子文件夹里面,顶层 cmake 需要关系这个第三方库。
add_library(${PROJECT_NAME} ${ALL_SOURCE_LIST})
target_link_libraries(${PROJECT_NAME} PRIVATE tensorflow-lite ${CMAKE_DL_LIBS})
link_directories("./sub/lib")
子文件夹下不用把 第三方库编译进去,只需要指明链接的库就行,在顶层 cmake 里面需要指定库所在的路径,否则最后链接库的时候,会找不到这个第三方库。
3. 类似于第一种方法
link_directories("./lib")
add_library(${PROJECT_NAME} ${ALL_SOURCE_LIST})
link_libraries(${PROJECT_NAME} PRIVATE tensorflow-lite ${CMAKE_DL_LIBS})
这样,在编译子文件夹后,立刻链接第三方库,然后生成子文件夹的二进制文件,这样顶层 cmake 也不需要关心第三方库了。
参考: https://segmentfault.com/a/1190000022075547 https://zhuanlan.zhihu.com/p/149191302 https://cmake.org/cmake/help/v3.5/command/link_libraries.html
17. add_definitions
add_definitions
作用是代码中的 #define
的功能。类似于 add_definitions(-DTEST_IT_CMAKE)
这样的写法。
option(TEST_IT_CMAKE "test" ON)
message(${TEST_IT_CMAKE})
if(TEST_IT_CMAKE)
message("itis" ${TEST_IT_CMAKE})
add_definitions(-DTEST_IT_CMAKE)
endif()
参考: https://blog.csdn.net/qq_35699473/article/details/115837708
https://cmake.org/cmake/help/latest/command/add_definitions.html
18. cmake 代码分支编译
代码写法类似
option (USE_MYMATH "Use provided math implementation" ON)
if (USE_MYMATH)
message(STATUS "USE_MYMATH")
elseif (USE_XXX)
message(STATUS "USE_XXX")
endif()
if(${address} STREQUAL "ON")
这种字符串比较经过实际测试,发现不起效果,可能是版本问题,或者其他情况。
具体参考: https://www.cnblogs.com/lidabo/p/13846640.html
https://www.jianshu.com/p/f0f71d36411a
https://blog.csdn.net/maizousidemao/article/details/104103279
https://www.cnblogs.com/rickyk/p/3872568.html
https://blog.csdn.net/Calvin_zhou/article/details/104025714
https://blog.csdn.net/hp_cpp/article/details/110373926
https://blog.csdn.net/lyq308152569/article/details/109388437
19. cmake 调试, 线程,报警信息
add_definitions("-Wall -lpthread -g -rdynamic")
参考: https://www.cnblogs.com/lidabo/p/7359422.html
https://blog.csdn.net/liu0808/article/details/79046022/
20. gcc 报警信息综合
https://blog.csdn.net/XiaoH0_0/article/details/107513936
21. sanitize
target_link_libraries(${PROJECT_NAME} PRIVATE libtengine-lite.so libface.so ${OpenCV_LIBS} -fsanitize=address -fsanitize=leak )
cmake 资料参考:
https://www.cnblogs.com/binbinjx/p/5626916.html https://www.cnblogs.com/is-smiling/p/3269059.html https://www.cnblogs.com/coderfenghc/archive/2012/06/23/2559603.html https://blog.csdn.net/bigdog_1027/article/details/79113342
ninja 资料参考:
https://ninja-build.org/manual.html#_the_literal_phony_literal_rule https://blog.csdn.net/qiuguolu1108/article/details/103842556 https://www.jianshu.com/p/c4d3ba6c6470 https://ninja-build.org/manual.html https://github.com/ninja-build/ninja https://blog.csdn.net/u010164190/article/details/104932437 https://www.cnblogs.com/fuland/p/3641311.html https://www.cnblogs.com/fuland/p/3641314.html https://www.cnblogs.com/fuland/p/3641317.html https://www.cnblogs.com/sandeepin/p/ninja.html