ExternalProject

外部项目定义

ExternalProject_Add

ExternalProject_Add() 函数创建一个自定义目标,以驱动外部项目的下载、更新/补丁、配置、构建、安装和测试步骤。

ExternalProject_Add(<name> [<option>...])

如果需要(例如,用于 CDash 提交),可以独立驱动流程中的各个步骤,并且可以定义额外的自定义步骤,同时能够控制步骤依赖关系。用于管理外部项目的目录结构也可以自定义。该函数支持大量选项,可用于定制外部项目行为。

目录选项

大多数情况下,默认目录布局就足够了。这在很大程度上是主项目通常不需要更改的实现细节。然而,在某些情况下,控制目录布局可能有用或必要。从主构建可以使用 ExternalProject_Get_Property() 命令检索其值的角度来看,目录选项可能更有用,从而允许主项目引用外部项目的构建产物。

PREFIX <dir>

外部项目的根目录。除非下面另有说明,否则所有与外部项目相关的其他目录都将在此处创建。

TMP_DIR <dir>

用于存储临时文件的目录。

STAMP_DIR <dir>

用于存储每个步骤时间戳的目录。除非被 LOG_DIR 覆盖(参见下面的 *日志选项*),否则单个步骤的日志文件也在此处创建。

LOG_DIR <dir>

3.14 版新增。

用于存储每个步骤日志的目录。

DOWNLOAD_DIR <dir>

用于存储下载文件解包前的目录。此目录仅由 URL 下载方法使用,所有其他下载方法直接使用 SOURCE_DIR

SOURCE_DIR <dir>

用于解压下载内容的源目录,或者对于非 URL 下载方法,是应检出、克隆存储库的目录。如果未指定下载方法,则此目录必须指向外部项目已解压或克隆/检出到的现有目录。

注意

如果指定了下载方法,源目录的任何现有内容都可能被删除。只有 URL 下载方法在启动下载前检查此目录是否缺失或为空,如果非空则停止并报错。所有其他下载方法都会静默丢弃源目录的任何先前内容。

BINARY_DIR <dir>

指定构建目录位置。如果启用了 BUILD_IN_SOURCE,则此选项将被忽略。

INSTALL_DIR <dir>

要放置在 <INSTALL_DIR> 占位符中的安装前缀。这实际上不会将外部项目配置为安装到给定前缀。这必须通过向外部项目配置步骤传递适当的参数来完成,例如使用 <INSTALL_DIR>

如果上述任何 ..._DIR 选项未指定,则其默认值按如下方式计算。如果给出了 PREFIX 选项或设置了 EP_PREFIX 目录属性,则外部项目将在指定前缀下构建和安装。

TMP_DIR      = <prefix>/tmp
STAMP_DIR    = <prefix>/src/<name>-stamp
DOWNLOAD_DIR = <prefix>/src
SOURCE_DIR   = <prefix>/src/<name>
BINARY_DIR   = <prefix>/src/<name>-build
INSTALL_DIR  = <prefix>
LOG_DIR      = <STAMP_DIR>

否则,如果设置了 EP_BASE 目录属性,则外部项目的组件将存储在指定的基础目录下。

TMP_DIR      = <base>/tmp/<name>
STAMP_DIR    = <base>/Stamp/<name>
DOWNLOAD_DIR = <base>/Download/<name>
SOURCE_DIR   = <base>/Source/<name>
BINARY_DIR   = <base>/Build/<name>
INSTALL_DIR  = <base>/Install/<name>
LOG_DIR      = <STAMP_DIR>

如果未指定 PREFIXEP_PREFIXEP_BASE,则默认将 PREFIX 设置为 <name>-prefix。相对路径将相对于调用 ExternalProject_Add() 时的 CMAKE_CURRENT_BINARY_DIR 进行解释。

下载步骤选项

如果使用 SOURCE_DIR 选项指向一个现有的非空目录,则可以省略下载方法。否则,必须指定下面的一种下载方法(不应给出多种下载方法)或提供自定义的 DOWNLOAD_COMMAND

DOWNLOAD_COMMAND <cmd>...

覆盖下载步骤使用的命令(支持生成器表达式)。如果指定此选项,所有其他下载选项将被忽略。为 <cmd> 提供空字符串将有效禁用下载步骤。

URL

URL <url1> [<url2>...]

外部项目源的路径和/或 URL 列表。当给出多个 URL 时,它们将依次尝试,直到成功一个。URL 可以是本地文件系统中的普通路径(在这种情况下,它必须是唯一提供的 URL)或 file(DOWNLOAD) 命令支持的任何可下载 URL。本地文件系统路径可以引用现有目录或归档文件,而 URL 预计指向可作为归档处理的文件。当使用归档时,它将自动解压,除非设置了 DOWNLOAD_NO_EXTRACT 选项以阻止它。归档类型通过检查实际内容而不是基于文件扩展名的逻辑来确定。

3.7 版本发生变化:允许多个 URL。

URL_HASH <algo>=<hashValue>

要下载的归档文件的哈希值。参数应采用 <algo>=<hashValue> 形式,其中 algo 可以是 file() 命令支持的任何哈希算法。强烈建议为 URL 下载指定此选项,因为它确保了下载内容的完整性。它还用作对先前下载文件的检查,如果本地目录中已经有一个匹配指定哈希的早期下载文件,则可以完全避免连接到远程位置。

URL_MD5 <md5>

等同于 URL_HASH MD5=<md5>

DOWNLOAD_NAME <fname>

用于下载文件的文件名。如果未给出,则使用 URL 的末尾来确定文件名。此选项很少需要,默认名称通常是合适的,并且通常不用于 ExternalProject 模块内部的代码之外。

