CMAKE使用手记

Posted 看,未来

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CMAKE使用手记相关的知识,希望对你有一定的参考价值。

致谢

首先感谢那位叫“任麒麟”的网友整理的PDF,有心了。
我也忘了哪里下载的,不过确实挺全的。

不过我也有心了,毕竟那PDF老长了,我二次开发也费劲呐。


编译与源代码分离

编译产生的中间过程文件全都放到 build目录下面,包括make生成的文件。


CMakeLists.txt 自动继承父目录

子目录的 CMakeLists.txt 自动继承了父目录里的 CMakeLists.txt 所定义的一切宏、变量。这极大地减少了重复的代码。


CMake 脚本基本语法

注释

# 这是注释

指令

CMake script 由一连串的指令 (command) 组成,每个指令可有零至多个参数。使用指令的语法为指令名称加上小括号,括号内可以有零或若干个参数,指令则依照出现在CMakeLists 当中的顺序执行。

指令的参数通常使用空格、tab 或者换行来分隔。


变量

在撰写 CMakeLists 时可以使用变量储存资料以及作为指令的参数。

CMake 中的变量具有以下特征:

1、变量严格区分大小写!
2、CMake 中的变量只有两种类型:字符串,和字符串数组。
3、变量无需声明即可赋值或者使用。未赋值的变量默认为一个空字符串。
4、与其他语言编程语言不同的是,CMake 脚本的语法中没有赋值操作。无论是赋值,还是比较、判断操作,都是通过内置指令来完成的。 
5、变量可以认为都是全局的,哪怕在一个宏中定义的变量,也可以在宏的外面被访问到。

如果字符串中不包含空格,那么可以不加引号,直接使用。


在 CMake 当中我们可以用 set() 指令来设定一个变量的值。提取变量值时通常必须在外面加上 ${} 符号,不过也有少数场合例外。

示例:

set(var hello)
message(${var})

会输出
hello

将字串用空白或分号分隔则表示字串数组。

set(foo this is a list)

将变量 foo 值指定为一个字串数组,内含 this、is、 a、list 四个字串。

如果在命令中,使用包含了字符串数组的变量作为参数会是怎样的情况呢?例如,下面的变量:

set(foo a b c)

将其作为参数传入一个指令:

command(${foo})

这等同于:

command(a b c)

在字符串中展开变量

在字符串中如果用${}将一个变量名包了起来,那么该变量也会被代换。
例如,如果我们执行下面的指令:

set(foo a b c d)
command("${foo}")

则相当于我们执行了 command(“a b c d”)。

不好猜吧,我现在不喜欢多说废话,尽量都是言简意赅。


转义字符串

如欲表示 CMake 当中的特殊字符时也可用 \\ 标记。

set(bar "alpha beta gamma")
message("\\${bar}: ${bar}")

上面的程式码输出

${bar}: alpha beta gamma

脚本流程控制

虽然我目前还不知道这个有什么用,但是也不敢确定这个哪天就用上了,反正也不难,就记着呗。

条件语句

CMake 的条件语句为 if、elseif、else、endif。

# 当 expr 值为下列其中之一時,执行 command1:
# ON, 1, YES, TRUE, Y
# 当 expr 值为下列其中之一時,执行 command2:
# OFF, 0, NO, FALSE, N, NOTFOUND, *-NOTFOUND, IGNORE 
if(expr)
 command1(arg)
else(expr)
 command2(arg)
endif(expr)
if((expr) AND (expr OR (expr)))

在条件式当中即使不加 ${},if 也会先尝试解释成变量。


循环语句

CMake 的循环有两种:

foreach ... endforeach
while ... endwhile
set(V alpha beta gamma)
message(${V})
foreach(i ${V})
   message(${i})
endforeach()
foreach(loop_var RANGE start stop [step])
endforeach(loop_var)
从 start 开始到 stop 结束,以 step 为步进

常用命令

指定项目的名称

命令语法:project(<projectname> [languageName1 languageName2 ... ] )
使用范例:project(Main)


指定需要的 CMake 的最低版本

命令语法:cmake_minimum_required(VERSION major[.minor[.patch[.tweak]]] [FATAL_ERROR])
使用范例:cmake_minimum_required(VERSION 2.8)


将 dir 目录下的所有源文件的名字保存在变量中

命令语法:aux_source_directory(<dir> <variable>)
使用范例:aux_source_directory(. DIR_SRCS)


指定从一组源文件编译出一个可执行文件且命名

命令语法:add_executable(<name> [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL]
source1 source2 … sourceN)
使用范例:add_executable(Main ${DIR_SRCS})


