cmake中CMakeLists.txt脚本的常用语法


在不同的平台编译的时候,会用到一些系统内置的变量,比如操作系统名称,版本号之类:
CMAKE_SYSTEM:系統全名,如 “Linux-2.4.22″,”FreeBSD-5.4-RELEASE” 或 “Windows 5.1”
CMAKE_SYSTEM_NAME:系統名称,如 “Linux”, “FreeBSD” or “Windows”,注意大小写
CMAKE_SYSTEM_VERSION:只显示系统全名中的版本部分
CMAKE_SYSTEM_PROCESSOR:CPU名称

1、option指令

option 提供一个用户可以任选的选项。语法如下
option( "help string describing option"
            [initial value])

option 提供选项让用户选择是 ON 或者 OFF ,如果没有提供初始化值,使用OFF。也就是说默认的值是OFF。
但是请注意:这个option命令和你本地是否存在编译缓存的关系很大。所以,如果你有关于 option 的改变,那么、
请你务必清理 CMakeCache.txt 和 CMakeFiles 文件夹。还有,请使用标准的 [initial value] 值 ON 或者 OFF。

2、include指令

用来载入CMakeLists.txt文件,也用于载入预定义的cmake模块。
INCLUDE(file1[OPTIONAL])
INCLUDE(module[OPTIONAL])
OPTIONAL参数的作用是文件不存在也不会产生错误,可以指定载入一个文件,如果定义的是一个模块,那么将在
CMAKE_MODULE_PATH中搜索这个模块并载入, 载入的内容将在处理到INCLUDE语句是直接执行。

3、控制指令

(1)、IF指令,基本语法为:
IF(expression_r_r)
    #THEN section.
    COMMAND1(ARGS…)
    COMMAND2(ARGS…)
    …
ELSE(expression_r_r)
    #ELSE section.
    COMMAND1(ARGS…)
    COMMAND2(ARGS…)
    …
ENDIF(expression_r_r)
另外一个指令是ELSEIF,总体把握一个原则,凡是出现IF的地方一定要有对应的ENDIF,出现ELSEIF的地方,
ENDIF是可选的。表达式的使用方法如下:
IF(var)  如果变量不是:空, 0, N, NO, OFF, FALSE, NOTFOUND 或 _NOTFOUND时,表达式为真。
IF(NOT var), 与上述条件相反。
IF(var1	AND var2), 当两个变量都为真是为真。
IF(var1	OR var2), 当两个变量其中一个为真时为真。
IF(COMM	AND	cmd), 当给定的cmd确实是命令并可以调用是为真。
IF(EXISTS dir) or IF(EXISTS file), 当目录名或者文件名存在时为真。
IF(file1 IS_NEWER_THAN file2), 当file1比file2新,或者file1/file2其中有一个不存在时为真文件名请使用完整路径。
IF(IS_DIRECTORY dirname),  当dirname是目录时为真。
IF(variable MATCHES regex)
IF(string MATCHES regex) 当给定的变量或者字符串能够匹配正则表达式regex时为真。比如:
IF("hello" MATCHES "hello")
    MESSAGE("true")
ENDIF("hello" MATCHES "hello")
数字比较表达式
IF(variable LESS number)
IF(string LESS number)
IF(variable GREATER number)
IF(string GREATER number)
IF(variable EQUAL number)
IF(string EQUAL number)
按照字母序的排列进行比较
IF(variable STRLESS string)
IF(string STRLESS string)
IF(variable STRGREATER string)
IF(string STRGREATER string)
IF(variable STREQUAL string)
IF(string STREQUAL string)
IF(DEFINED variable),如果变量被定义,为真。
一个小例子,用来判断平台差异:
IF(WIN32)
    MESSAGE(STATUS“This is windows.”) #作一些Windows相关的操作
ELSE(WIN32)
    MESSAGE(STATUS“This is not windows”) #作一些非Windows相关的操作
ENDIF(WIN32)
上述代码用来控制在不同的平台进行不同的控制,但是阅读起来却并不是那么舒服, ELSE(WIN32)之类的语句很容易引起歧义。 
这就用到了我们在 常用变量 一节提到的CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS开关。可以
SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTSON), 这时候就可以写成:
IF(WIN32)

