1. 入门实战
1.1. 什么是CMake
我们或许听过好几种Make工具, 例如GNU Make
, QT的qmake
, 微软的MS nmake
, BSD Make(pmake
), Makepp, 等等. 这些Make工具遵循着不通的规范和标准, 所执行的Makefile格式也是千差万别. 不mail.yahoo.com.cn就带来了一个严峻的问题: 如果软件想跨平台, 必须保证能够在不同平台编译. 而如果使用上面的Make工具, 就得为每一种标准写一次Makefile, 着将是一件让人抓狂的工作.
CMake就是针对上面问题所设计的工具: 它首先允许开发者编写一种平台无关的CMakeList.txt文件来定制整个编译流程, 然后再根据目标用户的平台进一步生成所需的本地化Makefile和工程文件, 如Unix的Makefile或者Window的Visual Studio工程. 从而遭到"Write once, run everywhere". 显然, CMake是一个比上述几种make更高级的编译配置工具. 一些使用CMake作为项目架构系统的知名开源项目有VTK
,ITK
,KDE
,OpenCV
, OSG
等.
1.2. 在linux平台下使用CMake生成Makefile并编译的流程如下
- 编写CMake配置文件
CMakeLists.txt
- 执行命令
cmake PATH
或者ccmake PATH
生成Makefile. 其中PATH
是CMakeList.txt
所在的目录 - 使用
make
命令进行编译 - 之后的步骤就是使用
makefile
一样的步骤了
1.3. 入门案例: 单个源文件
-
示例
- 示例文件 main.cpp
#include
using namespace std; int main(void) { cout << "hello world" << endl; return 0; } - CMakeLists.txt
# 指定运行此配置文件所需要的CMake的最低版本 cmake_minimum_required(VERSION 3.5) # 根据cmake --version获得 # 表示项目的名称是DEMO1 project (DEMO1) # 将名为main.cpp的源文件编译成一个名称为Demo的可执行文件 add_executable(Demo main.cpp)
- 生成makefile
-
main.cpp和CMakeLists.txt放到同一目录下
-
在
CMakeLists.txt
同一目录下执行cmake .
-
然后执行make
-
从第三步开始和makefile操作相同
1.4. 多个源文件
1.4.1. 同一目录, 多个源文件
-
示例
- 创建一个main.cpp
#include "my_printf.h" int main(int argc, char const *argv[]) { wtj_printf(); return 0; }
- 创建一个my_printf.h
#ifndef __MY_PRINTF_H #define __MY_PRINTF_H void wtj_printf(void); #endif
- 创建一个my_printf.cpp
#include "my_printf.h" #include
using namespace std; void wtj_printf(void) { cout << "hello world" << endl; } - 创建CMakeLists.txt
# CMake version cmake_minimum_required(VERSION 3.5) # project info project (DEMO2) # 查找当前目录下的所有源文件, 并将名称保存到DIR_SRCS 变量 aux_source_directory(. DIR_SRCS) # 指定生成目标 add_executable(Demo ${DIR_SRCS})
-
编译执行
cmake .
-
直接执行
make
, 然后运行可执行程序
1.4.2. 多个目录, 多个源文件
-
将上面的my_printf.h和my_printf.cpp放到test_a目录下
-
将
main.cpp
放在根目录(必须的
) -
CMakeLists.txt保持不变, 还是在根目录中
# CMake version cmake_minimum_required(VERSION 3.5) # project info project (DEMO2) # 查找当前目录下的所有源文件, 并将名称保存到DIR_SRCS 变量 aux_source_directory(. DIR_SRCS) # Add header file include directories include_directories(./ ./test_a) # Add block directories add_subdirectory(test_a) # 指定生成目标 add_executable(Demo ${DIR_SRCS}) target_link_libraries(Demo test_a)
-
test_a目录下的CMakeLists.txt
aux_source_directory(. DIR_test_a_SRCS) add_library(test_a ${DIR_test_a_SRCS})
2. 源外编译(干货
)
-
示例
# 在项目根目录下创建一个build文件夹 mkdir build # 进入build cd build # 使用cmake到根目录下 cmake .. # 在build目录下使用make编译项目 make ## 之后所有生成的东西都在build目录下, 想删除编译可以直接删除build, 或者build下的所有文件
要点
:- 所有的目录下都有CMakeLists.txt(build文件夹除外), 但是都没有编译过, 每一个要生成的目录下都
不能有内部编译的方式进行编译出来的任何文件
- 使用
cmake ..
进行编译
- 所有的目录下都有CMakeLists.txt(build文件夹除外), 但是都没有编译过, 每一个要生成的目录下都
3. 个人使用的cmake文件(重点
)
-
工程根目录下创建一个
build文件夹
-
将main.cpp放在
工程根目录下
-
在
工程根目录
下放置CMakeLists.txt# CMake version cmake_minimum_required(VERSION 3.5) # get current folder name get_filename_component(CURRENT_FOLDER_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) string(REPLACE " " "_" CURRENT_FOLDER_NAME ${CURRENT_FOLDER_NAME}) project(${CURRENT_FOLDER_NAME}) # print variable name message(${CURRENT_FOLDER_NAME}) # project name project (DEMO2) SET(ROOT_DIR ${PROJECT_SOURCE_DIR}) message("$PROJECT_SOURCE_DIR") # 查找当前目录下的所有源文件, 并将名称保存到DIR_SRCS 变量 aux_source_directory(. DIR_SRCS) # Add header file include directories include_directories(./ ./test_a ./test_b) # this should be changed # Add block directories add_subdirectory(test_a)# this should be changed add_subdirectory(test_b)# this should be changed # 指定生成目标为Demo add_executable(Demo ${DIR_SRCS}) target_link_libraries(Demo test_a test_b) # this should be changed
-
在其它有
源文件
的目录下放置一面的CMakeLists.txt# get current file name get_filename_component(CURRENT_FOLDER_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) string(REPLACE " " "_" CURRENT_FOLDER_NAME ${CURRENT_FOLDER_NAME}) # project named current folder name project(${CURRENT_FOLDER_NAME}) # print current folder name message(${CURRENT_FOLDER_NAME}) # 获得源文件 aux_source_directory(. DIR_${CURRENT_FOLDER_NAME}_SRCS) # 将这些源文件编译成名为"当前文件夹名"的"库文件" add_library(${CURRENT_FOLDER_NAME} ${DIR_${CURRENT_FOLDER_NAME}_SRCS})
4. 优化的版本
# CMake version
cmake_minimum_required(VERSION 3.5)
# 设置c++ -std=c++11
set(CMAKE_CXX_STANDARD 11)
# 设置工程名
project (DEMO)
# 获取当前目录下的源文件, 并保存到DIR_SRCS中
aux_source_directory(. DIR_SRCS)
# 添加头文件的路径
include_directories(/usr/include/spinnaker ./)
# 设置输出可执行文件路径, PROJECT_SOURCE_DIR是工程根目录
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
add_executable(Demo ${DIR_SRCS})
target_link_libraries(Demo Spinnaker) # 链接到spinnaker这个库, 这个是在环境变量中
# 添加pthread, 否则无法编译, 主要是多线程上用的, 用线程就必须用
# target_link_libraries(Demo pthread)
5. 优化的版本2(使用当前目录下的库)
# CMake version
cmake_minimum_required(VERSION 3.5)
# 设置c++ -std=c++11
set(CMAKE_CXX_STANDARD 11)
# 设置工程名
project (DEMO)
# 获取当前目录下的源文件, 并保存到DIR_SRCS中
aux_source_directory(. DIR_SRCS)
# 添加头文件的路径
include_directories(./)
# 设置输出可执行文件路径, PROJECT_SOURCE_DIR是工程根目录
# set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
link_directories(${PROJECT_SOURCE_DIR}/lib) # 添加当前目录下的lib, 主要要把对应的头文件也要放到这个源文件下
add_executable(Demo ${DIR_SRCS})
target_link_libraries(Demo -lmodbus) # 链接到spinnaker这个库, 这个是在环境变量中
# 添加pthread, 否则无法编译, 主要是多线程上用的, 用线程就必须用
# target_link_libraries(Demo pthread)
6. 优化的版本3(英文注释, 使用当前目录下的库)
# CMake version
cmake_minimum_required(VERSION 3.5)
# set c++ -std=c++11
set(CMAKE_CXX_STANDARD 11)
# set project name
project (DEMO)
# add .cpp dir
aux_source_directory(. DIR_SRCS)
# add .h dir
include_directories(./)
# add a custom lib under the current project
link_directories(${PROJECT_SOURCE_DIR}/lib)
# complie all .cpp file
add_executable(Demo ${DIR_SRCS})
# target link a custom lib modbus
target_link_libraries(Demo -lmodbus)
6.1. 优化的版本4(适合qtcreator创建工程)
# CMake version
cmake_minimum_required(VERSION 3.5)
# set c++ -std=c++11
set(CMAKE_CXX_STANDARD 11)
# set project name
project (DEMO)
# add .h dir
file (GLOB HEADERS "./*.h")
# add .cpp dir
aux_source_directory(. DIR_SRCS )
# put source and header files in a macro, SRC_LIST
SET(SRC_LIST ${SRC_LIST} ${HEADERS} ${DIR_SRCS})
# add a custom lib under the current project
#link_directories(${PROJECT_SOURCE_DIR}/lib)
# complie all .cpp file
add_executable(Demo ${SRC_LIST})
message("${DIR_SRCS}")
# target link a custom lib modbus
#target_link_libraries(Demo -lmodbus)
6.2. 优化的版本5(适合ros)
# get all .h file
include_directories(include ${catkin_INCLUDE_DIRS})
# get all .cppfile
aux_source_directory(src DIR_SRCS)
add_executable(
to_usun_node # node name, and the add the source file
${DIR_SRCS} # .cpp file
)
target_link_libraries(to_usun_node ${catkin_LIBRARIES} glog) # add glog
add_dependencies(to_usun_node to_usun_node_generate_messages_cpp)
6.3. 优化的版本6
#CMake version
cmake_minimum_required(VERSION 3.5)
#set c++ -std=c++11
set(CMAKE_CXX_STANDARD 11)
#set project name
project (DEMO)
#add .cpp dir
aux_source_directory(./src DIR_SRCS) # 这个是存放源文件的文件夹, 并保存到DIR_SRCS
#add .h dir
include_directories(./include) # 这个是存放头文件文件夹
#add a custom lib under the current project
link_directories(${PROJECT_SOURCE_DIR}/lib) # 这个是存放.so文件的文件夹
#complie all .cpp file
add_executable(Demo ${DIR_SRCS}) # 这个是编译所有的源文件的位置
#target link a custom lib modbus
target_link_libraries(Demo -lpthread)
target_link_libraries(Demo -lcontrolcan) # 添加对应的.so文件的lib库
7. 如何使用
touch CMakeLists.txt
mkdir build
cd build
cmake .. && make