【CMake】常用指令

CMake的指令是大小写不敏感的。

1、cmake_minimum_required

指定CMake工具的具体版本,使用格式如下:

cmake_minimum_required(VERSION <min>[...<policy_max>] [FATAL_ERROR])

可选参数<policy_max>是在3.12版本开始支持的。
<min><policy_max>支持的CMake版本格式如下:major.minor[.patch[.tweak]],同时...是字面量,不能省略。


当运行版本低于<min>时,CMake工具将会报错。当低于3.12版本时,...<policy_max>将会被忽略。FATAL_ERROR选项在2.6及以上版本会被忽略。在2.4及以下版本则会打印错误而不是告警。

这个命令会将CMAKE_MINIMUM_REQUIRED_VERSION变量设置为<min>

2、project

设置项目名字。

cmake_minimum_required执行该命令。

语法如下:

project(<PROJECT-NAME> [<language-name>...])
project(<PROJECT-NAME>
        [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
        [DESCRIPTION <project-description-string>]
        [HOMEPAGE_URL <url-string>]
        [LANGUAGES <language-name>...])

设置项目名字,同时将项目名存放到PROJECT_NAME变量中。如果是在顶层目录调用该命令,同时会将名字存放到CMAKE_PROJECT_NAME.

同时也会设置以下变量:

  • PROJECT_SOURCE_DIR, <PROJECT-NAME>_SOURCE_DIR: 该项目的源代码绝对路径。
  • PROJECT_BINARY_DIR, <PROJECT-NAME>_BINARY_DIR: 该项目的二进制绝对路径。
  • PROJECT_IS_TOP_LEVEL, <PROJECT-NAME>_IS_TOP_LEVEL: 3.21版本新增特性,指明当前项目是否是顶级项目。

可选参数:

  1. VERSION <version>

只有在CMP0048策略被设置为NEW时,该特性才会生效。

<version>参数是由非负整数组成。最多有以下4部分:<major>[.<minor>[.<patch>[.<tweak]]],同时会设置以下变量:

  • PROJECT_VERSION, <PROJECT-NAME>_VERSION
  • PROJECT_VERSION_MAJOR, <PROJECT-NAME>_VERSION_MAJOR
  • PROJECT_VERSION_MINOR, <PROJECT-NAME>_VERSION_MINOR
  • PROJECT_VERSION_PATCH, <PROJECT-NAME>_VERSION_PATCH
  • PROJECT_VERSION_TWEAK, <PROJECT-NAME>_VERSION_TWEAK

3.12新增特性:如果是顶层目录还会设置CMAKE_PROJECT_VERSION

  1. DESCRIPTION <project-description-string>

3.9版本新增特性

设置以下变量:

  • PROJECT_DESCRIPTION, <PROJECT-NAME>_DESCRIPTION

<project-description-string>需要足够简短,不能太长。当处于顶层目录时,同时会设置CMAKE_PROJECT_DESCRIPTION变量。

  1. HOMEPAGE_URL <url-string>

设置以下变量:

  • PROJECT_HOMEPAGE_URL, <PROJECT-NAME>_HOMEPAGE_URL

设置主页链接。当处于顶级目录时,同时会设置CMAKE_PROJECT_HOMEPAGE_URL

  1. LANGUAGES <language-name>...

指定项目使用的编程语言。支持以下语言:C, CXX, CUDA, OBJC, OBJCXX, Fortran, HIP, ISPC, ASM。如果未指定语言,默认使用CCXX。可以将语言设置为NONE, 或者使用LANGUAGES关键字,但是指定空列表,可以跳过启用任何语言。使用空格分隔不同语言。

3. add_executable

3.1 正常可执行文件

添加可执行文件到项目中。

add_executable(<name> [WIN32] [MACOSX_BUNDLE]
               [EXCLUDE_FROM_ALL]
               [source1] [source2 ...])

<name>表示可执行文件目标名字,需要保证在项目中唯一。实际构建出来的可执行文件名根据不同的平台有所区别。如<name>.exe<name>

3.1版本新增特性source参数可以使用生成器表达式,语法$<...>

3.11版本新增特性source参数可以被忽略,但后续需要使用target_sources命令添加。

默认情况下,可执行文件会在源代码树对应的构建树中生成。可以使用RUNTIME_OUTPUT_DIRECTORY属性修改目标文件的输出路径。可以使用OUTPUT_NAME属性修改最终文件的文件名,如果不指定,默认使用目标名。

设置WIN32属性后,对应的WIN32_EXECUTABLE属性也会被同时设置。

设置MACOSX_BUNDLE属性后,对应的MACOSX_BUNDLE属性也会被设置。

设置EXCLUDE_FROM_ALL属性后,对应的EXCLUDE_FROM_ALL属性也会被设置。

3.2 被导入可执行文件

add_executable(<name> IMPORTED [GLOBAL])

该命令用于导入项目之外的可执行文件。该target的IMPORTED属性会被设置为true,同时该target没有对应的规则用于生成。该target的作用域是本级及以下目录,同时可以使用GLOBAL属性扩展可见性。被导入可执行文件相关的一些细节通过IMPORTED_开头的属性指定。最重要的属性就是IMPORTED_LOCATION,该属性指定可执行文件的路径。

3.3 别名target

add_executable(<name> ALIAS <target>)

为指定的target创建别名。<target>不能是别名。

别名可以用于读取信息,并在自定义命令和目标中使用。别名不可以用于设置属性,所以在set_propertyset_target_propertiestarget_link_libraries等。

4. set

设置正常、缓存或环境变量

4.1 设置正常变量

set(<variable> <value>... [PARENT_SCOPE])

在当前函数或目录中设置或取消设置<variable>

如果<value>...至少有一个参数,则将变量设置为指定值;如果没给出值,则取消设置变量,等效于unset(<variable>)

如果设置了PARENT_SCOPE参数,那么就会设置上级作用域。每个新的目录和function()命令都会创建一个新的作用域。block()函数也会创建作用域。

set(PARENT_SCOPE)会将变量值设置到父目录、调用函数或上级作用域。同时,变量在当前作用域中的值保持不变,PARENT_SCOPE只是会改变上级作用域的值,并不会修改当前作用域的值。

block(PROPAGATE)return(PROPAGATE)的作用等效于set(PARENT_SCOPE)unset(PARENT_SCOPE)

注意:
cmake在计算${var}变量引用的时候,会先从正常变量中获取,如果正常变量找不到会从缓存条目中查找。因此,当把一个正常变量unset之后,会导致先前隐藏的缓存条目暴露出来。例如,正常变量中有个叫name的变量,缓存中也有个name条目,当unset(name)之后,下次再查找变量时,会把缓存中的值返回。
如果不想暴露缓存中的值,就不要使用unset命令,而用set(<variable> "")代替。

4.2 设置缓存条目

set(<variable> <value>... CACHE <type> <docstring> [FORCE])

因为缓存值旨在提供用户可设置的值,因此默认情况下,不会覆盖现有缓存项。可以使用FORCE选项,强制覆盖现有缓存项。

<type>必须是以下值之一:

  • BOOL:布尔值ON/OFF
  • FILEPATH:文件路径
  • PATH:文件目录
  • STRING:字符串
  • INTERNAL:文本,会覆盖现有缓存

<docstring>是缓存项的简短说明。

缓存项是可能没有设置type的(通过cmake命令行设置变量 -D<var>=<value>)。在这种情况下,set命令会向缓存项设置一个type。如果typePATH或者FILEPATH,而且<value>是相对路径,那么set命令会相对于当前工作目录,将相对路径转为绝对路径。

4.3 设置环境变量

set(ENV{<variable>} [<value>])

设置环境变量,随后使用$ENV{<variable>}访问环境变量。

这个命令只会影响当前CMake进程,不会影响调用cmake的进程,也不会影响系统环境变量,以及后续的构建和测试进程。

如果没有给出<value>,或者<value>是空字符串,这个命令会清楚环境变量的所有值。<value>后续参数会被忽略掉。

5. configure_file

configure_file(<input> <output>
               [NO_SOURCE_PERMISSIONS | USE_SOURCE_PERMISSIONS |
                FILE_PERMISSIONS <permissions>...]
               [COPYONLY] [ESCAPE_QUOTES] [@ONLY]
               [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])

<input>复制到<output>,中间再做一些转换,例如变量替换之类的。

参数解释如下:

  • <input>:输入文件路径,如果是相对路径,则基于CMAKE_CURRENT_SOURCE_DIR计算文件路径。
  • <output>: 输出文件路径或输出目录,如果是相对路径,则基于CMAKE_CURRENT_BINARY_DIR计算路径。如果输出目录已存在,则用与输入文件相同的文件名输出文件,如果目录不存在,则创建目录。
  • NO_SOURCE_PERMISSIONS: 输出文件不使用输入文件的权限,默认权限为644。
  • USE_SOURCE_PERMISSIONS: 输出文件使用输入文件的权限,默认配置项。
  • FILE_PERMISSIONS <permissions>...: 自定义输出文件权限。
  • COPYONLY: 仅复制,不做任何修改。不能和NEWLINE_STYLE参数一起使用。
  • ESCAPE_QUOTES: 用反斜杠转义引号。
  • @ONLY: 限制变量替换形式为@VAR@,不使用${VAR}的形式。
  • NEWLINE_STYLE <style>: 指定输出文件的换行样式,UNIXLF指定\nDOSWIN32CRLF指定\r\n

转换

在输入文件中的变量引用格式有以下3种:@VAR@${VAR}CACHE{VAR}。环境变量引用格式如下:$ENV{VAR}。如果变量未定义,则会使用空字符串替换。

输入文件中的以下代码:

#cmakedefine VAR ...

会被替换为:

#define VAR ...

/* #undef VAR */

具体会被替换成那种格式,需要根据if(VAR)命令的返回值判断,真值返回第一种,假值返回第二种。

#cmakedefine01 VAR

会被替换为:

#define VAR 0

#define VAR 1

取决于if(VAR)返回真值还是假值。

6、target_include_directories

向一个目标中添加头文件搜索路径。

语法如下:

target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]
  <INTERFACE|PUBLIC|PRIVATE> [items1...]
  [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])

