configure_file(
<input> <output>
[COPYONLY]
[ESCAPE_QUOTES]
[@ONLY]
[NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ]
COPYONLY:
只拷贝文件,不进行任何的变量替换。这个选项在指定了 NEWLINE_STYLE 选项时不能使用(无效)。
ESCAPE_QUOTES:
躲过任何的反斜杠(C风格)转义。躲避转义,比如你有个变量在CMake中是这样的 set(FOO_STRING “"foo"”) 那么在没有 ESCAPE_QUOTES 选项的状态下,通过变量替换将变为 "foo"
,如果指定了 ESCAPE_QUOTES 选项,变量将不变。
@ONLY:
限制变量替换:,让其只替换被 @VAR@ 引用的变量(那么 ${VAR}格式的变量将不会被替换)。这在配置 ${VAR} 语法的脚本时是非常有用的。
NEWLINE_STYLE:
指定输出文件中的新行格式。UNIX 和 LF 的新行是 \n ,DOS 和 WIN32 和 CRLF 的新行格式是 \r\n 。 这个选项在指定了 COPYONLY 选项时不能使用(无效)。
8.2 在CMake对文件的操作
8.2.1 file命令:
file(WRITE filename “message to write”… ):
WRITE选项会写一条消息到名为filename中,如果文件存在,则会覆盖原文件,如果文件不存在,他将创建该文件。
file(APPEND filename “message to write”… ):
APPEND选项和WRITE选项一样,只是APPEND会写到文件的末尾。
file(READ filename variable [LIMIT numBytes] [OFFSET offset] [HEX]):
READ选项会将读取的文件内容存放到变量variable,读取numBytes个字节,从offset位置开始,如果指定了[HEX]参数,二进制代码就会转换为十六进制的转换方式。
file(STRINGS filename variable [LIMIT_COUNT num] [LIMIT_INPUT numBytes] [LIMIT_OUTPUT numBytes] [LENGTH_MINIMUM numBytes] [LENGTH_MAXIMUM numBytes] [NEWLINE_CONSUME] [REGEX regex] [NO_HEX_CONVERSION]):
STRINGS标志,将会从一个文件中将ASCII字符串的list解析出来,然后储存在variable 变量中,文件中的二进制数据将会被忽略,回车换行符会被忽略(可以设置NO_HEX_CONVERSION选项来禁止这个功能)。LIMIT_COUNT:设定了返回字符串的最大数量;LIMIT_INPUT:设置了从输入文件中读取的最大字节数;LIMIT_OUTPUT:设置了在输出变量中允许存储的最大字节数;LENGTH_MINIMUM:设置了返回字符串的最小长度,小于该长度的字符串将会被忽略;LENGTH_MAXIMUM设置了返回字符串的最大长度,大于该长度的字符串将会被忽略;NEWLINE_CONSUME:该标志允许新行被包含到字符串中,而不是终止他们;REGEX:指定了返回的字符串必须满足的正则表达式。例如:file(STRINGS myfile.txt myfile)
,将myfile.txt中的文本按行存储到myfile这个变量中。
file(GLOB variable [RELATIVE path] [globbing expressions]…)
GLOB:该选项将会为所有匹配表达式的文件生成一个文件list,并将该list存放在variable 里面,文件名的查询表达式和正则表达式类似,匹配和正则表达式相似。
file(GLOB_RECURSE variable [RELATIVE path] [FOLLOW_SYMLINKS] [globbing expressions]…)
GLOB_RECURSE会生成一个类似于通常GLOB选项的list,不过该选项可以递归查找文件中的匹配项。例如:/dir/*.py -就会匹配所有在/dir文件下面的python文件。
file(RENAME )
RENAME选项对同一个文件系统下的一个文件或目录重命名。
file(REMOVE [file1 …])
REMOVE选项将会删除指定的文件,包括在子路径下的文件。
file(REMOVE_RECURSE [file1 …])
REMOVE_RECURSE选项会删除给定的文件以及目录,包括非空目录
file(MAKE_DIRECTORY [directory1 directory2 …])
MAKE_DIRECTORY选项将会创建指定的目录,如果它们的父目录不存在时,同样也会创建。
file(RELATIVE_PATH variable directory file)
RELATIVE_PATH选项会确定从direcroty参数到指定文件的相对路径,然后存到变量variable中。
file(TO_CMAKE_PATH path result)
TO_CMAKE_PATH选项会把path转换为一个以unix的 / 开头的cmake风格的路径
file(TO_NATIVE_PATH path result)
TO_NATIVE_PATH选项与TO_CMAKE_PATH选项很相似,但是它会把cmake风格的路径转换为本地路径风格
file(DOWNLOAD url file [TIMEOUT timeout] [STATUS status] [LOG log] [EXPECTED_MD5 sum] [SHOW_PROGRESS])
DOWNLOAD将给定的url下载到指定的文件中,如果指定了LOG log,下载的日志将会被输出到log中,如果指定了STATUS status选项下载操作的状态就会被输出到status里面,该状态的返回值是一个长度为2的list,list第一个元素是操作的返回值,是一个数字 ,第二个返回值是错误的字符串,错误信息如果是0,就表示没有错误;如果指定了TIMEOUT time选项,time秒之后,操作就会推出。如果指定了EXPECTED_MD5 sum选项,下载操作会认证下载的文件的实际MD5和是否与期望值相匹配,如果不匹配,操作将返回一个错误;如果指定了SHOW_PROGRESS,进度信息会被打印出来,直到操作完成。
8.2.2 source_group命令
使用该命令可以将文件在VS中进行分组显示;source_group("Header Files" FILES ${HEADER_FILES})
;以上命令是将变量HEADER_FILES里面的文件,在VS显示的时候都显示在“Header Files”选项下面
9 如何构建项目
使用include直接包含指定的文件,文件后缀名相关性不大,也可以使用add_subdirectories()来添加子文件夹,但是要求子文件夹中存在对应的CMakeList.txt文件。
存在项目目录如下:
project_dir
lib文件夹
libA.c
libB.c
CMakeLists.txt
include文件夹
includeA.h
inclueeB.h
CMakeLists.txt
main.c
CMakeLists.txt
cmake_minium_required(VERSION 2.8)
#将当前目录下的源文件名都赋给DIR_SRC目录
aux_source_directories(. DIR_SRC)
#添加include目录
include_directories(include)
#生成可执行文件
add_executable(main ${DIR_SRC})
#添加子目录
add_subdirectories(lib)
#将生成的文件与动态库相连
target_link_libraries(main test)
#test是lib目录里面生成的
lib目录下的CMakeLists
#将当前的源文件名字都添加到DIR_LIB变量下
aux_source_director(. DIR_LIB)
#生成库文件命名为
testadd_libraries(test ${DIR_LIB})
10 运行其它程序
CMakeLists.txt中可以使用execute_process
来运行系统中的程序。
execute_process(
[COMMAND <cmd1> [args1...]]
[COMMAND <cmd2> [args2...] [...]]
[WORKING_DIRECTORY <directory>]
[TIMEOUT <seconds>]
[RESULT_VARIABLE <variable>]
[OUTPUT_VARIABLE <variable>]
[ERROR_VARIABLE <variable>]
[INPUT_FILE <file>]
[OUTPUT_FILE <file>]
[ERROR_FILE <file>]
[OUTPUT_QUIET]
[ERROR_QUIET]
[OUTPUT_STRIP_TRAILING_WHITESPACE]
[ERROR_STRIP_TRAILING_WHITESPACE]
COMMAND
:子进程的命令行,CMake使用操作系统的API直接执行子进程,所有的参数逐字传输,没有中间脚本参与,像“>”的输出重定向也会被直接的传输到子进程里面,当做普通的参数进行处理。
WORKING_DIRECTORY
:指定的工作目录将会设置为子进程的工作目录
TIMEOUT
:子进程如果在指定的秒数之内没有结束就会被中断
RESULT_VARIABLE
:变量被设置为包含子进程的运算结果,也就是命令执行的最后结果将会保存在这个变量之中,返回码将是来自最后一个子进程的整数或者一个错误描述字符串
OUTPUT_VARIABLE
、ERROR_VARIABLE
:输出变量和错误变量
INPUT_FILE
、OUTPUT_FILE
、ERROR_FILE
:输入文件、输出文件、错误文件
OUTPUT_QUIET
、ERROR_QUIET
:输出忽略、错误忽略,标准输出和标准错误的结果将被默认忽略.
使用示例:
set(MAKE_CMD "/src/bin/make.bat")
MESSAGE("COMMAND: ${MAKE_CMD}")
execute_process(
COMMAND "${MAKE_CMD}"
RESULT_VARIABLE
CMD_ERROR OUTPUT_FILE CMD_OUTPUT
MESSAGE(
STATUS "CMD_ERROR:"
${CMD_ERROR}
MESSAGE(
STATUS
"CMD_OUTPUT:"
${CMD_OUTPUT}
#输出:COMMAND:/src/bin/make.batCMD_ERROR:No such file or directoryCMD_OUTPUT:(因为这个路径下面没有这个文件)
11 find_package() 查找链接库函数
11.1 find_package()命令查找***.cmake的顺序。
find_package()会优先从CMAKE_MODULE_PATH中寻找FindXXX.cmake来进行寻找。这种模式也成为Model模式。CMAKE_MODULE_PATH是cmake预先定义,但是一般没有值,一旦赋值则按照最先优先级去寻找。
因此我们可以通过set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)来进行添加,比较建议的做法是LIST(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake_modules)
这样解可以在多个列表后面直接添加。
如果没有在CMAKE_MODULE_PATH找到,就会在../.cmake/packages
或者../uesr/local/share/
中的包目录中查找:Config.cmake或者-config.cmake。这种查找模式称作Config模式。库名字小写>库名字大写>
无论那种方式只要找到XXXX.cmake文件,里面都会定义下面这些变量
<NAME>_FOUND<NAME>_INCLUDE_DIRS
<NAME>_INCLUDES<NAME>_LIBRARIES
<NAME>_LIBRARIES
<NAME>_LIBS<NAME>_DEFINITIONS
然后就可以使用include_directories(<Name>_INCLUDE_DIRS)
来包含库的头文件。使用:link_libraries(<NAME>_LIBRARIES)
来链接动态库。
可以使用cmake --help-module-list
命令来查看当前cmake支持的模块。
11.2 find_package()的命令参数
FIND_PACKAGE(
[version]
[EXACT]
[QUIET]
[NO_MODULE]
[ [ REQUIRED | COMPONENTS ] [ componets... ] ]
version:需要一个版本号,给出这个参数而没有给出EXACT,那个就是找到和给出的这个版本号相互兼容就符合条件。
EXACT:要求版本号必须和version给出的精确匹配。没有指定时只要兼容就不会报错,但是当指定后不符合就会报错,因此建议使用版本范围。如:
find_package(OpenCV 3.0 QUIET)
if(NOT OpenCV_FOUND)
find_package(OpenCV 2.4.3 QUIET)
if(NOT OpenCV_FOUND)
message(FATAL_ERROR "OpenCV > 2.4.3 not found.")
endif()
endif()
QUIET:会禁掉查找的包没有被发现的警告信息。对应于Find.cmake模块里面的的NAME_FIND_QUIETLY变量。
NO_MODULE:给出该指令之后,cmake将直接跳过Module模式的查找,直接使用Config模式查找。
COMPONENTS: 有些库不是一个整体比如Qt,其中还包含QtOpenGL和QtXml组件,当我们需要使用库的组件的时候,就使用COMPONENTS这个选项.
11.3 编写find模块。
find模块的编写流程
使用:find_path和find_library查找模块的头文件以及库文件,然后将结果放到_INCLUDE_DIR和_LIBRARY里面。
设置:<NAME>_INCLUDE_DIRS
为<NAME>_INCLUDE_DIR<dependency1>_INCLUDE_DIRS ...
设置 <name>_LIBRARIES
为 <name>_LIBRARY <dependency1>_LIBRARIES ...
调用宏 find_package_handle_standard_args() 设置 <name>_FOUND
并打印或失败信息。
find_path函数使用方式为:
find_path(<VAR> name1 [path1 path2 ...])
该命令搜索包含某个文件的路径,用于给定名字的文件坐在路径。的cache将会被创建。在路径中找到文件就存到变量中。除非变量被清除否则,搜索不会继续进行(者也是cmake配置错误需要删除cache的原因)。如果没有发现该文件就在里面存储`-NOTFOUND`
下面是一个FindBZip2.cmake模块的简单示例:
#.rst:
# FindBZip2
# ---------
# Try to find BZip2
# Once done this will define
# BZIP2_FOUND - system has BZip2
# BZIP2_INCLUDE_DIR - the BZip2 include directory
# BZIP2_LIBRARIES - Link these to use BZip2
# BZIP2_NEED_PREFIX - this is set if the functions are prefixed with BZ2_
# BZIP2_VERSION_STRING - the version of BZip2 found (since CMake 2.8.8)
#=============================================================================
# Distributed under the OSI-approved BSD License (the "License");
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
#设置_BZIP2_PATHS
set(_BZIP2_PATHS PATHS
"[HKEY_LOCAL_MACHINE\SOFTWARE\GnuWin32\Bzip2;InstallPath]"
#查找文件路径并保存到变量BZIP2_INCLUDE_DIR中
find_path(BZIP2_INCLUDE_DIR bzlib.h ${_BZIP2_PATHS} PATH_SUFFIXES include)
#如果没有定义BZIP2_LIBRARIES,进行查找
if (NOT BZIP2_LIBRARIES)
find_library(BZIP2_LIBRARY_RELEASE NAMES bz2 bzip2 ${_BZIP2_PATHS} PATH_SUFFIXES lib)
find_library(BZIP2_LIBRARY_DEBUG NAMES bzip2d ${_BZIP2_PATHS} PATH_SUFFIXES lib)
include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
SELECT_LIBRARY_CONFIGURATIONS(BZIP2)
endif ()
#include文件存在,进行正则匹配查找文件名中的版本信息。
if (BZIP2_INCLUDE_DIR AND EXISTS "${BZIP2_INCLUDE_DIR}/bzlib.h")
file(STRINGS "${BZIP2_INCLUDE_DIR}/bzlib.h" BZLIB_H REGEX "bzip2/libbzip2 version [0-9]+\.[^ ]+ of [0-9]+ ")
string(REGEX REPLACE ".* bzip2/libbzip2 version ([0-9]+\.[^ ]+) of [0-9]+ .*" "" BZIP2_VERSION_STRING "${BZLIB_H}")
endif ()
# handle the QUIETLY and REQUIRED arguments and set BZip2_FOUND to TRUE if
# all listed variables are TRUE
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
#答应获取的相关信息
FIND_PACKAGE_HANDLE_STANDARD_ARGS(BZip2
REQUIRED_VARS BZIP2_LIBRARIES BZIP2_INCLUDE_DIR
VERSION_VAR BZIP2_VERSION_STRING)
#如果找到了
if (BZIP2_FOUND)
include(${CMAKE_CURRENT_LIST_DIR}/CheckSymbolExists.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)
#确认cmake状态
cmake_push_check_state()
//设置CMAKE_REQUIRED_QUIET无错误的找到
set(CMAKE_REQUIRED_QUIET ${BZip2_FIND_QUIETLY})
set(CMAKE_REQUIRED_INCLUDES ${BZIP2_INCLUDE_DIR})
set(CMAKE_REQUIRED_LIBRARIES ${BZIP2_LIBRARIES})
CHECK_SYMBOL_EXISTS(BZ2_bzCompressInit "bzlib.h" BZIP2_NEED_PREFIX)
cmake_pop_check_state()
endif ()
#这个主要是给cmake-gui进行使用的
mark_as_advanced(BZIP2_INCLUDE_DIR)
cmake_minimum_required(VERSION 2.8)
project(helloword)
add_executable(hello main.c)
find_package(BZip2)
#如果查找成功BZIP2_FOUND会被设置成为1
if(BZIP2_FOUND)
include_directories(${BZIP2_INCLUDE_DIRS})
target_link_libraries(hello ${BZIP_LIBRARIES})
endif(BZIP_FOUND)
12 自定义内容
12.1 add_custom_command 为某一个工程添加一个自定义的命令
参考链接: 各平台编译器中的Pre-build及Post-build操作
add_custom_command(TARGET target
PRE_BUILD | PRE_LINK| POST_BUILD
COMMAND command1[ARGS] [args1...]
[COMMAND command2[ARGS] [args2...] ...]
[WORKING_DIRECTORYdir]
[COMMENT comment][VERBATIM]
执行命令的时间由第二个参数决定:
PRE_BUILD - 命令将会在其他依赖项执行前执行。
PRE_LINK - 命令将会在其他依赖项执行完后执行。
POST_BUILD - 命令将会在目标构建完后执行。
add_custom_command(
TARGET ${PROJECT_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E sleep 5
#目标就是TARGET后面跟的工程,当PROJECT_NAME被生成的时候就会执行COMMAND后面的命令。
add_custom_command(
TARGET test_elf
PRE_BUILD
COMMAND
move E:/cfg/start.o ${CMAKE_BINARY_DIR}/. &&
#在test_el执行依赖之前,将start.o文件复制到编译目录
12.2 add_custom_command:(2)添加自定义命令来产生一个输出
参数格式:
add_custom_command(
OUTPUT output1 [output2 ...]
COMMAND command1[ARGS] [args1...]
[COMMAND command2 [ARGS] [args2...] ...]
[MAIN_DEPENDENCYdepend]
[DEPENDS[depends...]]
[IMPLICIT_DEPENDS<lang1> depend1 ...]
[WORKING_DIRECTORYdir]
[COMMENT comment] [VERBATIM] [APPEND]
参数解析:
其中ARGS选项 是为了向后兼容,MAIN_DEPENDENCY选项是针对VisualStudio给出一个建议,这两选项可以忽略。
COMMAND:指定一些在构建阶段执行的命令。如果指定了多于一条的命令,他会按照顺序去执行。如果指定了一个可执行目标的名字(被add_executable()命令创建),他会自动被在构建阶段创建的可执行文件的路径替换。
DEPENDS:指定目标依赖的文件,如果依赖的文件是和CMakeLists.txt相同目录的文件,则命令就会在CMakeLists.txt文件的,目录执行。如果没有指定DEPENDS,则只要缺少OUTPUT,该命令就会执行。如果指定的位置和CMAkeLists.txt不是同一位置,会先去创建依赖关系,先去将依赖的目标或者命令先去编译。
WORKING_DIRECTORY:使用给定的当前目录执行命令,如果是相对路径,则相对于当前源目录对应的目录结构进行解析
#首先生成creator的可执行文件
add_executable(creator creator.cxx)
#获取EXE_LOC的LOCATION属性存放到creator里面
get_target_property(creator EXE_LOC LOCATION)
#生成created.c文件
add_custom_command(
OUTPUT ${PROJECT_BINARY_DIR}/created.c
DEPENDS creator
COMMAND ${EXE_LOC}
ARGS ${PROJECT_BINARY_DIR}/created.c
#使用上一步生成的created.c文件来生成Foo可执行文件
add_executable(Foo ${PROJECT_BINARY_DIR}/created.c)
注意:不要在多个相互独立的文件中使用该命令产生相同的文件,放置冲突。
12.3 add_custom_target:增加定制目标。
add_custom_target(
Name [ALL] [command1 [args1...]]
[COMMAND command2 [args2...] ...]
[DEPENDS depend depend depend ... ]
[BYPRODUCTS [files...]]
[WORKING_DIRECTORY dir]
[COMMENT comment]
[VERBATIM] [USES_TERMINAL]
[SOURCES src1 [src2...]]
add_custom_target 可以增加定制目标,常常用于编译文档、运行测试用例等。
12.4 add_custom_command和add_custom_target的区别
命令命名里面的区别就在于:command和target,前者是自定义命令,后者是自定义目标
目标:使用add_custom_target定义的叫做自定义目标,因此这些“目标”区别于正常的目标,他们不生成exe或者lib,但是仍然会具有一些正常目标相同的属性,构建他们的时候,只是调用了为他们设置的命令,如果自定义目标对于其他目标有依赖,那么就会优先生成依赖的那些目标。
自定义命令:自定义命令不是一个“可构建”的对象,并且没有可以设置的属性,自定义命令是一个在构建依赖目标之前被调用的命令,自定义命令的依赖可以通过add_custom_command(TARGET target …)形式显式设置,也可以通过add_custom_command(OUTPUT output1 …)生成文件的形式隐式设置。显示执行的时候,每次构建目标,首先会执行自定义的命令,隐式执行的时候,如果自定义的命令依赖于其他文件,则在构建目标的时候先去执行生成其他文件。
13 C++中的常用选项
参考链接: CMake编译中target_link_libraries中属性PRIVATE、PUBLIC、INTERFACE含义
13.1 C++11功能的激活
使用target_compile_features(<target> <PRIVATE|PUBLIC|INTERFACE> <feature> [...])
添加c++11标准:target_compile_features(<project_name> PUBLIC cxx_std_11)
。
注意:target必须是由:add_executable
或者add_library
生成的目标。
也可以使用下面的方式来进行支持:
#设置c++标准级别
set(CMAKE_CXX_STANDARD 11)
#告诉cmake使用它
set(CMAKE_CXX_STANDARD_REQUIRED ON)
#(可选)确保-std=c++11
13.2 中间过程优化
#检测编译器是否支持过程间优化
check_ipo_supported(RESULT result)
#如果不支持,判断进不去
if(result)
#为工程设置过程间优化
set_target_properties(foo PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
endif()
13.3 cmake中的option
option命令可以设置默认值;例如option(address "this is path for value" ON)
设置address的默认值为ON,并且添加注释提示。
注意:没有设置默认值时,默认的默认值是OFF,如果值已经改变一定要清除CMakeCache.txt。
可以另外当去创建option.txt文件,然后使用include进行包含。
可以使用cmake_dependent_option
设置存在依赖的option ,但是一般建议使用if判断来进行配置。
cmake_dependent_option(DEPENT_USE_CURL "this is dependent on USE_CURL" ON "USE_CURL;NOT USE_MATH" OFF)
#设置一个option:DEPENT_USE_CURL,第二个参数是他的说明,ON后面的参数是一个表达式,当“USE_CURL”且“USE_MATH”为真的时候,DEPENT_USE_CURL取ON,为假取OFF
13.4 属性调试模块(CMakePrintHelpers)
CMAKE_PRINT_PROPERTIES(
[TARGETS target1 .. targetN]
[SOURCES source1 .. sourceN]
[DIRECTORIES dir1 .. dirN]
[TESTS test1 .. testN]
[CACHE_ENTRIES entry1 .. entryN]
PROPERTIES prop1 .. propN
如果要检查foo目标的INTERFACE_INCLUDE_DIRS和LOCATION的值,则执行:
cmake_print_properties(
TARGETS foo
PROPERTIES
INTERFACE_INCLUDE_DIRS
LOCATION