CMake原理与快速入门
CMake是一个跨平台的构建(build)工具,完成代码编译、链接、打包过程。在开发AI应用平台时,由于开发的平台是在边缘设备运行的,而边缘设备的算力不高,所以对平台的效率要求比较高,都是优先使用C++开发的。
在C++开发中,CMake是不可或缺的,与CMake类似的工具有微软的MSBuild(在Visual Studio中使用)、安卓开发的Gradle(Android Studio)。
上图是c/cpp的编译流程:编译cpp时是以单个文件为单位,每个cpp文件会得到一个.o
的文件,里面包含了机器可以执行的代码。有多个文件的时候,会用到其它头文件里定义的函数,而编译这个cpp时编译器是不知道要调用的函数地址是什么,所以会暂时设置为0,直到链接过程才会修正。
随着项目的复杂化,编译的.cpp和.h文件越来越多,这个编译和链接的过程也越来越复杂,于是make工具(Makefile)出现了,这个古老的技术(1977)可以帮助我们构建一颗依赖树,然后通过make
命令来递归执行构建。
然而,随着项目变得更复杂,Makefile也变得繁杂了起来,而且对于不同平台,要写的Makefile还不一样,于是cmake出现了。CMake可以通过CMakeLists.txt来生成makefile来给make用。
快速例子
CMake依赖于CMakeLists.txt这个文本文件。
# 使用`#`来注释文件
# 这一行表示cmake的最低版本
cmake_minimum_required(VERSION 3.10)
# 项目名称,输出的文件就叫这个名字
project(Example)
# 项目Example需要构建可执行文件,由main.cpp编译得到
add_executable(Example main.cpp)
有了CMakeLists.txt之后,CMake需要根据编译平台进行配置(Configure),然后进行build。
build直接使用cmake build
即可。
CMake参数和命令
-
add_executable
就是为项目添加所有的源代码,可以无限加
add_executable(Example main.cpp my1.cpp my2.cpp my3.cpp)
-
aux_source_directory(dir var)
glob操作,将dir下的所有源文件存到var变量中,后续通过
${var}
进行调用aux_source_directory(. SRC_LIST) add_executable(Example ${SRC_LIST})
-
include_directories(dir)
之前是编译cpp文件,假如定义和实现分开,你有很多头文件,则可以让cmake自动去dir下寻找头文件(也可以多个目录)
include_directories(./include1 ./include1)
-
add_library(lib_name STATIC/SHARED src)
生成静态库或者动态库,和
add_executable
的用法类似。# 第一个参数是生成的库的名称 第二个是动态或者静态 后面是源文件 add_library(func_shared SHARED ${SRC_LIST}) add_library(func_shared STATIC ${SRC_LIST})
-
set_target_properties()
设置目标的属性,一般可以用来设置版本号和输出名称
# 更改输出文件名 # 将 hello_static 更名为 hello SET_TARGET_PROPERTIES (hello_static PROPERTIES OUTPUT_NAME "hello")# 设置版本号 # 将hello的动态库版本设置为1.2 API版本设置为1 SET_TARGET_PROPERTIES (hello PROPERTIES VERSION 1.2 SOVERSION 1)
-
set
用来定义或者修改变量的值,这些变量可以是普通变量、缓存变量或环境变量。
# EXECUTABLE_OUTPUT_PATH是系统变量,这里设置可执行文件的输出目录到bin下 set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/../bin) # LIBRARY_OUTPUT_PATH是系统变量,这里设置链接库的输出目录到lib下 set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/../lib)
-
find_library(var lib_name lib_path1 lib_path2)
在lib_path路径下查找库(.so .a),并存到var变量
# 将库myfunc的位置存到FUNC_LIB中 find_library(FUNC_LIB myfunc ${PROJECT_BINARY_DIR}/../lib)
-
target_link_libraries(target lib_name)
用来把lib连接到一个可执行文件中
# 上一步找到的库连接到可执行文件 target_link_libraries(hello ${FUNC_LIB})
-
find_package
从计算机上寻找库,寻找到的库会保存
XXX_FOUND/_DIR/_INCLUDE_DIR/_LIBS
等变量。REQUIRED
表示必须要找到package,否则报错。# 找OpenCV find_package(OpenCV REQUIRED) # 接下来可以使用这些路径了 ${OpenCV_DIR} ${OpenCV_INCLUDE_DIRS} ${OpenCV_LIBS} # 也可以进行一些逻辑控制(if中直接用变量名) if(OpenCV_FOUND)target_link_libraries(...) else(OpenCV_FOUND)message(FATAL_ERROR ”GLOG library not found”) endif(OpenCV_FOUND)
-
常用变量
PROJECT_BINARY_DIR
:cmake配置命令的目录,通常是build目录下。PROJECT_SOURCE_DIR
:代码的路径通常假如源码路径是
src
,那么在src下创建一个build,再进入build,然后cmake ..
,表示build的上一级是源码,但是编译结果保存在build下。
常用编译流程
rm -rf build # 删除旧的build,假如没有旧的或者makefile没有变化,则不需要这一步
mkdir build
cd build
cmake .. # 根据CMakeLists.txt生成makefile
make # 根据txt生成makefile进行编译make clean # 不一定需要,删除make之前生成的缓存
参考:
【软件构建: CMake 快速入门】 https://www.bilibili.com/video/BV1rR4y1E7n9/?share_source=copy_web&vd_source=cdc2983e744e85d26061233640e163f4
【cmake学习】set_target_properties 常见属性以及获取target 属性_set——target-CSDN博客
CMake,make,CMakeLists.txt,CMakeFiles之间的关系_.cmake .cmake.in cmakefile.txt 的关系-CSDN博客
【隐藏的细节:编译与链接】 https://www.bilibili.com/video/BV1TN4y1375q/?share_source=copy_web&vd_source=cdc2983e744e85d26061233640e163f4
2911202/article/details/85337968)【隐藏的细节:编译与链接】 https://www.bilibili.com/video/BV1TN4y1375q/?share_source=copy_web&vd_source=cdc2983e744e85d26061233640e163f4