DOWNLOAD_EXTRACT_TIMESTAMP <bool>

在 3.24 版本中添加。

当指定为 true 时,提取文件的修改时间将与存档中的时间匹配。当为 false 时,提取文件的修改时间将反映执行提取的时间。如果下载 URL 更改,基于存档中时间戳的时间戳可能导致依赖目标未在其可能应该重建时重建。因此,除非文件时间戳对项目有某种重要意义,否则请对此选项使用 false 值。如果未给出 DOWNLOAD_EXTRACT_TIMESTAMP,则默认值为 false。请参见策略 CMP0135

DOWNLOAD_NO_EXTRACT <bool>

3.6 版本新增。

通过为此选项传递布尔真值,可以禁用下载步骤的提取部分。如果未给出此选项,则下载的内容将根据需要自动解压。如果已禁用提取,则下载文件的完整路径可在后续步骤中作为 <DOWNLOADED_FILE> 使用,或通过 ExternalProject_Get_Property() 命令作为属性 DOWNLOADED_FILE 使用。

DOWNLOAD_NO_PROGRESS <bool>

可用于禁用下载进度日志。如果未给出此选项,将记录下载进度消息。

TIMEOUT <seconds>

文件下载操作允许的最长时间。

INACTIVITY_TIMEOUT <seconds>

3.19 版本新增。

在一段不活动期后终止操作。

HTTP_USERNAME <username>

3.7 版本中新增。

如果需要身份验证,则用于下载操作的用户名。

HTTP_PASSWORD <password>

3.7 版本中新增。

如果需要身份验证,则用于下载操作的密码。

HTTP_HEADER <header1> [<header2>...]

3.7 版本中新增。

为下载操作提供任意 HTTP 头列表。这对于访问 AWS 等系统中的内容可能很有用。

TLS_VERSION <min>

3.30 版本新增。

指定 https:// URL 的最低 TLS 版本。如果未提供此选项,将使用 CMAKE_TLS_VERSION 变量或 CMAKE_TLS_VERSION 环境变量的值(参见 file(DOWNLOAD))。

此选项也适用于 git clone 调用,尽管默认行为不同。如果未指定 TLS_VERSION 选项、CMAKE_TLS_VERSION 变量或 CMAKE_TLS_VERSION 环境变量中的任何一个,则行为将由 git 的默认设置或用户可能在全局级别设置的 http.sslVersion git 配置选项决定。

TLS_VERIFY <bool>

指定是否对 https:// URL 执行证书验证。如果未提供此选项,将使用 CMAKE_TLS_VERIFY 变量或 CMAKE_TLS_VERIFY 环境变量的值(参见 file(DOWNLOAD))。如果两者均未设置,则不执行证书验证。在无法提供 URL_HASH 的情况下,此选项可以作为替代验证措施。

此选项也适用于 git clone 调用,尽管默认行为不同。如果未指定 TLS_VERIFY 选项、CMAKE_TLS_VERIFY 变量或 CMAKE_TLS_VERIFY 环境变量中的任何一个,则行为将由 git 的默认值(true)或用户可能在全局级别设置的 http.sslVerify git 配置选项决定。

3.6 版本发生变化:此前,此选项不适用于 git clone 调用。

3.30 版本发生变化:此前,未检查 CMAKE_TLS_VERIFY 环境变量。

TLS_CAINFO <file>

如果启用了 TLS_VERIFY,则指定要使用的自定义证书颁发机构文件。如果未指定此选项,将使用 CMAKE_TLS_CAINFO 变量的值(参见 file(DOWNLOAD))。

NETRC <level>

3.11 版本新增。

指定是否将 .netrc 文件用于操作。如果未指定此选项,将使用 CMAKE_NETRC 变量的值(参见 file(DOWNLOAD))。有效级别为:

IGNORED

.netrc 文件被忽略。这是默认值。

OPTIONAL

.netrc 文件是可选的,URL 中的信息优先。文件将被扫描以查找 URL 中未指定的任何信息。

REQUIRED

.netrc 文件是必需的,URL 中的信息被忽略。

NETRC_FILE <file>

3.11 版本新增。

如果 NETRC 级别为 OPTIONALREQUIRED,则指定您主目录中 .netrc 文件的替代文件。如果未指定此选项,将使用 CMAKE_NETRC_FILE 变量的值(参见 file(DOWNLOAD))。

在 3.1 版本中新增:增加了对 tbz2.tar.xz.txz.7z 扩展的支持。

在 4.1 版本中新增:支持 cmake -E tar 可以提取的所有存档类型,无论文件扩展名如何。

Git

注意:如果使用此下载方法,则需要 Git 1.6.5 或更高版本。

GIT_REPOSITORY <url>

Git 仓库的 URL。可以使用 git 命令能理解的任何 URL。

3.27 版本发生变化:相对 URL 将根据父项目的远程仓库解析,受 CMP0150 策略影响。有关如何选择远程仓库(包括远程仓库选择失败的条件)的详细信息,请参阅策略文档。本地文件系统远程仓库应始终使用绝对路径。

GIT_TAG <tag>

Git 分支名称、标签或提交哈希。请注意,分支名称和标签通常应指定为远程名称(即 origin/myBranch 而不是简单的 myBranch)。这确保了如果远程端的标签移动或分支变基或历史重写,本地克隆仍将正确更新。然而,通常出于多种原因,应优先指定提交哈希:

  • 如果本地克隆已经拥有与哈希对应的提交,则每次重新运行 CMake 时无需执行 git fetch 来检查更改。如果使用了许多外部项目,这可以显著提高速度。

  • 使用特定的 git 哈希可以确保主项目自身的历史可以完全追溯到外部项目演变中的特定点。如果使用分支或标签名称,则检出主项目的特定提交不一定能将整个构建固定到外部项目生命周期中的特定点。这种非确定性行为导致主项目失去可追溯性和可重复性。

