CMake笔记
概述
-
正常流程:预编译、编译、汇编、链接
-
Visual Studio(集成开发环境IDE:编辑器、编译器VC++、nmake、调试器),比较傻瓜的进行完整的编译流程,不需要开发者干预。禁用VisualStudio后,windows平台下无法使用此流程工具,部分代码也因为引用了VC++的特性,所以也许要进行一定的改造重构
-
cmake优点:跨平台、支持多种编译器:vc++、mingw、crgwin、lcc等,利于开发者掌握代码模块间的关联性;缺点:官方文档比较杂,没有优秀的官方范例,很多配置项有多种配置方式,一些配置项互相影响导致结果与官方文档说明的功能有差异
CMakeLists.txt文件
-
CMakeLists.txt文件是CMake进行编译链接的配置文件,保存了项目信息、代码模块关联性、链接库生成配置、可执行文件生成配置、头文件引用配置等,一般由开发者根据项目内容手动编写,保存在项目的根目录下
-
CMakeLists.txt主要结构:
- [项目信息] 可省略
- [变量定义] 复杂项目可能需要进行,非必须
- [自定义配置选项] 自定义配置处理,非必须
- [子项目配置] 多模块开发涉及,非必须
- [头文件、库文件引用配置] 应用第三方库或多模块开发涉及,非必须
- [编译] 一般add_executable或者add_library即可
- [连接] 链接库(动态库、静态库)连接至上一步生成的产物上
涉及语法总览
语法 | 解释 | 其他注意事项 |
---|---|---|
project | 工程名 | 非必须 |
cmake_minimum_required | cmake最低版本需求 | 非必须 |
${} | 引用变量、宏定义等 | |
add_executable | 编译可执行文件 | |
add_library | 编译库文件 | |
include_directories | 设置头文件目录 | 一般引用第三方库时使用 |
link_directories | 设置库文件目录 | 一般引用第三方库时使用 |
message | 输出文本信息 | 多用以调试输出 |
add_compile_options | 设置编译选项 | gcc、g++选项 |
set | 设置选项 | |
aux_source_directory | 批量引用源文件 | |
options | 自定义选项 | |
if(),elseif(),else(),endif() | 条件分支 |
SET常用选项
选项 | 解释 | 参数 |
---|---|---|
CMAKE_BUILD_TYPE | 编译模式 | “Release”,“Debug” |
EXECUTABLE_OUTPUT_PATH | 设置可执行文件输出目录 | |
CMAKE_ARCHIVE_OUTPUT_DIRECTORY | 设置动态库模块导入文件dll.a(lib)输出目录 | mingw编译器绝大多数情况不需要,VC编译器必须 |
CMAKE_RUNTIME_OUTPUT_DIRECTORY | 设置链接库输出目录 | |
CMAKE_LIBRARY_OUTPUT_DIRECTORY | 设置链接库输出目录 | 未成功,原因未知 |
PS:链接库输出选项
- CMAKE_ARCHIVE_OUTPUT_DIRECTORY,CMAKE_RUNTIME_OUTPUT_DIRECTORY,CMAKE_LIBRARY_OUTPUT_DIRECTORY在Linux和Windows下的产生的效果不同,可能与CMake版本或者系统差异有关,需要酌情调用,或者全部调用
命令行常用选项
选项 | 说明 | 其他注意事项 |
---|---|---|
-version | 显示cmake版本信息 | |
-help | 显示cmake命令行帮助信息 | |
-G | 选择编译器 | MinGW编译器一般是"MinGW Makefiles" |
-D[选项] | 命令行临时修改选项,[选项]参见SET常用选项 | 如果命令行和CMakeLists.txt里有同样的选项,那么命令行选项设置会失效 |
详细解析
[项目信息]
project([NAME])项目名称
插入字符串即可
cmake_minimum_required(VERSION 3.0)cmake需求版本
最低版本号,根据所使用的cmake版本可支持的特性来决定,本篇所涉及的特性使用3.0以上即可
[变量定义]
set([NAME] [VALUE])设定变量
一般复杂项目时,部分字符串、文件名会反复调用,定义变量保存,方便编写,使用${NAME}可得到变量值
message(${NAME})输出内容
在cmake准备阶段,message会输出指定变量或者宏的值,方便开发者确认详细配置内容
[自定义配置选项]
option([NAME] [DESCRIPTION] [DEFAULT_VALUE])设置自定义选项
自定义执行选项,可在cmake执行阶段,通过命令行改变选项,一般配合if()else()进行编译分支
NAME-选项名称
DESCRIPTION-描述字符串
DEFAULT_VALUE-默认值ON/OFF或者字符串
if([表达式])…elseif([表达式])…else()…endif() 条件分支
关系运算符 | 解释 |
---|---|
AND | 与 |
NOT | 非 |
OR | 或 |
EXIST | 目录、文件是否存在 |
EQUAL | 变量等于 |
LESS | 变量小于 |
GREATER | 变量大于 |
STREQUAL | 字符串等于 |
STRELESS | 字符串小于 |
STREGREATER | 字符串大于 |
[子项目配置]
add_subdirectory([DIR])添加子项目
运用在多模块项目中,主模块CMakeLists.txt中应用其他模块,DIR目录为绝对路径,该目录下必须要有对应的源文件和CMakeLists.txt
[头文件、库文件引用配置]
include_directories([DIR])添加头文件目录
一般用在引用第三方模块
link_directories([DIR])添加链接库目录
一般用在引用第三方模块
[编译]
add_executable([OUT] [SOURCE FILE LIST])编译可执行文件
- OUT-可执行文件名
- SOURCE FILE LIST-编译OUT需要的源文件列表
add_library([OUT] [TYPE] [SOURCE FILE LIST])编译链接库
- OUT-编译输出的链接库名称,PS:cmake采用Linux命名规则,链接库会自动添加"lib"前缀
- TYPE-链接库类型:STATIC-静态库,SHARED-动态库;如果不指定,则默认静态库
- SOURCE FILE LIST-编译OUT需要的源文件列表
aux_source_directory([DIR] [NAME])查找目录中所有源文件
在调用add_executable或add_library时,需要列出全部的源文件。大项目中,源文件如果很多,一个一个添加很复杂,可以使用aux_source_directory自动扫描[DIR]下的全部源文件,赋值给[NAME]变量,再通过NAME引用
aux_source_directory(${CMAKE_SOURCE_DIR}/src CPPS)//扫描CMakeLists.txt所在目录下src目录下的全部源文件,定义为CPPS
add_executable(out CPPS) //使用CPPS来编译可执行文件out
[连接]
target_link_libraries([OUT] [LIBS])链接库文件
将LIBS的全部库文件链接到[OUT]可执行文件、库文件中
- target_link_libraries必须写在add_executable和add_library之后
- cmake采用的是Linux命名规则,所以指定LIBS时,如果只写库名,会在库名前加lib,默认优先查找静态库,再查找动态库
- LIBS可以指定完整的库文件名
- 不建议在一条target_link_libraries中混合使用2,3中的静态、动态、自动查找方式,否则可能会导致未知错误
CMake与交叉编译
由于每个交叉编译链的差异,以及个人部署的环境不同,所以CMake的交叉编译环境,需要根据系统差异进行反复测试才能调试通过
以下为官方文档,且较为通用的配置
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(ARMROOT "/home/ubuntu/arm-linux-gnueabi/")
//设置编译链的主目录(非必须,如果编译出错时,可以尝试加上)
set(CMAKE_SYSROOT ${ARMROOT})
//设置C编译器绝对路径
set(CMAKE_C_COMPILER ${ARMROOT}/bin/arm-linux-gnueabi-gcc)
//设置C++编译器绝对路径
set(CMAKE_CXX_COMPILER ${ARMROOT}/bin/arm-linux-gnueabi-g++)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
....
....
....