CMake使用总结及心得

CMake使用总结及心得

CMake(Cross-Make)是一个跨平台的构建工具,CMake本身并不参与工程的构建和编译,CMake使用简单的语法描述项目构建的细节,根据用户所需,生成makefile或者IDE的project。通常存放CMake工程描述细节的文件名是CMakeLists.txt

CMake在很多IDE和开源库中使用,比如VisualStudio、CLION、OpenCV、QT等一众常用的IDE和库都支持CMake。


使用CMake本质上就是编写CMakeLists.txt文件,使用CMake提供的脚本描述项目的构建规则,然后运行cmake程序,cmake根据CMakeLists.txt文件生成makefile或者IDE的project。所以使用CMake的重点就是学习CMake的构建脚本及CMake描述工程的逻辑。


对于Cmake的逻辑,总结如下:

CMAKE根据变量(包括CMake预定义的变量和用于定义的变量)来确定当前的构建环境和构建规则(构建环境包括依赖的库的位置、头文件位置等),修改构建环境和构建规则本质上就是在修改这些变量。然后用户和CMkae本身通过使用这些变量来描述构建的规则,比如要链接哪些库、需要包含哪些头文件、语言的版本、编译器参数等。

下面是一个使用OpenCV库的例子:

# 指定需要CMake的最低版本
cmake_minimum_required(VERSION 3.14)
# 设置工程名
project(test)
# 设置变量CMAKE_CXX_STANDARD的值为17
set(CMAKE_CXX_STANDARD 17)

# 设置opencv的根目录变量、头文件目录变量、链接库位置变量、链接库名称变量
set(opencv_root /home/ding/develop/lib/opencv/opencv-3.4.9)
set(opencv_include ${opencv_root}/include)
set(opencv_lib_dir ${opencv_root}/lib)
set(opencv_libs libopencv_world.so.3.4.9)

# 设置头文件目录为opencv_include的值
include_directories(${opencv_include})
# 设置链接库目录为opencv_lib_dir的值
link_directories(${opencv_lib_dir})
# 设置要链接文件的名字为opencv_libs的值
link_libraries(${opencv_libs})

# 添加构建可执行文件的目标demo,目标包含main.cpp源文件
add_executable(demo main.cpp)

在这个例子中,正如上文所说,想要修改c++的版本,只需通过set语句修改CMAKE_CXXSTANDARD这个变量的值,那么cmake在生成project的时候,将会根据这个变量的值来设置c++的语言版本。具体到编译参数,如gcc,就是加一个-std=c++17参数。再比如想要使用pthread库,将CMAKE_EXE_LINKER_FLAGS变量附加一个-lpthread即可,即:set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} -lpthread)

而设置opencv头文件、库目录、路名称和cmake的find_package语句的原理是一致的,只不过find_package使用的OpenCV_DIR变量,如下:

(注:OpenCV库是用CMake构建安装后,会生成相应的CMake支持文件,3.x版本cmake支持文件在<install_path>/share/OpenCV,4.x版本在<install_path>/lib/cmake/opencv4目录下)

# 指定需要CMake的最低版本x
cmake_minimum_required(VERSION 3.14)
# 设置工程名
project(test)
# 设置变量CMAKE_CXX_STANDARD的值为17
set(CMAKE_CXX_STANDARD 17)

# 设置OpenCV_DIR变量
set(OpenCV_DIR /home/ding/develop/lib/opencv/opencv-3.4.9/share/OpenCV)

# 查找OpenCV
find_package(OpenCV REQUIRED)

# 添加可执行构建目标demo
add_executable(demo main.cpp)

# 为demo目标设置链接库
target_link_libraries(demo ${OpenCV_LIBS})
# 设置包含目录
target_include_directories(demo ${OpenCV_INCLUDE_DIR} PRIVATE)

find_package在如下目录中搜索package>Config.cmake文件或Find<package>.cmake文件:

<package>_DIR
CMAKE_PREFIX_PATH
CMAKE_FRAMEWORK_PATH
CMAKE_APPBUNDLE_PATH
PATH

如果搜索成功,将执行package>Config.cmake或Find<package>.cmake文件(其中package>Config.cmake文件用于config模式,Find<package>.cmake用于moudle模式,cmake优先使用moudle模式)。执行完后,将添加如下变量:

<package>_FOUND
<package>_INCLUDE_DIRS or <package>_INCLUDES
<package>_LIBRARIES or <package>_LIBRARY or <package>_LIBS
<package>_DEFINITIONS

使用CMake构建同时使用Qt5和OpenCV的例子:

cmake_minimum_required(VERSION 3.5)

project(one LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

# 打开全局moc
set(CMAKE_AUTOMOC ON)
# 打开全局uic
set(CMAKE_AUTOUIC ON)
# 打开全局rcc
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# OpenCV的CMake支持文件目录
set(OpenCV_DIR /home/ding/develop/lib/opencv/opencv-3.4.9/share/OpenCV)
# Qt5的CMake支持文件目录
set(Qt5_DIR /home/ding/develop/sdk/qt/Qt5.12.7/5.12.7/gcc_64/lib/cmake/Qt5)

find_package(Qt5 COMPONENTS Core Gui Widgets Qml Quick REQUIRED)
find_package(OpenCV REQUIRED)

add_executable(one
    main.cpp
    mainwindow.cpp
    mainwindow.h
    mainwindow.ui)

target_link_libraries(one Qt5::Core Qt5::Gui Qt5::Widgets)
target_link_libraries(one ${OpenCV_LIBS})

所以编写CMakeLists.txt主要就是在做两件事:

1、定义、修改变量

2、使用变量

CMake常用语句:

# 用于定义、修改变量
set()
# 设置工程
project()
# 用于添加可执行构建目标
add_executable()
# 用于添加库构建目标
add_library()
# 用于为构建目标设置构建规则和依赖
target_include_directories()
target_link_libraries()
target_link_directories()
target_link_options()
target_compile_definitions()
target_compile_features()
target_compile_options()
target_sources()
# 设置目标属性
set_target_properties()
# 设置全局包含目录、库文件目录、库文件名
include_directories()
link_directories()
link_libraries()
# 查到包
find_package()
# 用于自动生成目录源文件集合
aux_source_directory()
# 添加子目录
add_subdirectory()


CMake学习教程:

CMake Tutorial - CMake 3.17.0-rc1 Documentationcmake.org
CMake快速入门-生命不息,奋斗不止-51CTO博客blog.51cto.com图标

编辑于 02-23