如果启用了 GIT_SHALLOW,则 GIT_TAG 仅适用于分支名称和标签。不允许使用提交哈希。

请注意,如果未提供 GIT_TAG,则默认为 master,而不是默认的 Git 分支名称。

GIT_REMOTE_NAME <name>

可选的远程名称。如果未指定此选项,则默认为 origin

GIT_SUBMODULES <module>...

也应更新的特定 git 子模块。如果未提供此选项,则所有 git 子模块都将更新。

3.16 版本发生变化:CMP0097 设置为 NEW 时,如果此值设置为空字符串,则不初始化或更新任何子模块。

GIT_SUBMODULES_RECURSE <bool>

在 3.17 版本中添加。

指定 git 子模块(如果有)是否应通过将 --recursive 标志传递给 git submodule update 来递归更新。如果未指定,则默认为启用。

GIT_SHALLOW <bool>

3.6 版本新增。

启用此选项后,git clone 操作将获得 --depth 1 选项。这将执行浅克隆,避免下载整个历史记录,而只检索由 GIT_TAG 选项指示的提交。

GIT_PROGRESS <bool>

版本 3.8 新增。

启用此选项后,它会指示 git clone 操作通过传递 --progress 选项来报告其进度。如果没有此选项,大型项目的克隆步骤可能会使构建看似停滞,因为在克隆操作完成之前不会记录任何内容。虽然此选项可用于提供进度以防止构建看似停滞,但如果使用大量外部项目,它也可能使构建过于嘈杂。

GIT_CONFIG <option1> [<option2>...]

版本 3.8 新增。

指定要传递给 git clone 的配置选项列表。列出的每个选项都将转换为其自己的 --config <option>git clone 命令行上,每个选项都要求采用 key=value 形式。

GIT_REMOTE_UPDATE_STRATEGY <strategy>

在 3.18 版本中新增。

GIT_TAG 指的是远程分支时,此选项可用于指定更新步骤的行为。<strategy> 必须是以下之一:

CHECKOUT

忽略本地分支,始终检出 GIT_TAG 指定的分支。

REBASE

尝试将当前分支变基到 GIT_TAG 指定的分支。如果有本地未提交的更改,它们将首先被暂存,并在变基后再次弹出。如果变基或弹出暂存的更改失败,则中止变基并报错。当 GIT_REMOTE_UPDATE_STRATEGY 不存在时,这是默认策略,除非默认策略已被 CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY 覆盖(见下文)。请注意,如果 GIT_TAG 中指定的分支与当前跟踪的上游分支不同,则执行变基不安全。在这种情况下,REBASE 将被静默地视为 CHECKOUT

REBASE_CHECKOUT

REBASE 相同,但如果变基失败,则在变基前原始的 HEAD 位置创建一个带注释的标签,然后像 CHECKOUT 策略一样检出 GIT_TAG。带注释的标签上存储的消息将提供有关尝试内容的详细信息,并且标签名称将包含时间戳,以便每次失败运行都会添加一个新标签。此策略确保不会丢失任何更改,但如果 GIT_TAG 指的是有效引用,则更新应始终成功,除非存在无法成功弹出的未提交更改。

变量 CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY 可以设置为覆盖默认策略。此变量不应由项目设置,它旨在供用户设置。它主要用于持续集成脚本中,以确保当远程分支上的历史被重写时,构建不会因变基操作期间的冲突而导致意外更改或构建失败。

Subversion

SVN_REPOSITORY <url>

Subversion 仓库的 URL。

SVN_REVISION -r<rev>

从 Subversion 仓库检出的版本。

SVN_USERNAME <username>

Subversion 检出和更新的用户名。

SVN_PASSWORD <password>

Subversion 检出和更新的密码。

SVN_TRUST_CERT <bool>

指定是否信任 Subversion 服务器站点证书。如果启用,则 --trust-server-cert 选项将传递给 svn 检出和更新命令。

Mercurial

HG_REPOSITORY <url>

Mercurial 仓库的 URL。

HG_TAG <tag>

Mercurial 分支名称、标签或提交 ID。

CVS

CVS_REPOSITORY <cvsroot>

CVS 仓库的 CVSROOT。

CVS_MODULE <mod>

从 CVS 仓库检出的模块。

CVS_TAG <tag>

从 CVS 仓库检出的标签。

更新步骤选项

每次重新运行 CMake 时,默认情况下,如果下载方法支持更新(例如,如果 GIT_TAG 未引用特定提交,则会检查 Git 仓库),外部项目的源文件将更新。

UPDATE_COMMAND <cmd>...

使用自定义命令覆盖下载方法的更新步骤。该命令可以使用 生成器表达式

UPDATE_DISCONNECTED <bool>

版本 3.2 中新增。

启用此选项时,将跳过更新步骤(但请参见下面的行为更改,此处并非如此)。它不会阻止下载步骤。更新步骤仍可以作为步骤目标添加(参见 ExternalProject_Add_StepTargets())并手动调用。这在您希望开发人员在断开网络连接时(下载步骤可能仍需要网络)构建项目时很有用。

3.27 版本发生变化:UPDATE_DISCONNECTED 为 true 时,如果更新或下载步骤的任何详细信息发生更改,则将执行更新步骤。此外,如果使用 git 下载/更新方法,更新逻辑将被修改以跳过尝试联系远程服务器。如果 GIT_TAG 提及了本地未知的引用,则更新步骤将因致命错误而停止。