指定target的头文件搜索路径,target使用前必须先定义,使用add_executableadd_library定义targettarget不能是别名target。

使用BEFOREAFTER,可以选择将头文件搜索目录插到最前面还是最后。

INTERFACEPUBLICPRIVATE关键字指定后面参数的作用域。PRIVATEPUBLIC作用域会将条目添加到targetINCLUDE_DIRECTORIES属性(本target构建需要的头文件搜索路径)。PUBLICINTERFACE作用域会将条目添加到targetINTERFACE_INCLUDE_DIRECTORIES属性(作为依赖库需要的头文件搜索路径)。

对同一个target重复调用,会按照调用顺序,添加头文件搜索路径。

SYSTEM选项指定这些目录是系统头文件搜索路径,这可能会抑制告警,在依赖检查时,会跳过包含的头文件,系统头文件搜索路径会在普通头文件搜索路径之后使用。

SYSTEMPUBLICINTERFACE一起使用的时候,会将包含路径添加到INTERFACE_SYSTEM_INCLUDE_DIRECTORIES属性中。

这个命令的头文件包含路径也可以使用生成器表达式,语法:$<...>

头文件包含路径可以是绝对路径,也可以是相对路径,如果是相对路径,就会基于CMAKE_CURRENT_SOURCE_DIR计算出绝对路径。如果路径以生成器表达式开始,那么该路径会被认为是一个绝对路径,不会做任何修改,直接使用。

