CMake学习

CMake学习


参考自《Cmake Practice --Cjacker》


基本语法规则

变量的引用

${variable}

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

环境变量的引用

$ENV{NAME}

指令的引用

instruction(param1 param2 ...)

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

注意

指令是大小写无关的,参数和变量是大小写相关的。

常用变量和常用变量环境

1

  • CMAKE_BINARY_DIR
  • PROJECT_BINARY_DIR
  • <projectname>_BINARY_DIR

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

2

  • CMAKE_SOURCE_DIR
  • PROJECT_SOURCE_DIR
  • <projectname>_SOURCE_DIR

这三个变量指代的内容是一致的,不论采用何种编译方式,都是工程顶层目录。也就是在 in source 编译时,他跟 CMAKE_BINARY_DIR 等变量一致。PROJECT_SOURCE_DIR 跟其他指令稍有区别,现在,你可以理解为他们是一致的。

3

  • CMAKE_CURRENT_SOURCE_DIR

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

4

  • CMAKE_CURRRENT_BINARY_DIR

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

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

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

5

  • CMAKE_CURRENT_LIST_FILE

输出调用这个变量的 CMakeLists.txt 的完整路径。

6

  • CMAKE_CURRENT_LIST_LINE

输出这个变量所在的行。

7

  • CMAKE_MODULE_PATH

这个变量用来定义自己的 cmake 模块所在的路径。

8

  • EXECUTABLE_OUTPUT_PATH
  • LIBRARY_OUTPUT_PATH

分别用来重新定义最终结果的存放目录。

9

  • PROJECT_NAME

返回通过 PROJECT 指令定义的项目名称。

系统信息

  • CMAKE_MAJOR_VERSION,CMAKE 主版本号,比如 2.4.6 中的 2。
  • CMAKE_MINOR_VERSION,CMAKE 次版本号,比如 2.4.6 中的 4。
  • CMAKE_PATCH_VERSION,CMAKE 补丁等级,比如 2.4.6 中的 6。
  • CMAKE_SYSTEM,系统名称,比如 Linux-2.6.22。
  • CMAKE_SYSTEM_NAME,不包含版本的系统名,比如 Linux。
  • CMAKE_SYSTEM_VERSION,系统版本,比如 2.6.22。
  • CMAKE_SYSTEM_PROCESSOR,处理器名称,比如 i686。
  • UNIX,在所有的类 UNIX 平台为 TRUE,包括 OS X 和 cygwin。
  • WIN32,在所有的 win32 平台为 TRUE,包括 cygwin。

开关选项

  • CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS

用来控制 IF ELSE 语句的书写方式。

  • BUILD_SHARED_LIBS

这个开关用来控制默认的库编译方式,如果不进行设置,使用 ADD_LIBRARY 并没有指定库类型的情况下,默认编译生成的库都是静态库。

如果 SET(BUILD_SHARED_LIBS ON)后,默认生成的为动态库。

  • CMAKE_C_FLAGS

设置 C 编译选项,也可以通过指令 ADD_DEFINITIONS()添加。

  • CMAKE_CXX_FLAGS

设置 C++编译选项,也可以通过指令 ADD_DEFINITIONS()添加。

基本指令

PROJECT指令语法

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

这个指令隐式的定义了两个 cmake 变量:

  • <projectname>_BINARY_DIR
  • <projectname>_SOURCE_DIR

同时 cmake 系统也帮助我们预定义了 PROJECT_BINARY_DIR 和 PROJECT_SOURCE_DIR变量,他们的值分别跟 <projectname>_BINARY_DIR 与 <projectname>_SOURCE_DIR 一致。

SET指令语法

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

SET 指令可以用来显式的定义变量。

MESSAGE指令语法

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

这个指令用于向终端输出用户定义的信息,包含了三种类型:

  • SEND_ERROR,产生错误,生成过程被跳过。
  • STATUS,输出前缀为"-- "的信息。
  • FATAL_ERROR,立即终止所有 cmake 过程。

ADD_EXECUTABLE指令语法

ADD_EXECUTABLE(executablename sourcelists)

定义了这个工程会生成一个文件名为 executablename 的可执行文件,相关的源文件是 sourcelists 中定义的源文件列表。

ADD_SUBDIRECTORY指令语法

ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

这个指令用于向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放的位置。EXCLUDE_FROM_ALL 参数的含义是将这个目录从编译过程中排除,比如工程的 example,可能就需要工程构建完成后,再进入 example 目录单独进行构建。

SUBDIRS指令语法