当此选项存在时,通常建议将其值设为开发人员控制的缓存变量,而不是硬编码。如果此选项不存在,则默认值取自 EP_UPDATE_DISCONNECTED 目录属性。如果该属性也未定义,则更新将正常执行。EP_UPDATE_DISCONNECTED 目录属性旨在方便地控制项目目录层次结构中整个部分的 UPDATE_DISCONNECTED 行为,并且可能是让开发人员控制是否执行更新的更便捷方法(假设项目也提供了一个缓存变量或一些其他便捷方法来设置目录属性)。

这可能导致为 download 步骤自动创建步骤目标。请参见策略 CMP0114

补丁步骤选项

PATCH_COMMAND <cmd>...

指定一个自定义命令,用于在更新后修补源文件。默认情况下,未定义补丁命令。请注意,定义一个能够稳健执行的适当补丁命令可能相当困难,特别是对于像 git 这样的下载方法,更改 GIT_TAG 不会丢弃以前补丁的更改,但在更新到新标签后,补丁命令将再次被调用。

配置步骤选项

配置步骤在下载和更新步骤之后运行。默认情况下,外部项目被假定为 CMake 项目,但如果需要,可以覆盖此设置。

CONFIGURE_COMMAND <cmd>...

默认的配置命令根据主项目运行 CMake,带有一些选项。添加的选项通常只包括使用与主项目相同的生成器所需的选项,但可以给出 CMAKE_GENERATOR 选项以覆盖此设置。项目负责添加它希望从主项目重用或另行指定的任何工具链详细信息、标志或其他设置(请参阅下面的 CMAKE_ARGSCMAKE_CACHE_ARGSCMAKE_CACHE_DEFAULT_ARGS)。

对于非 CMake 外部项目,必须使用 CONFIGURE_COMMAND 选项来覆盖默认配置命令(支持生成器表达式)。对于不需要配置步骤的项目,请为此选项指定空字符串作为要执行的命令。

CMAKE_COMMAND /.../cmake

为配置步骤指定一个替代的 cmake 可执行文件(使用绝对路径)。通常不建议这样做,因为通常希望在整个构建中使用相同的 CMake 版本。如果已通过 CONFIGURE_COMMAND 指定了自定义配置命令,则此选项将被忽略。

CMAKE_GENERATOR <gen>

覆盖配置步骤使用的 CMake 生成器。如果没有此选项,将使用与主构建相同的生成器。如果已通过 CONFIGURE_COMMAND 选项指定了自定义配置命令,则此选项将被忽略。

CMAKE_GENERATOR_PLATFORM <platform>

版本 3.1 中新增。

向 CMake 命令传递生成器特定的平台名称(参见 CMAKE_GENERATOR_PLATFORM)。如果未提供 CMAKE_GENERATOR 选项而提供此选项,则会报错。

CMAKE_GENERATOR_TOOLSET <toolset>

向 CMake 命令传递生成器特定的工具集名称(参见 CMAKE_GENERATOR_TOOLSET)。如果未提供 CMAKE_GENERATOR 选项而提供此选项,则会报错。

CMAKE_GENERATOR_INSTANCE <instance>

3.11 版本新增。

向 CMake 命令传递生成器特定的实例选择(参见 CMAKE_GENERATOR_INSTANCE)。如果未提供 CMAKE_GENERATOR 选项而提供此选项,则会报错。

CMAKE_ARGS <arg>...

指定的参数将传递给 cmake 命令行。它们可以是 cmake 命令能够理解的任何参数,而不仅仅是 -D... 参数定义的缓存值(另请参阅 CMake 选项)。

3.3 版本新增:参数可以使用 生成器表达式

CMAKE_CACHE_ARGS <arg>...

这是指定缓存变量的另一种方法,当命令行长度可能成为问题时。预期参数形式为 -Dvar:STRING=value,然后将其转换为带有 FORCE 选项的 CMake set() 命令。这些 set() 命令写入预加载脚本,然后通过 cmake -C 命令行选项应用。

3.3 版本新增:参数可以使用 生成器表达式

CMAKE_CACHE_DEFAULT_ARGS <arg>...

版本 3.2 中新增。

这与 CMAKE_CACHE_ARGS 选项相同,只是 set() 命令不包含 FORCE 关键字。这意味着这些值仅作为初始默认值,不会覆盖先前运行中已设置的任何变量。请谨慎使用此选项,因为它可能导致不同的行为,具体取决于构建是开始于新的构建目录还是重用以前的构建内容。

3.15 版本新增:如果 CMake 生成器是 Green Hills MULTI 且未被覆盖,则原始项目的 GHS 工具集和目标系统自定义缓存变量设置将传播到外部项目。

SOURCE_SUBDIR <dir>

3.7 版本中新增。

当未指定 CONFIGURE_COMMAND 选项时,配置步骤假定外部项目在其源树的顶部(即在 SOURCE_DIR 中)有一个 CMakeLists.txt 文件。SOURCE_SUBDIR 选项可用于指向源树中要用作 CMake 源树顶部的替代目录。这必须是相对路径,并将被解释为相对于 SOURCE_DIR

3.14 版本新增:当启用 BUILD_IN_SOURCE 选项时,BUILD_COMMAND 将用于指向源树中的替代目录。

CONFIGURE_HANDLED_BY_BUILD <bool>

在 3.20 版本中添加。

启用此选项会将配置步骤对其他外部项目的依赖关系放宽为仅排序。这意味着配置步骤将在其外部项目依赖项构建之后执行,但当其外部项目依赖项重建时,它不会被标记为脏。当构建步骤足够智能,能够判断配置步骤是否需要重新运行时,可以启用此选项。CMake 和 Meson 是构建系统的示例,它们的构建步骤足够智能,能够判断配置步骤是否需要重新运行。

构建步骤选项