ELSE()

ENDIF()
如果配合ELSEIF使用,可能的写法是这样:
IF(WIN32)
    #dosomething related to WIN32
ELSEIF(UNIX)
    #dosomething related to UNIX
ELSEIF(APPLE)
    #dosomething related to APPLE
ENDIF(WIN32)

4、find_path搜索包含某个文件的路径

 find_path( name1 [path1 path2 ...])
  在多数情况下,使用上述的精简命令格式就足够了。它与命令find_path( name1 [PATHS path1 path2 ...])等价。
  find_path(
             
             name | NAMES name1 [name2 ...]
             [HINTS path1 [path2 ... ENV var]]
             [PATHS path1 [path2 ... ENV var]]
             [PATH_SUFFIXES suffix1 [suffix2 ...]]
             [DOC "cache documentation string"]
             [NO_DEFAULT_PATH]
             [NO_CMAKE_ENVIRONMENT_PATH]
             [NO_CMAKE_PATH]
             [NO_SYSTEM_ENVIRONMENT_PATH]
             [NO_CMAKE_SYSTEM_PATH]
             [CMAKE_FIND_ROOT_PATH_BOTH |
              ONLY_CMAKE_FIND_ROOT_PATH |
              NO_CMAKE_FIND_ROOT_PATH]
            )

该命令用于给定名字文件所在的路径。一条名为的cache条目会被创建,并存储该命令的执行结果。
如果在某个路径下发现了该文件,该结果会被存储到该变量中;除非该变量被清除,该次搜索不会继续
进行。如果没有找到,存储的结果将会是-NOTFOUND,并且当下一次以相同的变量名调用find_path
命令时,该命令会再一次尝试搜索该文件。需要搜索的文件名通过在NAMES选项后面的列出来的参数来确
定。附加的搜索位置可以在PATHS选项之后指定。如果在PATHS或者HINTS命令中还指定了ENV var选项,
环境变量var将会被读取并从一个系统环境变量转换为一个cmake风格的路径list。比如,ENV PATH是
列出系统path变量的一种方法。参数DOC将用来作为该变量在cache中的注释。PATH_SUFFIXES指定了在
每个搜索路径下的附加子路径。

5、find_program 查找可执行程序

find_program( name1 [path1 path2 ...])
这是该命令的精简格式,它在大多数场合下都够用了。命令find_program( name1 [PATHS path1 path2 ...])是它的等价形式。

   find_program(
             
             name | NAMES name1 [name2 ...]
             [HINTS path1 [path2 ... ENV var]]
             [PATHS path1 [path2 ... ENV var]]
             [PATH_SUFFIXES suffix1 [suffix2 ...]]
             [DOC "cache documentation string"]
             [NO_DEFAULT_PATH]
             [NO_CMAKE_ENVIRONMENT_PATH]
             [NO_CMAKE_PATH]
             [NO_SYSTEM_ENVIRONMENT_PATH]
             [NO_CMAKE_SYSTEM_PATH]
             [CMAKE_FIND_ROOT_PATH_BOTH |
              ONLY_CMAKE_FIND_ROOT_PATH |
              NO_CMAKE_FIND_ROOT_PATH]
            )

该命令用于查找程序。一个名为的cache条目会被创建用来存储该命令的结果。如果该程
序被找到了,结果会存储在该变量中,搜索过程将不会再重复,除非该变量被清除。如果没有找到,
结果将会是-NOTFOUND,并且下次以相同的变量调用该命令时,还会做搜索的尝试。被搜索的
程序的名字由NAMES选项后列出的参数指定。附加的搜索位置可以在PATHS参数后指定。如果在HINTS
或者PATHS选项后有ENV var参数,环境变量var将会被读取并从系统环境变量转换为cmake风格的路
径list。比如ENV PATH是一种列出所有系统path变量的方法。DOC后的参数将会被用作cache中的注
释字符串。PATH_SUFFIXES指定了在每个搜索路径下要检查的附加子路径。