SUBDIRS(dir1 dir2...)

这个指令已经不推荐使用。它可以一次添加多个子目录,并且即使外部编译,子目录体系仍然会被保存。

INSTALL指令语法

INSTALL(TARGETS targets...
    [[ARCHIVE|LIBRARY|RUNTIME] 
    [DESTINATION <dir>]
    [PERMISSIONS permissions...]
    [CONFIGURATIONS
    [Debug|Release|...]]
    [COMPONENT <component>]
    [OPTIONAL]
    ] [...])

ADD_LIBRARY指令语法

ADD_LIBRARY(libname [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL] source1 source2 ...)

类型有三种:

  • SHARED,动态库
  • STATIC,静态库
  • MODULE,在使用 dyld 的系统有效,如果不支持 dyld,则被当作 SHARED 对待。

EXCLUDE_FROM_ALL 参数的意思是这个库不会被默认构建,除非有其他的组件依赖或者手工构建。

SET_TARGET_PROPERTIES指令语法

SET_TARGET_PROPERTIES(target1 target2 ...
            PROPERTIES prop1 value1
            prop2 value2 ...)

这条指令可以用来设置输出的名称,对于动态库,还可以用来指定动态库版本和 API 版本。

GET_TARGET_PROPERTY指令语法

GET_TARGET_PROPERTY(VAR target property)

LINK_DIRECTORIES指令语法

LINK_DIRECTORIES(directory1 directory2 ...)

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

TARGET_LINK_LIBRARIES指令语法

TARGET_LINK_LIBRARIES(target library1
            <debug | optimized> library2
            ...)

这个指令可以用来为 target 添加需要链接的共享库,但是同样可以用于为自己编写的共享库添加共享库链接。

CMAKE_INCLUDE_CURRENT_DIR

自动添加 CMAKE_CURRENT_BINARY_DIR 和 CMAKE_CURRENT_SOURCE_DIR 到当前处理的 CMakeLists.txt。相当于在每个 CMakeLists.txt 加入:

INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})

CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE

将工程提供的头文件目录始终至于系统头文件目录的前面,当你定义的头文件确实跟系统发生冲突时可以提供一些帮助。

CMAKE_INCLUDE_PATH 和 CMAKE_LIBRARY_PATH

ADD_DEFINITIONS

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

ADD_DEFINITIONS(-DENABLE_DEBUG-DABC)

参数之间用空格分割。

如果你的代码中定义了#ifdef ENABLE_DEBUG #endif,这个代码块就会生效。

如果要添加其他的编译器开关,可以通过 CMAKE_C_FLAGS 变量和 CMAKE_CXX_FLAGS 变量设置。

ADD_DEPENDENCIES

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

ADD_DEPENDENCIES(target-name depend-target1 depend-target2 ...)

ADD_TEST 与 ENABLE_TESTING

ADD_TEST 指令的语法是:

ADD_TEST(testname Exename arg1 arg2 ...)

testname 是自定义的 test 名称,Exename 可以是构建的目标文件也可以是外部脚本等等。后面连接传递给可执行文件的参数。如果没有在同一个 CMakeLists.txt 中打开ENABLE_TESTING()指令,任何 ADD_TEST 都是无效的。

ENABLE_TESTING 指令用来控制 Makefile 是否构建 test 目标,涉及工程所有目录。语法很简单,没有任何参数,ENABLE_TESTING(),一般情况这个指令放在工程的主CMakeLists.txt 中。

AUX_SOURCE_DIRECTORY

基本语法是:

AUX_SOURCE_DIRECTORY(dir VARIABLE)

作用是发现一个目录下所有的源代码文件并将列表存储在一个变量中,这个指令临时被用来自动构建源文件列表。因为目前 cmake 还不能自动发现新添加的源文件。

CMAKE_MINIMUM_REQUIRED

其语法为

CMAKE_MINIMUM_REQUIRED(VERSION versionNumber [FATAL_ERROR])

比如 CMAKE_MINIMUM_REQUIRED(VERSION 2.5 FATAL_ERROR)

如果 cmake 版本小与 2.5,则出现严重错误,整个过程中止。

EXEC_PROGRAM

在 CMakeLists.txt 处理过程中执行命令,并不会在生成的 Makefile 中执行。具体语法为:

EXEC_PROGRAM(Executable [directory in which to run]
            [ARGS <arguments to executable>]
            [OUTPUT_VARIABLE <var>]
            [RETURN_VALUE <var>])