如果配置步骤假定外部项目使用 CMake 作为其构建系统,则构建步骤也将如此。否则,构建步骤将假定基于 Makefile 的构建,并简单地运行不带参数的 make 作为默认构建步骤。如果需要,这可以通过自定义构建命令进行覆盖。

如果主项目和外部项目都使用 make 作为其构建工具,则外部项目的构建步骤将作为递归 make 使用 $(MAKE) 调用。这将把主项目的一些构建工具设置传递给外部项目。如果主项目或外部项目未使用 make,则除了配置步骤建立的设置(即,在主项目中运行 ninja -v 不会将 -v 传递给外部项目的构建步骤,即使它也使用 ninja 作为其构建工具)之外,不会将任何构建工具设置传递给外部项目。

BUILD_COMMAND <cmd>...

覆盖默认构建命令(支持生成器表达式)。如果未给出此选项,则将选择默认构建命令以最合适的方式与主构建集成(例如,对于 Makefile 生成器使用递归 make,如果项目使用 CMake 构建则使用 cmake --build)。此选项可以指定空字符串作为命令,以使构建步骤不执行任何操作。

BUILD_IN_SOURCE <bool>

启用此选项后,构建将直接在外部项目的源树中完成。这通常应避免,通常优先使用单独的构建目录,但在外部项目假定源内构建时可能有用。如果在源内构建,则不应指定 BINARY_DIR 选项。

BUILD_ALWAYS <bool>

启用此选项会强制始终运行构建步骤。这可能是确保可靠评估外部项目自身构建依赖项的最简单方法,而不是依赖于默认的基于成功时间戳的方法。除非开发人员预期以无法通过步骤目标依赖项检测到的方式修改外部项目构建所依赖的某些内容(例如,SOURCE_DIR 在没有下载方法的情况下使用,并且开发人员可能会修改 SOURCE_DIR 中的源文件),否则通常不需要此选项。

BUILD_BYPRODUCTS <file>...

版本 3.2 中新增。

指定将由构建命令生成的文件,但这些文件在后续构建中可能会或可能不会更新其修改时间。在使用 Ninja 生成器时,这也可能需要明确声明依赖项。这些最终将作为 BYPRODUCTS 传递给构建步骤自身的底层 add_custom_command() 调用,该调用有额外的文档。

BUILD_JOB_SERVER_AWARE <bool>

版本 3.28 新增。

指定构建步骤是否感知 GNU Make 作业服务器。有关详细信息,请参阅 add_custom_command() 文档中的 JOB_SERVER_AWARE 选项。此选项仅在指定显式 BUILD_COMMAND 时才相关。

安装步骤选项

如果配置步骤假定外部项目使用 CMake 作为其构建系统,则安装步骤也将如此。否则,安装步骤将假定基于 Makefile 的构建,并简单地运行 make install 作为默认构建步骤。如果需要,这可以通过自定义安装命令进行覆盖。

INSTALL_COMMAND <cmd>...

外部项目自身的安装步骤作为主项目 *构建* 的一部分调用。它在外部项目的构建步骤之后执行,并且可能在外部项目的测试步骤之前或之后(参见下面的 TEST_BEFORE_INSTALL 选项)。外部项目的安装规则不属于主项目的安装规则,因此如果外部项目中的任何内容应作为主构建的一部分安装,则需要在主构建中将其指定为附加的 install() 命令。默认安装步骤构建外部项目的 install 目标,但这可以使用此选项通过自定义命令覆盖(支持生成器表达式)。传递空字符串作为 <cmd> 会使安装步骤不执行任何操作。

INSTALL_BYPRODUCTS <file>...

3.26 版新增。

指定将由安装命令生成的文件,但这些文件在后续安装中可能会或可能不会更新其修改时间。在使用 Ninja 生成器时,这也可能需要明确声明依赖项。这些最终将作为 BYPRODUCTS 传递给安装步骤自身的底层 add_custom_command() 调用,该调用有额外的文档。

INSTALL_JOB_SERVER_AWARE <bool>

4.0 版本新增。

指定安装步骤是否感知 GNU Make 作业服务器。有关详细信息,请参阅 add_custom_command() 文档中的 JOB_SERVER_AWARE 选项。此选项仅在指定显式 INSTALL_COMMAND 时才相关。

注意

如果在构建主项目时设置了 CMAKE_INSTALL_MODE 环境变量,它只有在满足以下条件时才会生效:

  • 主项目的配置步骤假定外部项目使用 CMake 作为其构建系统。

  • 外部项目的安装命令实际运行。请注意,由于 ExternalProject 内部使用时间戳的方式,如果安装步骤所依赖的任何内容都不需要重新执行,则安装命令也可能不需要运行。

另请注意,ExternalProject 不会检查 CMAKE_INSTALL_MODE 环境变量是否在不同运行之间发生变化。

测试步骤选项

测试步骤仅在至少提供了以下 TEST_... 选项之一时才定义。

TEST_COMMAND <cmd>...

覆盖默认测试命令(支持生成器表达式)。如果未给出此选项,则测试步骤的默认行为是构建外部项目自身的 test 目标。此选项可以指定 <cmd> 为空字符串,这允许测试步骤仍然定义,但它将不执行任何操作。如果将空字符串作为测试命令提供,则不要指定其他任何 TEST_... 选项,但如果不需要测试步骤目标,则最好完全省略所有 TEST_... 选项。

TEST_BEFORE_INSTALL <bool>

启用此选项后,测试步骤将在安装步骤之前执行。默认行为是测试步骤在安装步骤之后运行。

TEST_AFTER_INSTALL <bool>