6、ADD_DEFINITIONS

向C/C++编译器添加-D定义
ADD_DEFINITIONS(-DENABLE_DEBUG -DABC),参数之间用空格分隔


7、file命令 

file(MAKE_DIRECTORY [directory1 directory2 ...])
MAKE_DIRECTORY在指定目录处创建子目录,如果它们的父目录不存在,也会创建它们的父目录。

file(GLOB variable [RELATIVE path] [globbing expressions]...)

注意GLOB这个参数,它不支持子目录。如果你想让它支持子目录,用GLOB_RECURSE。


8、add_custom_command

add_custom_command 为生成的构建系统添加一条自定义的构建规则
add_custom_command命令有两种主要的功能;第一种是为了生成输出文件,添加一条自定义命令。
add_custom_command(OUTPUT output1 [output2 ...]
                     COMMAND command1 [ARGS] [args1...]
                     [COMMAND command2 [ARGS] [args2...] ...]
                     [MAIN_DEPENDENCY depend]
                     [DEPENDS [depends...]]
                     [IMPLICIT_DEPENDS  depend1 ...]
                     [WORKING_DIRECTORY dir]
                     [COMMENT comment] [VERBATIM] [APPEND])
这种命令格式定义了一条生成指定的文件(文件组)的生成命令。在相同路径下创建的目标
(CMakeLists.txt文件)——任何自定义命令的输出都作为它的源文件——被设置了一条规则:在构
建的时候,使用指定的命令来生成这些文件。如果一个输出文件名是相对路径,它将被解释成相
对于构建树路径的相对路径,并且与当前源码路径是对应的。注意,MAIN_DEPENDENCY完全是可选

的,它用来向visual studio建议在何处停止自定义命令。


第二种格式为一个目标——比如一个库文件或者可执行文件——添加一条自定义命令。这种格式
可以用于目标构建前或构建后的一些操作。这条命令会成为目标的一部分,并且只有目标被构建

时才会执行。如果目标已经构建了,该目标将不会执行。

  add_custom_command(TARGET target
                     PRE_BUILD | PRE_LINK | POST_BUILD
                     COMMAND command1 [ARGS] [args1...]
                     [COMMAND command2 [ARGS] [args2...] ...]
                     [WORKING_DIRECTORY dir]
                     [COMMENT comment] [VERBATIM])
这条命令定义了一个与指定目标的构建过程相关的新命令。新命令在何时执行,由下述的选项决定:

PRE_BUILD  - 在所有其它的依赖之前执行;
PRE_LINK   - 在所有其它的依赖之后执行;
POST_BUILD - 在目标被构建之后执行;

9、FOREACH指令

FOREACH指令的使用方法有三种形式:

(1)、列表

FOREACH(loop_var arg1 arg2...)
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
ENDFOREACH(loop_var)

像我们前面使用的AUX_SOURCE_DIRECTORY的例子

AUX_SOURCE_DIRECTORY(. SRC_LIST)
FOREACH(F ${SRC_LIST})
MESSAGE(${F})
ENDFOREACH(F)
(2)、范围

FOREACH(loop_var RANGE total)
ENDFOREACH(loop_var)
从0到total以1为步进举例如下:
FOREACH(VAR RANGE 10)
MESSAGE(${VAR})
ENDFOREACH(VAR)
最终得到的输出是:0-10

(3)、范围和步进

FOREACH(loop_var RANGE start stop [step])
ENDFOREACH(loop_var)
从start开始到stop结束,以step为步进,举例如下
FOREACH(A RANGE 5 15 3)
MESSAGE(${A})
ENDFOREACH(A)
最终得到的结果是:
5
8
11
14
这个指令需要注意的是,直到遇到ENDFOREACH指令,整个语句块才会得到真正的执行。

10、list指令

list(LENGTH )
  list(GET   [ ...]
       )
  list(APPEND  [ ...])
  list(FIND  )
  list(INSERT   [ ...])
  list(REMOVE_ITEM  [ ...])
  list(REMOVE_AT  [ ...])
  list(REMOVE_DUPLICATES )
  list(REVERSE )
  list(SORT )