头文件包含目录在构建和安装的场景下,会有区别,在构建和安装的时候,可能需要使用不同的头文件包含路径。BUILD_INTERFACEINSTALL_INTERFACE生成表达式可以用来区分不同的场景。

INSTALL_INTERFACE中可以使用相对路径,最终他会基于安装目录生成绝对路径。在BUILD_INTERFACE中不可以使用相对路径,因为他不会自动转换相对路径。

示例如下:

target_include_directories(mylib PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/mylib>
  $<INSTALL_INTERFACE:include/mylib>  # <prefix>/include/mylib
)

7、add_library

7.1 正常库

add_library(<name> [<type>] [EXCLUDE_FROM_ALL] <sources>...)

创建一个库文件。

<type>选项如下:

  • STATIC:生成静态库
  • SHARED:生成动态库
  • MODULE:插件,可能不会链接到其他target,但是可以通过类似dlopen的方法,在运行时打开使用

type默认值由BUILD_SHARED_LIBS变量值指定。行为如下:

if(BUILD_SHARED_LIBS)
  add_library(example SHARED ${sources})
else()
  add_library(example STATIC ${sources})
endif()

EXCLUDE_FROM_ALL:自动设置targetEXCLUDE_FROM_ALL属性。

<name>属性在一个项目中应该是唯一的。构建的库文件名根据不同的平台会有差异,lib<name>.a<name>.lib

SHAREDMODULE类型的库的POSITION_INDEPENDENT_CODE会被自动置为ON

SHAREDSTATIC库的FRAMEWORK属性会被设置,用于创建macOS框架。

如果库没有导出符号表,那么就不能声明为SHARED库。

7.2 对象库

add_library(<name> OBJECT <sources>...)

添加一个对象库(只把源文件编译成对象文件,不会链接和归档源文件)。

其他目标可以使用对象库中的文件作为输入源,表达式如下:$<TARGET_OBJECTS:objlib>

示例如下:

add_library(... $<TARGET_OBJECTS:objlib> ...)
add_executable(... $<TARGET_OBJECTS:objlib> ...)

7.3 接口库

add_library(<name> INTERFACE)

接口库会指定依赖库的使用前置条件,但是不会编译源文件,也不会生成库文件。

add_library(<name> INTERFACE [EXCLUDE_FROM_ALL] <sources>...)

<sources>...包含在接口库中。

7.4 导入库

add_library(<name> <type> IMPORTED [GLOBAL])

<type>有效取值如下:

  • STATIC, SHARED, MODULE, UNKNOWN:
    引用项目外部库文件,targetIMPORTED_LOCATION属性指定了外部库文件所在路径。
  • OBJECT:
    引用项目外部的对象文件。targetIMPORTED_OBJECTS属性指定了外部对象文件所在路径。
  • INTERFACE:
    不引用库和对象文件。

GLOBAL选项:让target名字全局可见。

7.5 别名库

add_library(<name> ALIAS <target>)

创建库的别名。

8、add_subdirectory

add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL] [SYSTEM])

添加构建子目录

source_dir指定构建的子目录路径,如果是相对路径,则基于当前目录计算路径。binary_dir指定输出文件目录。如果没指定binary_dir,则使用source_dir作为输出文件目录。

如果source_dir中有CMakeLists.txt文件,则会立即执行该文件,执行完之后在接着执行当前文件。

如果指定了EXCLUDE_FROM_ALL参数,那么就会将子目录的EXCLUDE_FROM_ALL属性设置为true,那么在make的时候,这个子目录的所有target将不会构建。

SYSTEM参数会设置子目录的SYSTEM参数,这个属性会用来初始化非导入target的SYSTEM属性。

9、target_link_libraries

target_link_libraries(<target> ... <item>... ...)

指定链接的库文件。