用于在指定的目录运行某个程序,通过 ARGS 添加参数,如果要获取输出和返回值,可通过OUTPUT_VARIABLE 和 RETURN_VALUE 分别定义两个变量。

这个指令可以帮助你在 CMakeLists.txt 处理过程中支持任何命令,比如根据系统情况去修改代码文件等等。

FILE 指令

文件操作指令,基本语法为:

FILE(WRITE filename "message to write"...)
FILE(APPEND filename "message to append"...)
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)

INCLUDE 指令

用来载入 CMakeLists.txt 文件,也用于载入预定义的 cmake 模块。

INCLUDE(file [OPTIONAL])
INCLUDE(module [OPTIONAL])

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

你可以指定载入一个文件,如果定义的是一个模块,那么将在 CMAKE_MODULE_PATH 中搜索这个模块并载入。

载入的内容将在处理到 INCLUDE 语句是直接执行。

FIND_ 指令

FIND_系列指令主要包含一下指令:

FIND_FILE(<VAR> name1 path1 path2 ...)

VAR 变量代表找到的文件全路径,包含文件名。

FIND_LIBRARY(<VAR> name1 path1 path2 ...)

VAR 变量表示找到的库全路径,包含库文件名。

FIND_PATH(<VAR> name1 path1 path2 ...)

VAR 变量代表包含这个文件的路径。

FIND_PROGRAM(<VAR> name1 path1 path2 ...)

VAR 变量代表包含这个程序的全路径。

FIND_PACKAGE(<name> [major.minor] [QUIET] [NO_MODULE]
        [[REQUIRED|COMPONENTS] [componets...]])

用来调用预定义在 CMAKE_MODULE_PATH 下的 Find<name>.cmake 模块,你也可以自己定义 Find<name>模块,通过 SET(CMAKE_MODULE_PATH dir)将其放入工程的某个目录中供工程使用,我们在后面的章节会详细介绍FIND_PACKAGE 的使用方法和 Find 模块的编写。

控制指令

  • IF 指令,基本语法为:
IF(expression)
    # THEN section.
    COMMAND1(ARGS ...)
    COMMAND2(ARGS ...)
    ...
ELSE(expression)
    # ELSE section.
    COMMAND1(ARGS ...)
    COMMAND2(ARGS ...)
    ...
ENDIF(expression)

另外一个指令是 ELSEIF,总体把握一个原则,凡是出现 IF 的地方一定要有对应的ENDIF。出现 ELSEIF 的地方,ENDIF 是可选的。

  • WHILE 指令的语法是:
WHILE(condition)
    COMMAND1(ARGS ...)
    COMMAND2(ARGS ...)
    ...
ENDWHILE(condition)
  • FOREACH

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

1、 列表

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

2、 范围

FOREACH(loop_var RANGE total)
    COMMAND1(ARGS ...)
    COMMAND2(ARGS ...)
    ...
ENDFOREACH(loop_var)

3、范围和步进

FOREACH(loop_var RANGE start stop [step])
    COMMAND1(ARGS ...)
    COMMAND2(ARGS ...)
    ...
ENDFOREACH(loop_var)

推荐阅读更多精彩内容

  • CMake学习 本篇分享一下有关CMake的一些学习心得以及相关使用。 本文目录如下: [1、CMake介绍] [...
    AlphaGL阅读 10,006评论 11 77
  • 注:首发地址 1. 前言 当在做 Android NDK 开发时,如果不熟悉用 CMake 来构建,读不懂 CMa...
    cfanr阅读 17,470评论 1 47
  • cmake 学习笔记 最近接触到一些工程上的代码,都是用cmake来编译的,每次看着CMakeLists.txt ...
    thinkpp阅读 5,655评论 0 1
  • 可以设置的变量 使用方式cmake -DCMAKE_INSTALL_PREFIX=yourpath 或在CMAKE...
    赵海洋阅读 1,010评论 0 3
  • 我是一个爱运动的人,喜欢旅游,喜欢爬山,喜欢跑步。 一有时间,就去旅游,尤其周末的时候,似乎不出门去,总是缺少了什...
    读写人家阅读 408评论 3 4
  • 还是金庸,还是独孤九剑,(以下文字大部分引用自一位武侠爱好者整理) 所谓“重剑无锋,大巧不工”是剑走偏锋(一招鲜,...
    923e76b49a72阅读 1,677评论 0 1
  • 经过苏浙汇和苏浙汇 然后想起简书这个东东 于是终于记得下载下来… 不知道和博客 微博 微信的区别在哪里
    needyouso阅读 72评论 0 0