CMake提供了各种前端操作的客户端,各平台上的命令行客户端和GUI客户端。先主要看一下命令行操作的方法。
一、简单步骤
0、项目准备:项目的每个目录下都需要有CMakeLists.txt(名字区分大小写)文件
1、cd /path/to/build。#在build目录下运行cmake,因为cmake把当前目录作为build目录,存放生成文件和cache文件
2、cmake /path/to/project。
3、make。#该命令的输入项是位于/path/to/project的CMakeLists.tx文件,该文件可以通过include或add_subdirectory命令添加新的输入文件。
4、./target。#运行生成的程序
5、清理target:make clean。但是make distclean无效,无法清理构建过程文件。所以才在第一步中先进入build目录,这就是所谓的外部构建(out-of-source build)。
二、CMakeLists.txt语法
0、通用规则:
a #开头的行为注释行。
b 指令(参数1 参数2...) 参数使用括弧括起,参数之间使用空格或分号 分开,参数可使用双引号包着SET(SRC_LIST “main.c”)。指令是大小写无关的,参数和变量是大小写相关的。但,推荐指令全部使用大写。
c 变量使用${}方式取值,但是在 IF 控制语句中是直接使用变量名
d /字符用作转义字符。
e 用户可以自定义macro和function,用法同command指令
1、变量类型:Lists and Strings
a 变量的基本类型是String
b 变量也可以是list类型。list可被foreach命令枚举、list命令操作。定义list方法如下:
2、流程控制
a 条件判断:if
# some_command will be called if the variable's value is not:
# empty, 0, N, NO, OFF, FALSE, NOTFOUND, or -NOTFOUND.
if(var)
some_command(...)
elseif(var)
other_command(...)
else(var)
last_option(...)
endif(var)
b 循环:foreach
set(VAR a b c) # loop over a, b,c with the variable f foreach(f ${VAR}) message(${f}) endforeach(f)
c 循环:while
while(var) message(${var}) endwhile(var)
d 过程定义:macro 和 function
函数在2.6及以上版本才支持,函数和宏的区别在于函数中可定义局部变量,而宏定义的变量都是全局变量,或者应该是函数是局部的,宏是全局的。
# define a macro hello macro(hello MESSAGE) message(${MESSAGE}) endmacro(hello) # call the macro with the string "hello world" hello("hello world") # define a function hello function(hello MESSAGE) message(${MESSAGE}) endfunction(hello)
3、支持正则表达式
^ Matches at beginning of a line or string
$ Matches at end of a line or string
. Matches any single character other than a newline
[ ] Matches any character(s) inside the brackets
[^ ] Matches any character(s) not inside the brackets
[-] Matches any character in range on either side of a dash
* Matches preceding pattern zero or more times
+ Matches preceding pattern one or more times
? Matches preceding pattern zero or once only
() Saves a matched expression and uses it in a later replacement
三、命令API
虽然说Kitware有点儿不厚道的在卖Mastering CMake 这本书,而且貌似网上没有电子版,但是官方提供的文档 还是够用的。在写这篇心得时cmake是2.8版本。
文档也可以通过“cmake --help-html > help_name.html”在当前运行目录生成。
四、使用技巧
1、如何在构建过程中打印debug等信息到console?
使用MESSAGE命令。message([STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR] "message to display" ...)
2、过程文件和最终构建的目标文件的路径设置问题。
cmake有一些预定义的变量来设置各种路径。
PROJECT_BINARY_DIR:运行目录,生成过程文件的目录。运行cmake ..的工作目录。这个目录总会有些过程文件生成,因此需要外部构建。
PROJECT_SOURCE_DIR:代码目录,运行cmake ..时..指定的目录
工程组织方式:
proj + | +src +bin +build | + bin_1 +CMakeLists.txt
一般在CMakeLists.txt文件中用ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])指定src、bin目录,可以用相对路径也可以用绝对路径。
但 是要注意,如果用相对路径的话,source_dir是相对PROJECT_SOURCE_DIR(这里是proj目录)的,binary_dir是相对 PROJECT_BINARY_DIR(这里是build)的。所以如果是add_subdirectory(src bin)的话,bin是build下面的bin_1。
EXECUTABLE_OUTPUT_PATH 和 LIBRARY_OUTPUT_PATH 定义纯净的最终目标文件位置,可以通过下面方法修改
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
1、预定义变量
PROJECT_BINARY_DIR
PROJECT_SOURCE_DIR
EXECUTABLE_OUTPUT_PATH
LIBRARY_OUTPUT_PATH
CMAKE_INSTALL_PREFIX
2、基本指令
PROJECT(projectname [CXX] [C] [Java])
SET(VAR [VALUE [VALUE2] [VALUE3]] [CACHE TYPE DOCSTRING [FORCE]])
MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] "message to display" ...)
ADD_EXECUTABLE(targetRunable ${SRC_LIST})
ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
目录的安装:INSTALL(DIRECTORY src_dirs... DESTINATION <dir>
[FILE_PERMISSIONS permissions...]
[DIRECTORY_PERMISSIONS permissions...]
[USE_SOURCE_PERMISSIONS]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[[PATTERN <pattern> | REGEX <regex>] [EXCLUDE] [PERMISSIONS permissions...]][...])
DIRECTORY 后面连接的src_dirs注意abc 和 abc/有很大的区别。如果目录名不以/结尾,那么这个目录将被安装为目标路径下的 abc,如果目录名以/结尾, 代表将这个目录中的内容安装到目标路径,但不包括这个目录本身。
3、换个地方保存目标二进制:在 ADD_EXECUTABLE 或 ADD_LIBRARY所在的CMakeLists.txt文件里面定义
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)