<item>选项如下:

  • 库目标名:链接的时候会生成库文件的全路径
  • 库文件的绝对路径
  • 库文件名:例如foo -> -lfoo 或 foo.lib
  • 链接选项:以-开头,而不是-l-framework。这个链接选项会被插入到链接库的地方。插入位置可能不对。可以使用targetLINK_OPTIONS属性,和target_link_options命令显式设置链接选项。
  • 生成器表达式:$<...>生成器表达式可以计算出上述的选项,或者是选项列表。如果...出现了分号,那么需要在生成器表达式外面加上双引号,以确保把这个表达式当成一个完整的item。生成器表达式也可以作为上述item的一部分使用。例如:foo$<1:_d>
  • debugoptimizedgeneral关键字后面跟<item>。这个<item>仅会用于对应的构建配置。debug对应Debug配置,或者DEBUG_CONFIGURATIONS全局属性指定的配置。optimized对应除Debug以外的所有配置。general对应所有配置,这个是可选,默认配置。

item中包含::,如Foo::Bar,会被认为是导入库或别名库。


target_link_libraries(<target>
                      <PRIVATE|PUBLIC|INTERFACE> <item>...
                     [<PRIVATE|PUBLIC|INTERFACE> <item>...]...)

该命令既可以指定链接依赖,又可以指定链接接口。

PUBLIC后面的item可以被链接,同时也会添加到链接接口中;PRIVATE后面的item可以被链接,但不会加入到链接接口中;INTERFACE后面的item会加入到链接接口中,但不会进行链接。

10、if

条件执行指令。

if(<condition>)
  <commands>
elseif(<condition>) # optional block, can be repeated
  <commands>
else()              # optional block
  <commands>
endif()

复合条件计算优先级如下:

  1. 括号
  2. 一元测试:EXISTS, COMMAND, 和 DEFINED
  3. 二元测试:EQUAL, LESS, LESS_EQUAL, GREATER, GREATER_EQUAL, STREQUAL, STRLESS, STRLESS_EQUAL, STRGREATER, STRGREATER_EQUAL, VERSION_EQUAL, VERSION_LESS, VERSION_LESS_EQUAL, VERSION_GREATER, VERSION_GREATER_EQUAL, PATH_EQUAL, 和 MATCHES
  4. 一元逻辑操作符:NOT
  5. 二元逻辑操作符:AND,OR

10.1 基础表达式

if(<constant>)

真值:1, ON, YES, TRUE, Y, 非0数字(浮点数也行)
假值:0, OFF, NO, FALSE, N, IGNORE, NOTFOUND, 空字符串,以-NOTFOUND结尾

如果不是上述值,则被当成变量或者字符串


if(<variable>)

如果variable的值是真值,那么判断条件就是true。除了真值以外的其他值都是假值。注意,宏参数不是变量,环境变量不能使用这种方式测试。


if(<string>)

字符串一直都被计算为假值,以下情况除外:

  • 字符串值是真值。

11、macro

宏定义,和c语言中的宏定义类似,原理也是文本替换。

macro(<name> [<arg1> ...])
  <commands>
endmacro()

宏是大小写不敏感的。

11.1 参数