此选项主要用作指示需要测试步骤但所有默认行为都足够的方式。将此选项设置为布尔真值可确保定义测试步骤且其在安装步骤之后执行。如果同时启用了 TEST_BEFORE_INSTALLTEST_AFTER_INSTALL,则后者将被静默忽略。

TEST_EXCLUDE_FROM_MAIN <bool>

版本 3.2 中新增。

如果启用,主构建的默认 ALL 目标将不依赖于测试步骤。这是一种确保定义测试步骤但仅在手动请求时才调用的有用方法。这可能导致为 installbuild 步骤自动创建步骤目标。请参见策略 CMP0114

输出日志选项

以下每个 LOG_... 选项都可用于将相关步骤封装在脚本中,以将其输出捕获到文件中。日志文件将创建在 LOG_DIR(如果提供)或 STAMP_DIR 目录中,并带有步骤特定的文件名。

LOG_DOWNLOAD <bool>

启用后,下载步骤的输出将记录到文件中。

LOG_UPDATE <bool>

启用后,更新步骤的输出将记录到文件中。

LOG_PATCH <bool>

3.14 版新增。

启用后,补丁步骤的输出将记录到文件中。

LOG_CONFIGURE <bool>

启用后,配置步骤的输出将记录到文件中。

LOG_BUILD <bool>

启用后,构建步骤的输出将记录到文件中。

LOG_INSTALL <bool>

启用后,安装步骤的输出将记录到文件中。

LOG_TEST <bool>

启用后,测试步骤的输出将记录到文件中。

LOG_MERGED_STDOUTERR <bool>

3.14 版新增。

启用后,任何输出正在记录到文件中的步骤的标准输出和标准错误将被合并。

LOG_OUTPUT_ON_FAILURE <bool>

3.14 版新增。

此选项仅在至少一个其他 LOG_<step> 选项启用时才生效。如果对启用了文件日志记录的步骤发生错误,并且 LOG_OUTPUT_ON_FAILURE 设置为 true,则该步骤的输出将打印到控制台。对于记录大量输出的情况,可能只将输出的末尾打印到控制台。

终端访问选项

3.4 版本新增。

在某些情况下,步骤可以直接访问终端。允许某个步骤访问终端可能允许它在需要时接收终端输入,例如其他选项未提供的身份验证详细信息。对于 Ninja 生成器,这些选项将步骤放置在 console job pool 中。每个步骤都可以通过以下选项单独授予终端访问权限:

USES_TERMINAL_DOWNLOAD <bool>

授予下载步骤终端访问权限。

USES_TERMINAL_UPDATE <bool>

授予更新步骤终端访问权限。

USES_TERMINAL_PATCH <bool>

在版本 3.23 中添加。

授予补丁步骤终端访问权限。

USES_TERMINAL_CONFIGURE <bool>

授予配置步骤终端访问权限。

USES_TERMINAL_BUILD <bool>

授予构建步骤终端访问权限。

USES_TERMINAL_INSTALL <bool>

授予安装步骤终端访问权限。

USES_TERMINAL_TEST <bool>

授予测试步骤终端访问权限。

目标选项

DEPENDS <targets>...

指定外部项目所依赖的其他目标。在执行外部项目的任何步骤之前,这些其他目标将被更新。由于外部项目内部为每个步骤使用额外的自定义目标,因此 DEPENDS 选项是确保所有这些步骤都依赖于其他目标的最便捷方式。简单地执行 add_dependencies(<name> <targets>) 不会使任何步骤依赖于 <targets>

EXCLUDE_FROM_ALL <bool>

启用此选项后,外部项目将从主构建的默认 ALL 目标中排除。

STEP_TARGETS <step-target>...

为指定的步骤生成自定义目标。如果步骤需要手动触发或需要用作其他目标的依赖项,则需要此选项。如果未指定此选项,则默认值取自 EP_STEP_TARGETS 目录属性。有关此选项效果的进一步讨论,请参阅下面的 ExternalProject_Add_StepTargets()

INDEPENDENT_STEP_TARGETS <step-target>...

自 3.19 版本弃用:仅当策略 CMP0114 未设置为 NEW 时才允许此操作。

为指定步骤生成自定义目标,并防止这些目标应用常规依赖关系。如果未指定此选项,则默认值取自EP_INDEPENDENT_STEP_TARGETS目录属性。此选项主要用于允许独立驱动各个步骤,例如,在CDash设置中,每个步骤应单独启动和报告,而不是作为一个整体构建。有关此选项影响的进一步讨论,请参阅下面的ExternalProject_Add_StepTargets()

杂项选项

LIST_SEPARATOR <sep>

对于各种..._COMMAND选项和CMAKE_ARGSExternalProject将在指定的命令行中将<sep>替换为;。这可以用来确保命令中包含字面量的;,否则直接使用会被解释为CMake API的参数分隔符。请注意,应选择分隔符以避免与序列的非列表分隔符用法混淆。例如,使用LIST_SEPARATOR可以在命令行中将列表值传递给CMake缓存变量

ExternalProject_Add(example
  ... # Download options, etc.
  LIST_SEPARATOR ","
  CMAKE_ARGS "-DCMAKE_PREFIX_PATH:STRING=${first_prefix},${second_prefix}"
)
COMMAND <cmd>...

任何其他..._COMMAND选项可以通过在其后附加所需数量的COMMAND ...选项来追加额外的命令(支持generator expressions)。例如

ExternalProject_Add(example
  ... # Download options, etc.
  BUILD_COMMAND ${CMAKE_COMMAND} -E echo "Starting $<CONFIG> build"
  COMMAND       ${CMAKE_COMMAND} --build <BINARY_DIR> --config $<CONFIG>
  COMMAND       ${CMAKE_COMMAND} -E echo "$<CONFIG> build complete"
)