LENGTH返回列表的长度
GET返回列表中指定下标的元素
APPEND添加新元素到列表中
INSERT 将新元素插入到列表中指定的位置
REMOVE_ITEM从列表中删除某个元素
REMOVE_AT从列表中删除指定下标的元素
REMOVE_DUPLICATES从列表中删除重复的元素
REVERSE 将列表的内容实地反转,改变的是列表本身,而不是其副本
SORT 将列表按字母顺序实地排序,改变的是列表本身,而不是其副本


11、source_group

CMake 的 SOURCE_GROUP 用来在 Visual Studio IDE 中对文件进行分组,当工程比较大、文件数目多时特别有意义。

在根CMakeLists.txt下开启显示目录选项。就是以下命令:
 # dispaly folder in MSVS
 SET_PROPERTY(GLOBAL PROPERTY USE_FOLDERS ON) 
这个是必须的,否者就不会显示目录结构。

(1)、手动组织目录

如果想要构建一个好的项目解决方案,那么非常有必要手工组织代码的结构。
1>、对于有编译目标的单元
(即有ADD_EXECUTABLE或者ADD_LIBRARY),那么我们通过一下命令可以把这个编译单元放到
某个目录下:
 SET_PROPERTY(TARGET trivial PROPERTY FOLDER "libraries")  
如上,SET_PPRPERTY第一个参数TARGET是固定值,第二个trivial就是编译单元的名称,
第三个PROPERTY,第四个FOLDER都是固定值,第五个libiraries是要放到的目录下。
目录支持层级结构,这里用/来划分层级结构,如libraries/cnn。

2>、对于无编译目标的单元(比如按功能区分的头文件),使用以下命令来使得其在MSVS显示中能够分组:
 SOURCE_GROUP("lookup_table" FILES ${lookup_table_headers} ${lookup_table_srcs})
SOURCE_GROUP第一个参数同样是目录路径,路径可以是层级的,用\\双反斜杠表示,如
trivial\\lookup_table就是在trivial文件夹下有lookup_table;第二个参数是FILES固定值,
后面的参数就是具体的FILES路径(文件)。经过测试,发现对于有编译目标的单元,使用
SOURCE_GROUP没有作用,实际在MSVS显示时都是以编译目标中的依赖项分组为头文件和源文
件的。但是对于没有编译目标的文件,可以用这个方式来组织。因为如果我们不组织的话,
那么显示的时候就是flat的结构,在文件系统中的目录层级就消失了。

https://stackoverflow.com/questions/31652255/source-group-cmake-command-isnt-working
https://gitlab.cip.ifi.lmu.de/hofero/vr/blob/80955302fc2697babcb184eaf8205ffc38ba7939/portaudio/CMakeLists.txt

12、set_source_files_properties

Source files can have properties that affect how they are built.
set_source_files_properties([file1 [file2 [...]]]
                            PROPERTIES prop1 value1
                            [prop2 value2 [...]])

Set properties associated with source files using a key/value paired list. 
See Properties on Source Files for the list of properties known to CMake. 
Source file properties are visible only to targets added in the same directory (CMakeLists.txt).





target_link_libraries
add_library
set_target_properties
add_executable



参考网址:http://www.cnblogs.com/coderfenghc/archive/2012/06/19/2555388.html
参考网址:http://www.cnblogs.com/coderfenghc/archive/2012/07/08/2581734.html
参考网址:http://blog.csdn.net/wzzfeitian/article/details/40963457
参考网址:http://blog.csdn.net/z_h_s/article/details/50699905
参考网址:http://www.th7.cn/Program/c/201512/709247.shtml


参考网址:https://cmake.org/pipermail/cmake/2004-April/004982.html
参考网址:https://stackoverflow.com/questions/34465878/cmake-post-build-step-copy-multiple-files-dependent-on-visual-studio-configurat
参考网址:http://www.cnblogs.com/foohack/p/3494423.html
参考网址:https://stackoverflow.com/questions/18427877/add-custom-build-step-in-cmake



你可能感兴趣的:(cmake中CMakeLists.txt脚本的常用语法)