${ARGC}表示传入给宏的参数个数;
${ARGV}表示预期的参数列表;
${ARGN}表示预期参数之后的所有多余参数列表;
${ARGV#}表示具体某个参数,如${ARGV0}${ARGV1}${ARGV2}

11.2 函数与宏

在函数中,ARGN, ARGC, ARGVARGV0, ARGV1是真正的变量,而在宏中,仅仅只是文本替换。

12、aux_source_directory

aux_source_directory(<dir> <variable>)

获取指定目录下的所有源文件,并存储到指定的变量中。

13、option

定义一个开关选项

option(<variable> "<help_text>" [value])

如果选项定义时没有指定<value>,那么默认值就是OFF

如果<variable>已经被定义为正常或缓存变量,那么该命令没有任何效果。

CMake项目模式下,<variable>会被创建成缓存变量,在CMake脚本模式下,<variable>会被创建成正常变量。

14、list

Reading
  list(LENGTH <list> <out-var>)
  list(GET <list> <element index> [<index> ...] <out-var>)
  list(JOIN <list> <glue> <out-var>)
  list(SUBLIST <list> <begin> <length> <out-var>)

Search
  list(FIND <list> <value> <out-var>)

Modification
  list(APPEND <list> [<element>...])
  list(FILTER <list> {INCLUDE | EXCLUDE} REGEX <regex>)
  list(INSERT <list> <index> [<element>...])
  list(POP_BACK <list> [<out-var>...])
  list(POP_FRONT <list> [<out-var>...])
  list(PREPEND <list> [<element>...])
  list(REMOVE_ITEM <list> <value>...)
  list(REMOVE_AT <list> <index>...)
  list(REMOVE_DUPLICATES <list>)
  list(TRANSFORM <list> <ACTION> [...])

Ordering
  list(REVERSE <list>)
  list(SORT <list> [...])

list命令会在当前作用域中创建一个新的变量,如果想将变量传递到其他作用域中,可以使用set()命令,带上PARENT_SCOPECACHE_INTERNAL

cmake中的list其实是用分号分隔的字符串。例如,set(var a b c d e)就会创建字符串a;b;c;d;e

cmake中对列表索引的时候,0表示第一个元素,-1表示列表最后一个元素。

14.1 Reading

list(LENGTH <list> <output variable>)

返回列表长度。


list(GET <list> <element index> [<element index> ...] <output variable>)

返回指定的元素


list(JOIN <list> <glue> <output variable>)

使用glue字符串连接列表所有元素


list(SUBLIST <list> <begin> <length> <output variable>)

获取子列表,如果length等于0返回空表,等于-1返回begin后面的所有元素。

list(FIND <list> <value> <output variable>)

返回value在列表中的索引,如果没找到,返回-1。

14.3 Modification

list(APPEND <list> [<element> ...])

向列表中添加元素,如果list不存在则创建空列表。


list(FILTER <list> <INCLUDE|EXCLUDE> REGEX <regular_expression>)

根据给定的正则表达式,包含或移除元素。


list(INSERT <list> <element_index> <element> [<element> ...])

将元素按指定的索引插入列表。

如果索引不在列表范围之内,则会报错。有效索引是0到N,N是列表长度,如果列表不存在,则会创建空列表。


list(POP_BACK <list> [<out-var>...])

弹出后面的元素,如果没有变量接收,那么就会弹出最后一个元素,如果接收的变量有N个,那么就会弹出N个元素。


list(POP_FRONT <list> [<out-var>...])

弹出前面的元素,和POP_BACK类似。


list(PREPEND <list> [<element> ...])

在列表前面添加元素。


list(REMOVE_ITEM <list> <value> [<value> ...])

从列表中移除所有的给定元素。


list(REMOVE_AT <list> <index> [<index> ...])

从列表中移除给定索引的元素。


list(REMOVE_DUPLICATES <list>)

移除重复元素。


list(TRANSFORM <list> <ACTION> [<SELECTOR>] [OUTPUT_VARIABLE <output variable>])

转换列表,如果没有给定SELECTOR,那么就会在列表中的所有item上应用ACTION。如果没有指定变量,则会把转换后的结果放在本地,如果指定了这将结果放到指定变量中。

ACTION取值必须是以下选项:

  • APPEND, PREPEND:给list中的每个元素在前面或后面加上value
list(TRANSFORM <list> (APPEND|PREPEND) <value> ...)
  • TOLOWER, TOUPPER:将list中的每个元素转为大写或小写
list(TRANSFORM <list> (TOLOWER|TOUPPER) ...)
  • STRIP: 移除list中元素的前面和后面的空白字符
list(TRANSFORM <list> STRIP ...)
  • GENEX_STRIP: 移除list中元素的所有生成器表达式
list(TRANSFORM <list> GENEX_STRIP ...)
  • REPLACE: 将正则表达式匹配到的部分全部替换成指定的表达式
list(TRANSFORM <list> REPLACE <regular_expression> <replace_expression> ...)

SELECTOR取值必须是以下选项:

  • AT:指定列表索引
list(TRANSFORM <list> <ACTION> AT <index> [<index> ...] ...)
  • FOR: 指定元素范围,同时可以指定一个递进数
list(TRANSFORM <list> <ACTION> FOR <start> <stop> [<step>] ...)
  • REGEX: 指定正则表达式,只有匹配的元素才会被转换
list(TRANSFORM <list> <ACTION> REGEX <regular_expression> ...)

14.4 Ordering

list(REVERSE <list>)

原地倒换列表元素


list(SORT <list> [COMPARE <compare>] [CASE <case>] [ORDER <order>])

按字典序原地排序列表。

使用COMPARE关键字选择排序算法,取值有以下几种:

  • STRING:以字典序排序列表,默认行为
  • FILE_BASENAME:按文件路径进行排序
  • NATURAL:以自然顺序排序,如10.0 1.1 2.1 8.0 2.0 3.1,如果按自然序,则是1.1 2.0 2.1 3.1 8.0 10.0,如果是字典序,则是1.1 10.0 2.0 2.1 3.1 8.0

使用CASE关键字,表明是否大小写敏感,取值有以下两种:

  • SENSITIVE: 大小写敏感,默认行为
  • INSENSITIVE:大小写不敏感

ORDER决定排序顺序,取值有以下两种:

  • ASCENDING:升序
  • DESCENDING:降序

15、message

记录消息

General messages
  message([<mode>] "message text" ...)

Reporting checks
  message(<checkState> "message text" ...)

16、target_compile_definitions

添加目标编译选项。

target_compile_definitions(<target>
  <INTERFACE|PUBLIC|PRIVATE> [items1...]
  [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])

PRIVATEPUBLIC设置目标的COMPILE_DEFINITIONS属性,PUBLICINTERFACE设置INTERFACE_COMPILE_DEFINITIONS属性。

本目标编译使用COMPILE_DEFINITIONS属性,依赖本目标的目标编译使用INTERFACE_COMPILE_DEFINITIONS属性。

参数中的-D前导会被移除,如:

target_compile_definitions(foo PUBLIC FOO)
target_compile_definitions(foo PUBLIC -DFOO)  # -D removed
target_compile_definitions(foo PUBLIC "" FOO) # "" ignored
target_compile_definitions(foo PUBLIC -D FOO) # -D becomes "", then ignored

17、target_compile_options

添加编译选项。

target_compile_options(<target> [BEFORE]
  <INTERFACE|PUBLIC|PRIVATE> [items1...]
  [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])

target_compile_definitions命令类似,PRIVATEPUBLIC设置COMPILE_OPTIONS属性,PUBLICINTERFACE设置INTERFACE_COMPILE_OPTIONS属性。

18、install

指定安装规则。

install(TARGETS <target>... [...])
install(IMPORTED_RUNTIME_ARTIFACTS <target>... [...])
install({FILES | PROGRAMS} <file>... [...])
install(DIRECTORY <dir>... [...])
install(SCRIPT <file> [...])
install(CODE <code> [...])
install(EXPORT <export-name> [...])
install(RUNTIME_DEPENDENCY_SET <set-name> [...])

此命令有多个可选项:

  • DESTINATION

指定安装目录,可以是相对路径也可以是绝对路径。

如果是相对路径,那么就会基于CMAKE_INSTALL_PREFIX计算绝对路径。CMAKE_INSTALL_PREFIX可以在安装的时候重新设置。

  • PERMISSIONS

指定安装文件权限,有效权限:OWNER_READ, OWNER_WRITE, OWNER_EXECUTE, GROUP_READ, GROUP_WRITE, GROUP_EXECUTE, WORLD_READ, WORLD_WRITE, WORLD_EXECUTE, SETUID 和 SETGID。

  • CONFIGURATIONS

指定安装的构建配置列表(如Debug、Release)。

例如为Debug和Release指定不同的安装路径:

install(TARGETS target
        CONFIGURATIONS Debug
        RUNTIME DESTINATION Debug/bin)
install(TARGETS target
        CONFIGURATIONS Release
        RUNTIME DESTINATION Release/bin)
  • COMPONENT

指定与安装规则关联的安装组件名。例如,runtime和development。

在指定安装组件时,则会只执行特定的组件安装,如果是全量安装,则会安装所有的组件。如果没有指定组件名,则会创建一个默认的组件名Unspecified。默认组件名可以通过CMAKE_INSTALL_DEFAULT_COMPONENT_NAME变量进行控制。

  • EXCLUDE_FROM_ALL

指定全量安装的时候,不安装此组件,仅通过指定组件安装。

  • RENAME

为已安装的文件指定一个可能与原始文件不同的名称。仅当使用该命令安装单个文件时才允许重命名。

  • OPTIONAL

安装文件不存在时,不报错。

18.1 安装目标

install(TARGETS targets... [EXPORT <export-name>]
        [RUNTIME_DEPENDENCIES args...|RUNTIME_DEPENDENCY_SET <set-name>]
        [[ARCHIVE|LIBRARY|RUNTIME|OBJECTS|FRAMEWORK|BUNDLE|
          PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE]
         [DESTINATION <dir>]
         [PERMISSIONS permissions...]
         [CONFIGURATIONS [Debug|Release|...]]
         [COMPONENT <component>]
         [NAMELINK_COMPONENT <component>]
         [OPTIONAL] [EXCLUDE_FROM_ALL]
         [NAMELINK_ONLY|NAMELINK_SKIP]
        ] [...]
        [INCLUDES DESTINATION [<dir> ...]]
        )

该命令的输出结果可能有以下几种:

  • ARCHIVE
  1. 静态库
  2. DLL导入库(扩展名.lib
  • LIBRARY
  1. 动态库
  • RUNTIME
  1. 可执行文件
  2. DLL(扩展名.dll
  • OBJECTS

对象库关联的对象文件

  • FRAMEWORK

带有FRAMEWORK属性的动态库和静态库(macOS平台)

  • BUNDLE

带有MACOSX_BUNDLE属性的可执行文件(macOS平台)

  • PUBLIC_HEADER

在非apple平台上,与库关联的任何PUBLIC_HEADER文件都安装在由PUBLIC_HEADER参数指定的目标中。

  • PRIVATE_HEADER

类似于PUBLIC_HEADER,但用于PRIVATE_HEADER文件。

  • RESOURCE

类似于PUBLIC_HEADER和PRIVATE_HEADER,但用于RESOURCE文件。


当DESTINATION没有给出时,将会使用下列的默认值:

image

如果需要指定特定的安装目录,建议使用GNUInstallDirs中的变量,这有利于后期指定特定的安装目录。

如·:

add_library(mylib STATIC ...)
set_target_properties(mylib PROPERTIES PUBLIC_HEADER mylib.h)
include(GNUInstallDirs)
install(TARGETS mylib
        PUBLIC_HEADER
          DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/myproj
)

除了上面列出的常见选项外,每个目标还可以接受以下附加参数:

  • NAMELINK_COMPONENT

在某些平台上,版本化的共享库具有符号链接,例如:

lib<name>.so -> lib<name>.so.1

NAMELINK_COMPONENT选项类似于COMPONENT选项,但它会更改共享库名称链接的安装组件(如果生成了)。如果未指定,则默认为COMPONENT的值。

该选项只能在LIBRARY中设置,不能在其他选项中设置。

install(TARGETS mylib
        LIBRARY
          COMPONENT Libraries
          NAMELINK_COMPONENT Development
        PUBLIC_HEADER
          COMPONENT Development
       )

该选项通常用于具有独立运行时和开发包的包管理器。例如,在Debian系统上,库应该在运行时包中,而头文件和命名链接应该在开发包中。

  • NAMELINK_ONLY

此选项导致在安装库目标时仅安装名称链接。在受版本控制的共享库没有名称链接的平台上,或者当库没有版本控制时,NAMELINK_ONLY选项不安装任何东西。在LIBRARY块之外使用这个参数是错误的。

当给出NAMELINK_ONLY时,NAMELINK_COMPONENT或COMPONENT都可以用来指定名称链接的安装组件,但通常应该首选COMPONENT。

  • NAMELINK_SKIP

类似于NAMELINK_ONLY,但它具有相反的效果:当安装库目标时,它会导致安装库文件而不是名称链接。当没有指定NAMELINK_ONLY或NAMELINK_SKIP时,将同时安装这两个部分。在受版本控制的共享库没有符号链接的平台上,或者当库没有版本控制时,NAMELINK_SKIP将安装该库。在LIBRARY块之外使用这个参数是错误的。

如果指定了NAMELINK_SKIP,则NAMELINK_COMPONENT不起作用。不建议将NAMELINK_SKIP与NAMELINK_COMPONENT结合使用。

  • EXPORT

该选项将安装的目标文件与名为的导出关联起来。它必须出现在任何目标选项之前。要实际安装导出文件本身,请调用install(EXPORT)。

  • INCLUDES DESTINATION

该选项指定一个目录列表,当通过install(EXPORT)命令导出时,这些目录将被添加到的INTERFACE_INCLUDE_DIRECTORIES target属性中。如果指定了相对路径,则将其视为相对于$<INSTALL_PREFIX>的路径。

  • RUNTIME_DEPENDENCY_SET

此选项会将已安装的可执行文件、共享库和模块目标的所有运行时依赖项添加到指定的运行时依赖项集中。然后可以使用install(RUNTIME_DEPENDENCY_SET)命令安装该集合。

该关键字与RUNTIME_DEPENDENCIES关键字互斥。

  • RUNTIME_DEPENDENCIES

此选项导致安装的可执行文件、共享库和模块目标的所有运行时依赖项与目标本身一起安装。RUNTIME、LIBRARY、FRAMEWORK和泛型参数用于确定这些依赖项安装的属性(DESTINATION、COMPONENT等)。

RUNTIME_DEPENDENCIES在语义上等同于下面这对调用:

install(TARGETS ... RUNTIME_DEPENDENCY_SET <set-name>)
install(RUNTIME_DEPENDENCY_SET <set-name> args...)

其中<set-name>将是随机生成的集合名称。args……可以包括install(RUNTIME_DEPENDENCY_SET)命令支持的以下任何关键字:

  1. DIRECTORIES

  2. PRE_INCLUDE_REGEXES

  3. PRE_EXCLUDE_REGEXES

  4. POST_INCLUDE_REGEXES

  5. POST_EXCLUDE_REGEXES

  6. POST_INCLUDE_FILES

  7. POST_EXCLUDE_FILES

可以在对该命令的TARGETS形式的单个调用中指定一组或多组属性。一个目标可以在不同的位置安装多次。示例代码如下:

install(TARGETS myExe mySharedLib myStaticLib
        RUNTIME DESTINATION bin
        LIBRARY DESTINATION lib
        ARCHIVE DESTINATION lib/static)
install(TARGETS mySharedLib DESTINATION /some/full/path)

将把myExe安装到<prefix>/bin,把myStaticLib安装到<prefix>/lib/static。在非DLL平台上,mySharedLib将安装到<prefix>/lib和/some/full/path。在DLL平台上,mySharedLib DLL将安装到<prefix>/bin和/some/full/path,其导入库将安装到<prefix>/lib/static和/some/full/path。

接口库也可以作为安装目标,接口库不会安装任何组件,但是会包含在关联的EXPORT里。如果安装对象库没有给定destination,那么这些对象库就会被导出为接口库。

安装EXCLUDE_FROM_ALL属性为true的目标,其行为是不可预期的。

18.2 安装导入运行时构建

install(IMPORTED_RUNTIME_ARTIFACTS targets...
        [RUNTIME_DEPENDENCY_SET <set-name>]
        [[LIBRARY|RUNTIME|FRAMEWORK|BUNDLE]
         [DESTINATION <dir>]
         [PERMISSIONS permissions...]
         [CONFIGURATIONS [Debug|Release|...]]
         [COMPONENT <component>]
         [OPTIONAL] [EXCLUDE_FROM_ALL]
        ] [...]
        )

IMPORTED_RUNTIME_ARTIFACTS指定导入目标的运行时工件安装规则。当项目需要绑定安装外部可执行文件或模块时,可以使用此命令。

18.3 安装文件

install(<FILES|PROGRAMS> files...
        TYPE <type> | DESTINATION <dir>
        [PERMISSIONS permissions...]
        [CONFIGURATIONS [Debug|Release|...]]
        [COMPONENT <component>]
        [RENAME <name>] [OPTIONAL] [EXCLUDE_FROM_ALL])

如果文件名是相对路径,那么就会基于当前源代码路径计算绝对路径。安装文件的默认权限是644。

PROGRAMSFILES基本相同,唯一的区别就是默认文件权限,PROGRAMSFILES多了可执行权限,默认为755。PROGRAMS目的在于安装程序(例如shell脚本),而不是目标。

必须指定TYPEDESTINATION中的其中一个参数,不能都不指定。TYPE指定安装的文件类型,指定TYPE之后,随后会使用GNUInstallDirs中相应的变量,设置DESTINATION,如果想显示指定安装路径,可使用DESTINATION参数。TYPE的可能取值及相关变量、默认值见下表:

image

上面DATAROOT前缀,它的默认值是share目录。

18.4 安装目录

install(DIRECTORY dirs...
        TYPE <type> | DESTINATION <dir>
        [FILE_PERMISSIONS permissions...]
        [DIRECTORY_PERMISSIONS permissions...]
        [USE_SOURCE_PERMISSIONS] [OPTIONAL] [MESSAGE_NEVER]
        [CONFIGURATIONS [Debug|Release|...]]
        [COMPONENT <component>] [EXCLUDE_FROM_ALL]
        [FILES_MATCHING]
        [[PATTERN <pattern> | REGEX <regex>]
         [EXCLUDE] [PERMISSIONS permissions...]] [...])

当目录名是相对路径的时候,就会基于当前源代码路径计算绝对路径。FILE_PERMISSIONSDIRECTORY_PERMISSIONS指定文件和目录权限。如果指定了USE_SOURCE_PERMISSIONS,但是没有指定FILE_PERMISSIONS,那么文件权限就会拷贝源文件权限。如果没有指定权限,那么文件权限将和FILE命令权限保持一致,即644,文件夹权限和PROGRAM保持一致,即755。

MESSAGE_NEVER指定是否输出安装状态。

PATTERNREGEX通过指定通配表达式和正则表达式匹配特定的文件夹或目录。使用文件或目录的绝对路径进行匹配。PATTERN只会匹配完整的文件名,匹配的部分必须在完整路径的末尾,且前面需要带一个斜杆。REGEX可以匹配全路径的任意部分,同时可以使用/$近似达到PATTERN的作用。默认情况下,不管是否匹配,文件和目录都会全部安装。FILES_MATCHING可以用来指定未匹配的文件不安装(不包括目录)。

例如:

install(DIRECTORY src/ DESTINATION include/myproj
        FILES_MATCHING PATTERN "*.h")

上面的示例会提取并安装所有的头文件。

PATTERNREGEX命令后面可以跟一些选项用来控制匹配的文件和目录。EXCLUDE选项用于跳过匹配的文件和路径。PERMISSIONS用于指定匹配文件的权限。

install(DIRECTORY icons scripts/ DESTINATION share/myproj
        PATTERN "CVS" EXCLUDE
        PATTERN "scripts/*"
        PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ
                    GROUP_EXECUTE GROUP_READ)

TYPEDESTINATIONS选项必须指定其中一个。TYPE的取值和FILES类似,如下:

18.5 自定义安装逻辑

install([[SCRIPT <file>] [CODE <code>]]
        [ALL_COMPONENTS | COMPONENT <component>]
        [EXCLUDE_FROM_ALL] [...])

SCRIPT会在安装的时候调用指定的CMake脚本。如果是相对路径,这基于当前源代码路径计算绝对路径。CODE会在安装的时候执行给定的CMake代码。CODE参数需要使用双引号包括,如下:

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

ALL_COMPONENTS选项表示在每个组件安装的时候都执行指定的脚本和代码,COMPONENTS表示只有在特定组件安装的时候才执行指定的脚本和代码。

18.6 安装导出

install(EXPORT <export-name> DESTINATION <dir>
        [NAMESPACE <namespace>] [[FILE <name>.cmake]|
        [PERMISSIONS permissions...]
        [CONFIGURATIONS [Debug|Release|...]]
        [EXPORT_LINK_INTERFACE_LIBRARIES]
        [COMPONENT <component>]
        [EXCLUDE_FROM_ALL])
install(EXPORT_ANDROID_MK <export-name> DESTINATION <dir> [...])

EXPORT表单生成并安装一个CMake文件,其中包含从安装树导入目标到另一个项目的代码。NAMESPACE选项将<namespace>添加到目标名的前面。默认情况下,生成文件的文件名叫<export-name>.cmake,但是也可以通过FILE选项指定其他的名字。如果指定了CONFIGURATIONS选项,那么只有在特定的配置被安装的时候,才会安装cmake文件。

EXPORT命令有利于帮助外部项目使用当前项目构建和安装的目标。例如:

install(TARGETS myexe EXPORT myproj DESTINATION bin)
install(EXPORT myproj NAMESPACE mp_ DESTINATION lib/myproj)
install(EXPORT_ANDROID_MK myproj DESTINATION share/ndk-modules)

上述示例会将myexe可执行文件安装到<prefix>/bin,同时生成导入文件<prefix>/lib/myproj/myproj.cmake<prefix>/share/ndk-modules/Android.mk。外部项目可以使用include命令,加载导入文件,以引用可执行文件。

18.7 安装运行时依赖

install(RUNTIME_DEPENDENCY_SET <set-name>
        [[LIBRARY|RUNTIME|FRAMEWORK]
         [DESTINATION <dir>]
         [PERMISSIONS permissions...]
         [CONFIGURATIONS [Debug|Release|...]]
         [COMPONENT <component>]
         [NAMELINK_COMPONENT <component>]
         [OPTIONAL] [EXCLUDE_FROM_ALL]
        ] [...]
        [PRE_INCLUDE_REGEXES regexes...]
        [PRE_EXCLUDE_REGEXES regexes...]
        [POST_INCLUDE_REGEXES regexes...]
        [POST_EXCLUDE_REGEXES regexes...]
        [POST_INCLUDE_FILES files...]
        [POST_EXCLUDE_FILES files...]
        [DIRECTORIES directories...]
        )

运行时依赖在DLL平台上,将安装到RUNTIME路径下;在非DLL平台,会安装到LIBRARY路径下;macOS系统,安装到FRAMEWORK路径下。

posted @   NotReferenced  阅读(378)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示