CMake学习笔记

1、总结

  CMake和Qt自带的QMake对比,本身都是用于构建的工具,CMake更加通用,而且就功能来说更加丰富。CMake已经可以看成是一门专门的语言了,具有比较完善的自定义流程控制能力。对于现代CMake与经典CMake,现代CMake核心是面向对象,这个对象通常指的是编译的可执行程序或者库,也可以是用户自己创建的target。从API变化来看,最直观的就是在前面增加了一个target,表示该设置仅针对该target生效,所有属性设置围绕该对象。例如可以针对不同编译对象设置不同的编译搜索头文件路径。这样在大型工程中可以优化头文件路径搜索时间,加速编译。

2、细节用法整理

2.1、工程目录结构组织

  在工程目录管理上,QMake和CMake很相似,比如多工程这种解决方案级别的工程,QMake提供了SUBDIRS这个关键字用于添加二级工程目录,而CMake则提供add_subdirectory。在三级目录管理上,QMake提供了pri文件,用于组织子目录中的源码,上级工程文件中就可以通过include(xxx.pri)引入此目录中的源码。CMake中则可以采取类似的做法,在每级目录中新建一个子CMakeLists.txt,然后通过add_subdirectory把子目录包含进去,但是子目录中的CMakeLists.txt只负责组织源码,需要上层工程将组织好的源码变量拼接到对应的变量中,然后通过指令用指定存储源码列表的变量生成具体的target(库或者可执行程序)。下面介绍一个最基本的工程构建目录结构。

2.1.1、最顶层的多工程管理工程文件

1
2
3
4
5
6
7
cmake_minimum_required(VERSION 3.5)
project(test LANGUAGES CXX)

add_subdirectory(A)
add_subdirectory(B)

add_dependencies(A B)

2.1.2、二级工程目录工程文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
cmake_minimum_required(VERSION 3.5)
project(A LANGUAGES CXX)

file(GLOB SRC_FILES ${CMAKE_CURRENT_LIST_DIR}/main.cpp)
file(GLOB HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/test.h)
#拼接子目录中的源码
list(APPEND SRC_FILES ${A1_SRC_FILES} ${A2_SRC_FILES})
list(APPEND HEADER_FILES ${A1_HEADER_FILES} ${A2_HEADER_FILES})

add_executable(${PROJECT_NAME}
${SRC_FILES}
${HEADER_FILES}
)

target_link_libraries(${PROJECT_NAME} PRIVATE B)

add_subdirectory(A1)
add_subdirectory(A2)

2.1.3、三级源码子目录(A1)工程文件

1
2
3
4
5
6
file(GLOB A1_SRC_FILES ${CMAKE_CURRENT_LIST_DIR}/test1.cpp)
file(GLOB A1_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/test1.h)

#将源码变量暴露给上层目录,注意默认情况下,上层工程是无法获取下级工程中定义的变量,需要使用set(xxx PARENT_SCOPE)暴露给上层目录,且仅限上层目录,再往上的工程就无法获取这个变量了。
set(A1_SRC_FILES ${A1_SRC_FILES} PARENT_SCOPE)
set(A1_HEADER_FILES ${A1_HEADER_FILES} PARENT_SCOPE)

  这个简单工程介绍了一个最常用的目录结构,一个大工程,包含两个子工程,一个是可执行主工程(A),一个是动态库或静态库(B)。A工程依赖B工程产生的库文件,通过顶层工程指定了依赖关系之后,就会先编译B工程,再编译A工程。这里我这种组织源码的方法有些繁琐,但是优点是可以每层目录精确控制源码的引入。可以在复杂环境下,比如跨平台工程,在不同情况下引入不同平台的代码进行编译。有一种比较偷懒的做法如下:

1
file(GLOB_RECURSE SRC_FILES ${PROJECT_SOURCE_DIR} *.cpp)

这种用法会递归扫描所有的目录,然后将所有后缀为cpp的源码全部添加到SRC_FILES变量中,如果是练习项目可以采取这种做法节约时间。

2.2、CMake生成vs工程去掉控制台界面

  在使用CMake生成vs工程(Qt GUI),启动之后会先启动一个控制台,非常不雅观,这个配置如果是是在qmake的pro中配置,只需要将CONFIG中的console选项去掉即可。在CMake中可以在有如下两种方式解决:

  • add_executable

    1
    add_executable(<name> [WIN32] [MACOSX_BUNDLE]               [EXCLUDE_FROM_ALL]               source1 source2 ... sourceN)

&emsp;&emsp;创建进程时选择WIN32参数即可。

  • set_target_properties

    1
    set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")

&emsp;&emsp;这两种做法是等价的,但是明显第一个要简单。

2.2、External_Project用法

2.3、Private Public Interface的区别


CMake学习笔记
http://yoursite.com/2021/11/13/CMake学习笔记/
作者
还在输入
发布于
2021年11月13日
许可协议