还应注意,每个构建步骤都是通过调用ExternalProject_Add_Step()创建的。有关某些选项支持的自动替换,请参阅该命令的文档。

获取项目属性

ExternalProject_Get_Property

ExternalProject_Get_Property()函数检索外部项目目标属性

ExternalProject_Get_Property(<name> <prop1> [<prop2>...])

该函数将属性值存储在同名变量中。属性名称对应于ExternalProject_Add()的关键字参数名称。例如,可以这样检索源目录

ExternalProject_Get_property(myExtProj SOURCE_DIR)
message("Source dir of myExtProj = ${SOURCE_DIR}")

显式步骤管理

ExternalProject_Add()函数本身通常足以将外部项目纳入主构建。某些场景需要额外的工作来实现所需行为,例如添加自定义步骤或使步骤作为手动触发目标可用。ExternalProject_Add_Step()ExternalProject_Add_StepTargets()ExternalProject_Add_StepDependencies函数提供了实现此类步骤级别功能所需的底层控制。

ExternalProject_Add_Step

ExternalProject_Add_Step()函数为通过先前调用ExternalProject_Add()定义的外部项目指定一个额外的自定义步骤

ExternalProject_Add_Step(<name> <step> [<option>...])

<name>与最初调用ExternalProject_Add()时传递的名称相同。指定的<step>不能是预定义步骤之一(mkdirdownloadupdatepatchconfigurebuildinstalltest)。支持的选项有

COMMAND <cmd>...

此自定义步骤要执行的命令行(支持generator expressions)。此选项可以重复多次,以指定要按顺序执行的多个命令。

COMMENT "<text>..."

执行自定义步骤时要打印的文本。

DEPENDEES <step>...

此步骤依赖的其他步骤(自定义或预定义)。

DEPENDERS <step>...

依赖于此新自定义步骤的其他步骤(自定义或预定义)。

DEPENDS <file>...

此自定义步骤依赖的文件。

INDEPENDENT <bool>

3.19 版本新增。

指定此步骤是否独立于ExternalProject_Add()DEPENDS选项指定的外部依赖项。默认值为FALSE。标记为独立的步骤只能依赖于其他标记为独立的步骤。请参阅策略CMP0114

请注意,“独立”一词在此处的使用仅指独立于DEPENDS选项指定的外部目标,并且与步骤对其他步骤的依赖性是正交的。

如果ExternalProject_Add()STEP_TARGETS选项或ExternalProject_Add_StepTargets()函数为独立步骤创建了步骤目标,则它将不依赖于外部目标,但可能依赖于其他步骤的目标。

BYPRODUCTS <file>...

版本 3.2 中新增。

此自定义步骤将生成的文件,但其修改时间可能或可能不会由后续构建更新。在使用Ninja生成器时,可能还需要显式声明依赖项。此文件列表最终将作为BYPRODUCTS选项传递给内部用于实现自定义步骤的add_custom_command(),其中包含额外文档。

ALWAYS <bool>

启用此选项后,它指定自定义步骤应始终运行(即始终被视为过期)。

JOB_SERVER_AWARE <bool>

版本 3.28 新增。

指定自定义步骤知道GNU Make作业服务器。有关详细信息,请参阅add_custom_command()JOB_SERVER_AWARE选项的文档。

EXCLUDE_FROM_MAIN <bool>

启用此选项后,它指定外部项目的主目标不依赖于自定义步骤。这可能会导致为该步骤所依赖的步骤自动创建步骤目标。请参阅策略CMP0114

WORKING_DIRECTORY <dir>

指定在运行自定义步骤命令之前要设置的工作目录。如果未指定此选项,则目录将是调用ExternalProject_Add_Step()CMAKE_CURRENT_BINARY_DIR的值。

LOG <bool>

如果设置,这将导致自定义步骤的输出被捕获到外部项目的LOG_DIR(如果提供)或STAMP_DIR中的文件。

USES_TERMINAL <bool>

如果启用,这将使自定义步骤尽可能直接访问终端。

每个标准和自定义步骤的命令行、注释、工作目录和副产品都经过处理,以将令牌<SOURCE_DIR><SOURCE_SUBDIR><BINARY_DIR><INSTALL_DIR><TMP_DIR><DOWNLOAD_DIR><DOWNLOADED_FILE>替换为最初调用ExternalProject_Add()中定义的相应属性值。

版本3.3新增:令牌替换扩展到副产品。

版本3.11新增:<DOWNLOAD_DIR>替换令牌。

ExternalProject_Add_StepTargets

ExternalProject_Add_StepTargets()函数为列出的步骤生成目标。每个创建的目标的名称将采用<name>-<step>的形式

ExternalProject_Add_StepTargets(<name> <step1> [<step2>...])

为步骤创建目标允许它作为另一个目标的依赖项或手动触发。为特定步骤设置目标还允许通过在构建命令行上指定目标来独立驱动它们。例如,您可能正在向基于子项目的仪表板提交,您希望驱动构建的配置部分,然后提交到仪表板,接着是构建部分,然后是测试。如果您调用依赖于步骤依赖链中途的自定义目标,则所有先前的步骤也将运行以确保一切都是最新的。

在内部,ExternalProject_Add()调用ExternalProject_Add_Step()来创建每个步骤。如果指定了任何STEP_TARGETS,则在ExternalProject_Add_Step()之后也将调用ExternalProject_Add_StepTargets()。即使STEP_TARGETS选项中未提及某个步骤,也可以稍后手动调用ExternalProject_Add_StepTargets()来为该步骤定义目标。