指定从一组源文件 source1 source2 … sourceN 编译出一个库文件且命名

命令语法:add_library([STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] source1 source2 … sourceN)
使用范例:add_library(Lib ${DIR_SRCS})


指定某个目标(可执行文件或者库文件)依赖于其他的目标

命令语法:add_dependencies(target-name depend-target1 depend-target2 …)
这里的目标必须是 add_executable、add_library、add_custom_target 命令创建的目标


添加一个需要进行构建的子目录

命令语法:add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
使用范例:add_subdirectory(Lib)


指定 target 需要链接

命令语法:target_link_libraries(<target> [item1 [item2 [...]]] [[debug|optimized|general] ] …)
这里 target 必须已经被创建,链接的item 可以是已经存在的 target(依赖关系会自动添加)
使用范例:target_link_libraries(Main Lib)


设定变量的值为

命令语法:set(<variable> <value> [[CACHE <type> <docstring> [FORCE]] | PARENT_SCOPE])
如果指定了 CACHE 变量将被放入 Cache(缓存)中。
使用范例:set(ProjectName Main)


移除变量

命令语法:unset(<variable> [CACHE])
命令简述:用于 variable。如果指定了 CACHE 变量将被从 Cache 中移除。
使用范例:unset(VAR CACHE)


输出信息

命令语法:message([STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR] “message to display” …)
该输出的编译信息它自己会默认输出的。
使用范例:message(“Hello World”)


设定目录

命令语法:include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2 …)
这些设定的目录将被编译器用来查找 include 文件
使用范例:include_directories(${PROJECT_SOURCE_DIR}/lib)


CMakeLists.txt 示例

cmake_minimum_required(VERSION 3.0) # 最低版本
project(main)   # 给这个工程一个名字,这不是可执行文件的名字,是工程的名字

# 设置编译选项,不知道最后能不能过
set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -g)

# 设置可执行文件最后的输出目录
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

# 配置头文件的搜索路径
include_directories(${PROJECT_SOURCE_DIR}/include)
include_directories(${PROJECT_SOURCE_DIR}/include/server)
include_directories(${PROJECT_SOURCE_DIR}/include/server/model)
include_directories(${PROJECT_SOURCE_DIR}/include/server/db)
include_directories(${PROJECT_SOURCE_DIR}/thirdparty)

# 加载子目录
add_subdirectory(src)
# 定义一个SRC_LIST变量,存放该目录下所有的源文件
aux_source_directory(. SRC_LIST)
aux_source_directory(./db SRC_LIST)
aux_source_directory(./model SRC_LIST)

# 指定生成可执行文件
add_executable(ChatServer ${SRC_LIST})

# 指定可执行文件生成时需要链接的外部库
target_link_libraries(ChatServer muduo_net muduo_base pthread mysqlclient hiredis)

# 指定可执行文件存放位置
#set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}../bin)

CMake 常用变量

CMAKE_SOURCE_DIR
内容为 source tree 根目录的完整路径,也就是 CMake 开始建置过程的进入点。

CMAKE_BINARY_DIR
内容为 binary tree 根目录的完整路径,在 in-source build 的时候值与 CMAKE_SOURCE_DIR 相同。

PROJECT_SOURCE_DIR
目前正在处理中的专案最上层目录,即内含 project() 指令的 CMakeLists 所在资料夹。

PROJECT_BINARY_DIR
目前所属专案的建置根目录。在 in-source build 时和 PROJECT_SOURCE_DIR 相同。

CMAKE_CURRENT_SOURCE_DIR
目前正在处理的 CMakeLists.txt 所在位置。

CMAKE_CURRENT_BINARY_DIR
目前正在处理的 CMakeLists.txt 对应的建置资料夹位置。在 in-source build 时和 CMAKE_CURRENT_SOURCE_DIR 相同。

CMAKE_CURRENT_LIST_DIR
表示正在处理的 CMakeLists.txt 文件的所在的目录的绝对路径(2.8.3 以及以后版本才支持)

CMAKE_LIBRARY_OUTPUT_DIRECTORY
用于设置 LIBRARY 目标的输出路径


CMAKE的局限性

CMake 并不遵守 GNU 规则。这使得 CMake 对一些开源软件的支持不够。

以上是关于CMAKE使用手记的主要内容,如果未能解决你的问题,请参考以下文章

代码手记笔录——哈希法

SonarQube搭建手记

结巴分词和自然语言处理HanLP处理手记

2016-03-22-信息系统实践手记3-按业务展开的代码剥离

ABP开发手记2 - 体系架构

信息系统实践手记3-按业务展开的代码剥离