参考
https://blog.csdn.net/afei__/article/details/81201039
https://www.bilibili.com/video/BV12f4y1X7Jm?t=505
简介
cmake 是一个跨平台、开源的构建系统。它是一个集软件构建、测试、打包于一身的软件。它使用与平台和编译器独立的配置文件来对软件编译过程进行控制。
语法介绍
CMAKE_SOURCE_DIR和PROJECT_SOURCE_DIR,指的是定义顶级CMakeLists.txt的绝对路径
命令名称是不区分大小写的,而参数和变量是大小写相关的。
1、指定cmake的最小版本
cmake_minimum_required(VERSION 3.5)
声明要求的cmake最低版本,这个命令是可选的
可以在linux下输入cmake -version可以查看cmake的版本
2、项目名称
project(demo)
声明cmake工程的名称demo
这个命令不是强制性的,但最好都加上。它会引入两个变量 demo_BINARY_DIR 和 demo_SOURCE_DIR,同时,cmake 自动定义了两个等价的变量 PROJECT_BINARY_DIR 和 PROJECT_SOURCE_DIR。
3、编译模式
set(CMAKE_BUILD_TYPE "Debug")
设置cmake编译模式有debug和release两种,因为debug模式编译生成的可执行文件包含可调试的相关信息,所以文件大小会变大。
4、编译优化
set(CMAKE_CXX_FLAGS "-std=c++11 -march=native -O3")
参数CMAKE_CXX_FLAGS含义是:set compiler for c++ language
添加C++11标准支持
-march=native 指定目标程序的cpu架构来进行程序优化
native 就是相当于自检测cpu,-march是gcc优化选项
后面的-O3使用来调节编译是的优化程度,最高为-O3,最低为-O0即不做优化
5、指定头文件和库文件
5.1 头文件
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include)
把该目录设为头文件目录
5.2 库文件
LINK_DIRECTORIES(${PROJECT_SOURCE_DIR}/lib)
把该目录设为链接目录,它相当于g++命令的-L选项的作用,也相当于环境变量中增加LD_LIBRARY_PATH的路径的作用。也可以多个链接库文件地址
LINK_DIRECTORIES(directory1 directory2 ...)
一般链接库目录的做法,如下:
LINK_DIRECTORIES(/home/cxzx/opencv44/lib)
LINK_LIBRARIES(opencv_ml opencv_objdetect opencv_imgproc opencv_core opencv_highgui
opencv_imgcodecs opencv_shape opencv_videoio opencv_video)
LINK_DIRECTORIES(/home/cxzx/training/cv_yolo)
LINK_LIBRARIES(darknet)
6、指定编译包含的源文件
6.1 明确指定包含哪些源文件
add_executable(demo demo.cpp test.cpp util.cpp)
6.2 搜索所有的 cpp 文件
aux_source_directory(dir VAR) 发现一个目录下所有的源代码文件并将列表存储在一个变量中。
aux_source_directory(. SRC_LIST) # 搜索当前目录下的所有.cpp文件
add_library(demo ${SRC_LIST})
6.3 自定义搜索规则
file(GLOB SRC_LIST "*.cpp" "protocol/*.cpp")
add_library(demo ${SRC_LIST})
# 或者
file(GLOB SRC_LIST "*.cpp")
file(GLOB SRC_PROTOCOL_LIST "protocol/*.cpp")
add_library(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST})
# 或者
aux_source_directory(. SRC_LIST)
aux_source_directory(protocol SRC_PROTOCOL_LIST)
add_library(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST})
7、设置编译类型
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.dl
8、设置 target 需要链接的库
target_link_libraries( # 目标库
demo
# 目标库需要链接的库
在 Windows 下,系统会根据链接库目录,搜索xxx.lib 文件,Linux 下会搜索 xxx.so 或者 xxx.a 文件,如果都存在会优先链接动态库(so 后缀)。
8.1 指定链接动态库或静态库
target_link_libraries(demo libface.a) # 链接libface.a
target_link_libraries(demo libface.so) # 链接libface.so
8.2 指定全路径
target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.a)
target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.so)
8.3 指定链接多个库
target_link_libraries(demo
${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.a
boost_system.a
boost_thread
pthread)
9. 设置变量
9.1 set 直接设置变量的值
set(SRC_LIST main.cpp test.cpp)
add_executable(demo ${SRC_LIST})
9.2 set 追加设置变量的值
set(SRC_LIST main.cpp)
set(SRC_LIST ${SRC_LIST} test.cpp)
add_executable(demo ${SRC_LIST})
10、打印信息message
message(${PROJECT_SOURCE_DIR})
message("build with debug mode")
message(WARNING "this is warnning message")
message(FATAL_ERROR "this build has many error") # FATAL_ERROR 会导致编译失败
11、find_package
find_package( OpenCV REQUIRED)
添加依赖,去寻找该库的头文件位置、库文件位置以及库文件名称,并将其设为变量,返回提供给CMakeLists.txt其他部分使用。
在CMakeLists中使用第三方库的三部曲
find_package、include_directories、target_link_libraries
include_directories(${OpenCV_INCLUDE_DIRS})
去哪里找头文件
target_link_libraries(${OpenCV_LIBRARIES})
需要链接的库文件
LINK_DIRECTORIES()
去哪里找库文件(.so/.lib/.ddl等)
12、安装地址配置
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
设定生成的可执行二进制文件存放的存放目录
SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
设定生成的库文件的存放目录
SET(CMAKE_INSTALL_PREFIX < install_path >)
在CMakeLists中指定安装位置
cmake -DCMAKE_INSTALL_PREFIX=/usr ..
在编译终端指定安装位置
实例
1、demo1
└── demo1
├── build
├── CMakeLists.txt
└── demo.cpp
新建demo.cpp
#include <iostream>
int main()
{
std::cout<< "hello world" << std::endl;
}
新建CMakeLists.txt
add_executable(demo demo.cpp)
运行
mkdir build && cd build &&cmake ..&& make -j
./demo
为什么要新建一个 build 文件夹?
一般我们采用 cmake 的 out-of-source 方式来构建(即生成的中间产物和源代码分离),这样做可以让生成的文件和源文件不会弄混,且目录结构看起来也会清晰明了。所以推荐使用这种方式,至于这个文件夹的命名并无限制,我们习惯命名为 build
2、demo2
demo2
├── build
├── CMakeLists.txt
├── main.cpp
└── src
├── add.cpp
└── add.hpp
新建main.cpp
#include <iostream>
#include "add.hpp"
int main()
{
std::cout << "hello world" << std::endl;
int a = 1, b = 1;
std::cout << Add(a,b) << std::endl;
return 0;
}
新建add.cpp
#include <iostream>
int Add(int a, int b)
{
return a+b;
}
新建add.hpp
#ifndef __ADD_HPP__
#define __ADD_HPP__
int Add(int a, int b);
#endif
新建CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(demo2)
include_directories(./src)
add_executable(demo main.cpp ./src/add.cpp)
或者使用
cmake_minimum_required(VERSION 3.5)
project(demo2)
include_directories(./src)
FILE(GLOB_RECURSE SRCS ${CMAKE_SOURCE_DIR}/src/*.cpp)
add_executable(demo main.cpp ${SRCS})
运行
mkdir build && cd build &&cmake ..&& make -j
./demo
结果
hello world
2