ExternalProject_Add()STEP_TARGETS选项通常是确保为感兴趣的特定步骤创建目标的最简单方法。对于自定义步骤,如果也应为该自定义步骤创建目标,则必须显式调用ExternalProject_Add_StepTargets()。这两个选项的替代方法是填充EP_STEP_TARGETS目录属性。它作为步骤目标选项的默认值,并且在定义多个外部项目时可以避免重复指定相同的步骤目标集。

版本3.19新增:如果CMP0114设置为NEW,则步骤目标完全负责保存实现其步骤的自定义命令。ExternalProject_Add创建的主目标依赖于步骤目标,并且步骤目标相互依赖。目标级别的依赖项与每个步骤的自定义命令使用的文件级别的依赖项匹配。使用ExternalProject_Add_Step()INDEPENDENT选项创建的步骤的目标不依赖于ExternalProject_Add()DEPENDS选项指定的外部目标。预定义的步骤mkdirdownloadupdatepatch是独立的。

如果CMP0114不是NEW,则以下废弃行为可用

  • 废弃的NO_DEPENDS选项可以在<name>之后和第一个步骤之前立即指定。如果指定了NO_DEPENDS选项,则步骤目标将不依赖于外部项目的依赖项(即,不依赖于ExternalProject_Add()创建的<name>自定义目标的任何依赖项)。这对于downloadupdatepatch步骤通常是安全的,因为它们通常不需要更新和构建依赖项。然而,将NO_DEPENDS用于任何其他预定义步骤可能会破坏并行构建。仅当确定命名步骤确实没有依赖项时才使用NO_DEPENDS。对于自定义步骤,请考虑自定义命令是否需要配置、构建和安装依赖项。

  • ExternalProject_Add()INDEPENDENT_STEP_TARGETS选项,或EP_INDEPENDENT_STEP_TARGETS目录属性,告诉函数在内部使用NO_DEPENDS选项调用ExternalProject_Add_StepTargets()以用于指定的步骤。

ExternalProject_Add_StepDependencies

版本 3.2 中新增。

ExternalProject_Add_StepDependencies()函数可用于向步骤添加依赖项。添加的依赖项必须是CMake已经知道的目标(这些可以是普通的执行文件或库目标、自定义目标,甚至是另一个外部项目的步骤目标)

ExternalProject_Add_StepDependencies(<name> <step> <target1> [<target2>...])

此函数负责设置目标和文件级别的依赖项,并将确保并行构建不会中断。在为ExternalProject模块生成的某些步骤目标添加依赖项时,应使用它而不是add_dependencies()

示例

以下示例演示了如何从github下载和构建一个名为*FooBar*的假设项目

include(ExternalProject)
ExternalProject_Add(foobar
  GIT_REPOSITORY    git@github.com:FooCo/FooBar.git
  GIT_TAG           origin/release/1.2.3
)

为了示例,还定义了第二个名为*SecretSauce*的假设外部项目,该项目从Web服务器下载。给出了两个URL以利用可用的更快内部网络,并回退到较慢的外部服务器。该项目是一个典型的Makefile项目,没有配置步骤,因此覆盖了一些默认命令。构建仅需要构建*sauce*目标

find_program(MAKE_EXE NAMES gmake nmake make)
ExternalProject_Add(secretsauce
  URL               http://intranet.somecompany.com/artifacts/sauce-2.7.tgz
                    https://www.somecompany.com/downloads/sauce-2.7.zip
  URL_HASH          MD5=d41d8cd98f00b204e9800998ecf8427e
  CONFIGURE_COMMAND ""
  BUILD_COMMAND     ${MAKE_EXE} sauce
)

假设secretsauce的构建步骤要求foobar必须已经构建。这可以这样强制执行

ExternalProject_Add_StepDependencies(secretsauce build foobar)

另一种替代方法是为foobar的构建步骤创建一个自定义目标,并使secretsauce依赖于该目标而不是整个foobar项目。这意味着foobar只需构建,它不需要在secretsauce构建之前运行其安装或测试步骤。依赖项也可以与secretsauce项目一起定义

ExternalProject_Add_StepTargets(foobar build)
ExternalProject_Add(secretsauce
  URL               http://intranet.somecompany.com/artifacts/sauce-2.7.tgz
                    https://www.somecompany.com/downloads/sauce-2.7.zip
  URL_HASH          MD5=d41d8cd98f00b204e9800998ecf8427e
  CONFIGURE_COMMAND ""
  BUILD_COMMAND     ${MAKE_EXE} sauce
  DEPENDS           foobar-build
)

不必调用ExternalProject_Add_StepTargets(),可以在foobar项目本身中定义目标

ExternalProject_Add(foobar
  GIT_REPOSITORY git@github.com:FooCo/FooBar.git
  GIT_TAG        origin/release/1.2.3
  STEP_TARGETS   build
)

如果许多外部项目应具有相同的步骤目标集,则设置目录属性可能更方便。可以通过在创建带有ExternalProject_Add()的外部项目之前设置EP_STEP_TARGETS目录属性来自动创建build步骤目标

set_property(DIRECTORY PROPERTY EP_STEP_TARGETS build)

最后,假设secretsauce提供了一个名为makedoc的脚本,可用于生成其自身的文档。进一步假设该脚本期望输出目录作为唯一的参数提供,并且应从secretsauce源目录运行。可以这样定义自定义步骤和用于触发脚本的自定义目标

ExternalProject_Add_Step(secretsauce docs
  COMMAND           <SOURCE_DIR>/makedoc <BINARY_DIR>
  WORKING_DIRECTORY <SOURCE_DIR>
  COMMENT           "Building secretsauce docs"
  ALWAYS            TRUE
  EXCLUDE_FROM_MAIN TRUE
)
ExternalProject_Add_StepTargets(secretsauce docs)

然后,可以这样从主构建触发自定义步骤

cmake --build . --target secretsauce-docs