cmake笔记

最近给公司同事介绍代码的编译结构,重新看了一遍cmake。做了下笔记。

  • PROJECT(projectname [CXX] [C] [Java])

你可以用这个指令定义工程名称,并可指定工程支持的语言,支持的语言列表是可以忽略的,默认情况表示支持所有语言。这个指令隐式的定义了两个 cmake 变量:<projectname>_BINARY_DIR 以及<projectname>_SOURCE_DIR(内部编译),为了统一起见,建议以后直接使用 PROJECT_BINARY_DIR,PROJECT_SOURCE_DIR,即使修改了工程名称,也不会影响这两个变量。

  • SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])

现阶段,你只需要了解 SET 指令可以用来显式的定义变量即可。比如我们用到的是 SET(SRC_LIST main.c),如果有多个源文件,也可以定义成:

SET(SRC_LIST main.c t1.c t2.c)。

语法比较弹性,SET(SRC_LIST main.c)也可以写成 SET(SRC_LIST “main.c”)

  • MESSAGE 指令的语法是:

MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] "message to display" ...)

遇到FATAL_ERROR,立即终止所有 cmake 过程

  • ADD_EXECUTABLE(hello ${SRC_LIST})

定义了这个工程会生成一个文件名为 hello 的可执行文件,相关的源文件是 SRC_LIST 中

定义的源文件列表, 本例中你也可以直接写成 ADD_EXECUTABLE(hello main.c)。

  • 基本语法规则

1,变量使用${}方式取值,但是在 IF 控制语句中是直接使用变量名

2,指令(参数 1 参数 2...)

参数使用括弧括起,参数之间使用空格或分号分开。

以上面的 ADD_EXECUTABLE 指令为例,如果存在另外一个 func.c 源文件,就要写成:

ADD_EXECUTABLE(hello main.c func.c)或者

ADD_EXECUTABLE(hello main.c;func.c)

3,指令是大小写无关的,参数和变量是大小写相关的。但,推荐你全部使用大写指令。

  • ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

这个指令用于向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放的位置。EXCLUDE_FROM_ALL 参数的含义是将这个目录从编译过程中排除

  • 外部编译时,通过 SET 指令重新定义 EXECUTABLE_OUTPUT_PATH 和 LIBRARY_OUTPUT_PATH 变量来指定最终的目标二进制的位置(指最终生成的 hello 或者最终的共享库,不包含编译生成的中间文件)

SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

  • 添加库  

ADD_LIBRARY(libname [SHARED|STATIC|MODULE]

[EXCLUDE_FROM_ALL]

source1 source2 ... sourceN)

如:ADD_LIBRARY(hello STATIC ${LIBHELLO_SRC}) //生成hello的静态库,源文件在${LIBHELLO_SRC}这个目录下

  • INSTALL([[SCRIPT <file>] [CODE <code>]] [...]) 安装文件,此外还可以安装lib

SCRIPT 参数用于在安装时调用 cmake 脚本文件(也就是<abc>.cmake 文件)。CODE 参数用于执行 CMAKE 指令,必须以双引号括起来。比如:

INSTALL(CODE "MESSAGE(\"Sample install message.\")")

  • INCLUDE_DIRECTORIES([AFTER|BEFORE] [SYSTEM] dir1 dir2 ...)

这条指令可以用来向工程添加多个特定的头文件搜索路径,路径之间用空格分割,如果路径中包含了空格,可以使用双引号将它括起来,默认的行为是追加到当前的头文件搜索路径的后面,你可以通过两种方式来进行控制搜索路径添加的方式:

1,CMAKE_INCLUDE_DIRECTORIES_BEFORE,通过 SET 这个 cmake 变量为 on,可以将添加的头文件搜索路径放在已有路径的前面。

2,通过 AFTER 或者 BEFORE 参数,也可以控制是追加还是置前。

  • LINK_DIRECTORIES(directory1 directory2 ...)

这个指令非常简单,添加非标准的共享库搜索路径,比如,在工程内部同时存在共享库和可执行二进制,在编译时就需要指定一下这些共享库的路径。

  • TARGET_LINK_LIBRARIES(target library1

<debug | optimized> library2

...)

这个指令可以用来为 target 添加需要链接的共享库,本例中是一个可执行文件,但是同样可以用于为自己编写的共享库添加共享库链接。

例如:TARGET_LINK_LIBRARIES(main libhello.so)

  • CMAKE_BINARY_DIR

PROJECT_BINARY_DIR

<projectname>_BINARY_DIR

这三个变量指代的内容是一致的,如果是 in source 编译,指得就是工程顶层目录,如果是 out-of-source 编译,指的是工程编译发生的目录。PROJECT_BINARY_DIR 跟其他指令稍有区别,现在,你可以理解为他们是一致的。

  • CMAKE_SOURCE_DIR

PROJECT_SOURCE_DIR

<projectname>_SOURCE_DIR

这三个变量指代的内容是一致的,不论采用何种编译方式,都是工程顶层目录。也就是在 in source 编译时,他跟 CMAKE_BINARY_DIR 等变量一致。

PROJECT_SOURCE_DIR 跟其他指令稍有区别,现在,你可以理解为他们是一致的。

  • CMAKE_CURRENT_SOURCE_DIR

指的是当前处理的 CMakeLists.txt 所在的路径

  • CMAKE_CURRRENT_BINARY_DIR

如果是 in-source 编译,它跟 CMAKE_CURRENT_SOURCE_DIR 一致,如果是 out-of-source 编译,他指的是 target 编译目录。

使用 ADD_SUBDIRECTORY(src bin)可以更改这个变量的值。

使用 SET(EXECUTABLE_OUTPUT_PATH <新路径>)并不会对这个变量造成影响,它仅仅修改了最终目标文件存放的路径。

  • cmake 调用环境变量的方式

使用$ENV{NAME}指令就可以调用系统的环境变量了。

比如MESSAGE(STATUS “HOME dir: $ENV{HOME}”)

设置环境变量的方式是:SET(ENV{变量名} 值)

  • ADD_DEFINITIONS

向 C/C++编译器添加-D 定义,比如:

ADD_DEFINITIONS(-DENABLE_DEBUG -DABC),参数之间用空格分割。

  • ADD_DEPENDENCIES

定义 target 依赖的其他 target,确保在编译本 target 之前,其他的 target 已经被构建。

ADD_DEPENDENCIES(target-name depend-target1

depend-target2 ...)

  • INCLUDE 指令,用来载入 CMakeLists.txt 文件,也用于载入预定义的 cmake 模块.

INCLUDE(file1 [OPTIONAL])

INCLUDE(module [OPTIONAL])

OPTIONAL 参数的作用是文件不存在也不会产生错误。

  • FILE 指令(文件操作指令),基本语法为:

FILE(WRITE filename "message to write"... )

FILE(APPEND filename "message to write"... )

FILE(READ filename variable)

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

FILE(GLOB_RECURSE variable [RELATIVE path] [globbing expressions]...)

FILE(REMOVE [directory]...)

FILE(REMOVE_RECURSE [directory]...)

FILE(MAKE_DIRECTORY [directory]...)

FILE(RELATIVE_PATH variable directory file)

FILE(TO_CMAKE_PATH path result)

FILE(TO_NATIVE_PATH path result)

  • IF 指令,基本语法为:

IF(expression)

# THEN section.

COMMAND1(ARGS ...)

ELSE(expression)

# ELSE section.

COMMAND1(ARGS ...)

ENDIF(expression)

IF(var),如果变量不是:空,0,N, NO, OFF, FALSE, NOTFOUND 或<var>_NOTFOUND 时,表达式为真。

IF(NOT var ),与上述条件相反。

IF(var1 AND var2),当两个变量都为真是为真。

IF(var1 OR var2),当两个变量其中一个为真时为真。

还很多很多其他条件类型的IF。还可以用ELSEIF()。

  • WHILE 指令的语法是:

WHILE(condition)

COMMAND1(ARGS ...)

ENDWHILE(condition)

  • FOREACH

对列表

FOREACH(loop_var arg1 arg2 ...)

COMMAND1(ARGS ...)

ENDFOREACH(loop_var)

对范围

FOREACH(loop_var RANGE total)

ENDFOREACH(loop_var)

从 0 到 total 以1为步进

对范围和步进

FOREACH(loop_var RANGE start stop [step])

ENDFOREACH(loop_var)

从 start 开始到 stop 结束,以 step 为步进

  • SET_TARGET_PROPERTIES

设置目标的一些属性来改变它们构建的方式。

set_target_properties(target1 target2 ...

PROPERTIES prop1 value1

prop2 value2 ...)

  为一个目标设置属性。该命令的语法是列出所有你想要变更的文件,然后提供你想要设置的值。你能够使用任何你想要的属性/值对,并且在随后的代码中调用GET_TARGET_PROPERTY命令取出属性的值。

  影响一个目标输出文件的名字的属性详述如下。

PREFIX和SUFFIX属性覆盖了默认的目标名前缀(比如lib)和后缀(比如.so)。

IMPORT_PREFIX和IMPORT_SUFFIX是与之等价的属性,不过针对的是DLL(共享库目标)的导入库。

  • add_custom_command

构造一个定制化的build规则。可以用来产生file和events(库或者可执行文件)。二者的命令是不一样的。

add_custom_command(OUTPUT output1 [output2 ...] COMMAND command1 [ARGS] [args1...] [COMMAND command2 [ARGS] [args2...] ...] [MAIN_DEPENDENCY depend] [DEPENDS [depends...]] [BYPRODUCTS [files...]] [IMPLICIT_DEPENDS <lang1> depend1 [<lang2> depend2] ...] [WORKING_DIRECTORY dir] [COMMENT comment] [VERBATIM] [APPEND] [USES_TERMINAL]) //产生文件

add_custom_command(TARGET target PRE_BUILD | PRE_LINK | POST_BUILD COMMAND command1 [ARGS] [args1...] [COMMAND command2 [ARGS] [args2...] ...] [BYPRODUCTS [files...]] [WORKING_DIRECTORY dir] [COMMENT comment] [VERBATIM] [USES_TERMINAL]) //产生一个目标比如库文件或者可执行文件

笔记内容主要来自Cjacker的《Cmake 实践》

猜你喜欢

转载自blog.csdn.net/chinagreenwall/article/details/81110703