news 2026/10/3 8:21:42

CMake get_property 命令完全指南:十种作用域属性读取与源码实现解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CMake get_property 命令完全指南:十种作用域属性读取与源码实现解析
  • 构建工具
  • 开发工具
  • CLI

【免费下载链接】CMake

Mirror of CMake upstream repository

项目地址:https://gitcode.com/gh_mirrors/cm/CMake
点击查看免费下载

get_property是 CMake 中读取属性的通用入口命令,它从全局、目录、目标、源文件、测试、缓存等多种作用域中取回属性值并存入变量。本文以 get_property 官方文档 为主体,结合 CMake 源码实现与仓库测试用例,系统讲解其完整语法、十种作用域(Scope)的语义差异、SET/DEFINED/BRIEF_DOCS/FULL_DOCS四种输出模式,以及属性继承、错误行为等边界细节,读完即可在真实构建脚本中正确、灵活地使用该命令。

命令总览:统一属性读取入口

get_property从一个作用域中的一个对象上读取一个属性,并将结果存储到指定的变量中。其核心语法如下(来自 官方文档):

get_property(<variable> <GLOBAL | DIRECTORY [<dir>] | RULE <rule> | TARGET <target> | FILE_SET <file_set> TARGET <target> | SOURCE <source> [DIRECTORY <dir> | TARGET_DIRECTORY <target>] | INSTALL <file> | TEST <test> [DIRECTORY <dir>] | CACHE <entry> | VARIABLE> PROPERTY <name> [SET | DEFINED | BRIEF_DOCS | FULL_DOCS])
  • 第一个参数<variable>:结果存储的目标变量名。
  • 第二个参数:指定读取属性的作用域类型(Scope),必须是GLOBAL、DIRECTORY、RULE、TARGET、FILE_SET、SOURCE、INSTALL、TEST、CACHE、VARIABLE之一。
  • PROPERTY <name>:必填,指定要读取的属性名。
  • 末尾可选参数:SET、DEFINED、BRIEF_DOCS、FULL_DOCS,决定写入变量的是属性的值还是关于属性的信息(详见下文"四种输出模式")。

与专用命令的关系

get_property是通用形式,仓库中还提供了一批同类的"专用快捷命令",它们本质上是针对特定作用域的封装:

  • get_directory_property ——DIRECTORY作用域专用;
  • get_target_property ——TARGET作用域专用;
  • get_source_file_property ——SOURCE作用域专用;
  • get_test_property ——TEST作用域专用;
  • get_cmake_property —— 全局/目录信息的另一入口。

与读取相对的写入命令是 set_property,它支持相同的作用域列表,并额外提供APPEND与APPEND_STRING两种追加语义。属性本身的定义与继承行为由 define_property 管理。三者构成 CMake 属性系统的完整闭环:定义 → 设置 → 读取。

十种作用域逐一拆解

作用域参数决定了"从哪里读属性"。从源码实现看,作用域字符串是在 cmGetPropertyCommand.cxx 中被逐一映射为内部枚举cmProperty::ScopeType的;若传入无法识别的字符串,CMake 会直接报错given invalid scope ...并列出全部合法取值。

GLOBAL —— 全局命名空间

get_property(<variable> GLOBAL PROPERTY <name>)

全局作用域唯一,不接受名称参数(源码中若传入名称会报错given name for GLOBAL scope.,见 cmGetPropertyCommand.cxx)。常用于读取GENERATOR_IS_MULTI_CONFIG、CMAKE_C_KNOWN_FEATURES等全局属性。仓库自身大量使用这一形式,例如 CMakeInstall.cmake 中:

get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)

再如 CompileFeatures 测试 读取 CMake 已知的 C/C++ 语言特性列表:

get_property(c_features GLOBAL PROPERTY CMAKE_C_KNOWN_FEATURES) get_property(cxx_features GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES)

DIRECTORY —— 目录作用域

get_property(<variable> DIRECTORY [<dir>] PROPERTY <name>)
  • 不带<dir>时,读取当前目录(即调用该命令的CMakeLists.txt所在目录)的属性;
  • 带<dir>时,可读取另一个已被 CMake 处理过的目录的属性,<dir>可以是完整路径或相对路径,相对路径以当前源码目录为基准;
  • 自 CMake 3.19 起,<dir>还可以引用二进制目录;
  • 若指定的目录尚未被处理(例如尚未执行到add_subdirectory),会返回错误(源码错误信息见 cmGetPropertyCommand.cxx)。

RULE —— 自定义规则作用域(4.5 新增)

get_property(<variable> RULE <rule> PROPERTY <name>)
  • CMake 4.5 起新增。<rule>必须是当前目录中已由 add_custom_rule 创建的规则名;
  • 若规则不存在,报错could not find RULE ... Perhaps it has not yet been created.(见 cmGetPropertyCommand.cxx)。

仓库在 add_custom_rule 测试 中封装了规则属性读取的辅助函数:

function(check_rule_property rule property expected) get_property(value RULE ${rule} PROPERTY ${property}) if(NOT "${value}" STREQUAL "${expected}") string (APPEND TEST_FAILED "RULE ${rule}, PROPERTY ${property}: ...") endif() return(PROPAGATE TEST_FAILED) endfunction()

TARGET —— 目标作用域

get_property(<variable> TARGET <target> PROPERTY <name>)
  • <target>必须是已存在的目标;若目标未创建,报错could not find TARGET ...(见 cmGetPropertyCommand.cxx);
  • 目标不限于当前CMakeLists.txt,此前创建的任何目标都可查询(与 get_target_property 行为一致);
  • 属性未设置时,与get_target_property的<variable>-NOTFOUND行为不同,get_property会直接取消该变量的定义(详见下文"未设置属性的处理")。

仓库的 AliasTarget 测试 展示了通过别名(ALIAS)目标读取属性的用法,包括ALIASED_TARGET、IMPORTED、ALIAS_GLOBAL以及自定义属性LIB_PROPERTY:

add_library(lib empty.cpp) set_property (TARGET lib PROPERTY LIB_PROPERTY "LIB") add_library(alias::lib ALIAS lib) check_property (alias::lib ALIASED_TARGET "lib") check_property (alias::lib LIB_PROPERTY "LIB")

FILE_SET —— 文件集作用域(4.3 新增)

get_property(<variable> FILE_SET <file_set> TARGET <target> PROPERTY <name>)
  • CMake 4.3 起新增。<file_set>必须是已附加到<target>上的现有文件集,TARGET <target>为必填选项;
  • 文件集不存在时报错could not find FILE_SET ... for TARGET ...(见 cmGetPropertyCommand.cxx);
  • 常用于读取TYPE、SCOPE、BASE_DIRS、SOURCES、INTERFACE_SOURCES、LANGUAGE等文件集属性。

仓库 FileSetProperties 测试 给出完整读写示例:

add_library(foo STATIC) target_sources(foo PRIVATE FILE_SET sources TYPE SOURCES FILES foo.c) set_property(FILE_SET sources TARGET foo PROPERTY LANGUAGE CXX) get_property(language FILE_SET sources TARGET foo PROPERTY LANGUAGE) if(NOT language STREQUAL "CXX") message(SEND_ERROR "wrong language: '${language}' instead of 'CXX'") endif()

SOURCE —— 源文件作用域

get_property(<variable> SOURCE <source> [DIRECTORY <dir> | TARGET_DIRECTORY <target>] PROPERTY <name>)
  • 默认从当前源码目录的作用域读取该源文件的属性;
  • CMake 3.18 起支持两种覆盖目录范围的子选项:
    • DIRECTORY <dir>:从<dir>目录的作用域读取;CMake 必须已知该目录(通过add_subdirectory添加或为顶层目录),相对路径以当前源码目录为基准;3.19 起<dir>可以是二进制目录;
    • TARGET_DIRECTORY <target>:从创建<target>的目录作用域读取(目标必须已存在);
  • 若源文件无法找到或创建,报错given SOURCE name that could not be found or created: ...(见 cmGetPropertyCommand.cxx)。

INSTALL —— 安装文件作用域(3.1 新增)

get_property(<variable> INSTALL <file> PROPERTY <name>)
  • CMake 3.1 起新增。<file>必须是已声明的安装文件路径;
  • 该作用域主要用于向 CPack 传递部署相关信息,目前安装文件属性主要面向 WIX 生成器定义,路径相对安装前缀,需使用正斜杠、已归一化且区分大小写(详见 set_property 文档 中INSTALL段的说明);
  • 实现上通过GetOrCreateInstalledFile查找或创建安装文件记录(见 cmGetPropertyCommand.cxx)。

TEST —— 测试作用域

get_property(<variable> TEST <test> [DIRECTORY <dir>] PROPERTY <name>)
  • <test>必须是已存在的测试(通常由add_test创建);
  • CMake 3.28 起支持DIRECTORY <dir>覆盖目录作用域:从<dir>目录的作用域读取测试属性;CMake 必须已知该目录,相对路径以当前源码目录为基准,<dir>也可以引用二进制目录;
  • 测试不存在时报错given TEST name that does not exist: ...(见 cmGetPropertyCommand.cxx)。

CACHE —— 缓存条目作用域

get_property(<variable> CACHE <entry> PROPERTY <name>)
  • <entry>必须是已存在的缓存条目,读取的是该缓存条目的属性(例如TYPE、HELPSTRING、ADVANCED等),而非缓存条目本身的值——读取缓存变量的值应使用$CACHE{<entry>}语法或VARIABLE作用域配合缓存变量名;
  • 实现中通过GetCacheEntryValue判断条目是否存在、再经GetCacheEntryProperty取属性(见 cmGetPropertyCommand.cxx)。

VARIABLE —— 普通变量作用域

get_property(<variable> VARIABLE PROPERTY <name>)
  • 作用域唯一,不接受名称参数;
  • 语义等价于"读取一个普通 CMake 变量的值":把名为<name>的变量当前值写入<variable>(源码见 cmGetPropertyCommand.cxx)。

仓库 GetPropertyTest 对该作用域做了直接验证:

set(test_var alpha) get_property(result VARIABLE PROPERTY test_var) if(NOT result STREQUAL "alpha") message(SEND_ERROR "bad value of VARIABLE PROPERTY test_var: got '${result}' instead of 'alpha'") endif()

PROPERTY 与四种输出模式

PROPERTY :必填的属性名

PROPERTY选项后必须紧跟属性名。源码在解析完参数后会检查propertyName是否为空,否则报错not given a PROPERTY <name> argument.(见 cmGetPropertyCommand.cxx)。

默认模式:直接返回属性值

不带任何末尾选项时,属性值被写入<variable>:

  • 若属性已设置:变量被设为属性值;
  • 若属性未设置:变量在调用作用域内被取消定义(RemoveDefinition,见 cmGetPropertyCommand.cxx);
  • 特例:部分被定义为INHERITED行为的属性(见 define_property)支持向父作用域链式查找。

这一"未设置即取消变量"的行为,与get_target_property(未找到时置为<variable>-NOTFOUND)形成鲜明对比,是排查"变量为何是空"问题时常被忽略的关键差异。

SET:属性是否被显式设置

get_property(<variable> TARGET <target> PROPERTY <name> SET)

变量被设置为布尔值:属性已被设置时为1,否则为0。注意SET判断的是"是否显式设置过",与DEFINED(是否定义过该属性)语义不同。仓库在 AliasTarget 测试 中使用它:

get_property(_aliased_target_set TARGET foo PROPERTY ALIASED_TARGET SET)

DEFINED:属性是否已被定义

get_property(<variable> TARGET <target> PROPERTY <name> DEFINED)

变量被设为布尔值,表示该属性是否已被定义(例如通过 define_property 定义)。实现上直接查询状态机中的属性定义表(GetPropertyDefinition,见 cmGetPropertyCommand.cxx)。

BRIEF_DOCS / FULL_DOCS:读取属性文档

get_property(<variable> TARGET <target> PROPERTY <name> BRIEF_DOCS) get_property(<variable> TARGET <target> PROPERTY <name> FULL_DOCS)
  • 变量被设置为该属性的简要文档或完整文档字符串;
  • 若该属性从未被定义过(没有关联文档),返回NOTFOUND(见 cmGetPropertyCommand.cxx)。

仓库 GetPropertyTest 验证了未定义属性时两个模式均返回NOTFOUND:

get_property(FOO_BRIEF GLOBAL PROPERTY FOO BRIEF_DOCS) get_property(FOO_FULL GLOBAL PROPERTY FOO FULL_DOCS) if (NOT FOO_BRIEF STREQUAL "NOTFOUND") message(SEND_ERROR "property FOO has BRIEF_DOCS set to '${FOO_BRIEF}'") endif ()

而 define_property 测试 则系统验证了"定义过的属性能取到对应文档、未定义的返回 NOTFOUND":

define_property(TARGET PROPERTY PROP2 BRIEF_DOCS "Brief") define_property(TARGET PROPERTY PROP3 FULL_DOCS "Full") # ... assert_prop_scope_eq(PROP2 BRIEF_DOCS "Brief") assert_prop_scope_eq(PROP2 FULL_DOCS "NOTFOUND") assert_prop_scope_eq(PROP3 BRIEF_DOCS "NOTFOUND") assert_prop_scope_eq(PROP3 FULL_DOCS "Full")

属性继承(INHERITED)与 define_property 协同

get_property的继承行为由 define_property 的INHERITED选项控制:

  • 带INHERITED定义的属性,若在指定作用域未设置,get_property会向更高一级作用域链式查找:
    • DIRECTORY作用域沿父目录逐级上溯,直到顶层仍未找到则链到GLOBAL作用域;
    • TARGET、SOURCE、TEST属性链到DIRECTORY作用域,并继续按目录层级向上;
  • 继承只发生在读取时(get_property、get_directory_property、get_target_property、get_source_file_property、get_test_property);设置时不存在继承,因此 set_property 的APPEND/APPEND_STRING不会基于继承值追加,若属性未被显式设置,则行为等同未加APPEND/APPEND_STRING;
  • CMake 3.23 起,BRIEF_DOCS/FULL_DOCS变为可选,并新增INITIALIZE_FROM_VARIABLE(仅限目标属性,变量名必须以属性名结尾、不得以CMAKE_或_CMAKE_开头、属性名须含至少一个下划线,且建议带项目专属前缀);
  • 属性一经定义不可重定义(同作用域同属性名的重复define_property会被静默忽略),但同一属性名可分别用于不同作用域类型。

define_property 文档 给出了"定义 → 查询是否已定义 → 读取文档"的完整示例:

# Initial definition define_property(TARGET PROPERTY MY_NEW_PROP BRIEF_DOCS "My new custom property" ) # Later examination get_property(my_new_prop_exists TARGET NONE PROPERTY MY_NEW_PROP DEFINED ) if(my_new_prop_exists) get_property(my_new_prop_docs TARGET NONE PROPERTY MY_NEW_PROP BRIEF_DOCS ) # ${my_new_prop_docs} is now set to "My new custom property" endif()

注意其中TARGET NONE的写法:查询DEFINED/BRIEF_DOCS这类属性元信息时不需要真实目标存在——因为处理这些输出模式时根本不会执行目标查找,NONE只是一个占位名称。

常见错误与边界行为

从源码的参数解析(cmGetPropertyCommand.cxx)与各作用域处理器中可以归纳出以下易错点:

场景行为
参数少于 3 个报错called with incorrect number of arguments
作用域字符串不合法报错given invalid scope ...并列出合法取值
GLOBAL/VARIABLE后跟名称报错given name for GLOBAL scope./VARIABLE scope.
TARGET/SOURCE/TEST/CACHE/RULE/FILE_SET/INSTALL缺少名称报错not given name for ... scope.
目标/规则/文件集/测试不存在报错could not find ... Perhaps it has not yet been created.
未给出PROPERTY报错not given a PROPERTY <name> argument.
属性未设置(默认模式)变量在调用作用域中被取消定义
未定义属性 +BRIEF_DOCS/FULL_DOCS变量被设为NOTFOUND
GENERATED源文件属性可能全局可见(见 GENERATED 属性文档)

此外还有一个易被忽略的细节:FILE_SET的TARGET子选项、SOURCE的DIRECTORY/TARGET_DIRECTORY子选项、TEST的DIRECTORY子选项都必须紧跟对应作用域之后出现,源码按"状态机"逐 token 解析(DoingFileSetTarget、DoingSourceDirectory等),顺序或用法错误会报given invalid argument ...。

实战小结与推荐路径

get_property的核心价值在于:一个命令、统一语法、覆盖 CMake 全部属性作用域。实际项目中的选择建议:

  • 只读目标属性,且确认属性必定存在 → 可用get_target_property(未命中时得到-NOTFOUND,便于if(...)判空);
  • 需要区分"属性未设置"与"值为空"、或需要跨作用域/带目录覆盖读取 → 用通用get_property+SET/DEFINED;
  • 需要读取文档元信息 →get_property+BRIEF_DOCS/FULL_DOCS,配合 define_property 为自定义属性书写文档;
  • 需要批量或追加设置属性 → 配合 set_property 的APPEND/APPEND_STRING。

深入阅读建议:

  • 属性读写对偶命令:set_property、define_property;
  • 各作用域的完整属性清单:cmake-properties 手册;
  • 底层实现:cmGetPropertyCommand.cxx(作用域映射、参数解析、StoreResult存储逻辑);
  • 官方测试佐证:GetPropertyTest.cmake.in、define_property 测试、alias_targets/get_property.cmake、FileSetProperties 测试、add_custom_rule 测试。
  • 构建工具
  • 开发工具
  • CLI

【免费下载链接】CMake

Mirror of CMake upstream repository

项目地址:https://gitcode.com/gh_mirrors/cm/CMake
点击查看免费下载
上一篇:GPU模拟与高性能计算的终极指南:GPGPU-Sim完整教程
下一篇:终极指南:让Element UI表格横向滚动条始终可见的完美解决方案

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/3 8:17:27

agno Agent 输入输出实用指南:6 个机制控制它说什么、怎么说

agno Agent 输入输出实用指南&#xff1a;6 个机制控制它说什么、怎么说 【免费下载链接】agno Build, run, and manage agent platforms. 项目地址: https://gitcode.com/GitHub_Trending/ag/agno agno 是一个用 Python 构建、运行和管理 Agent 平台的框架。实际用起来…

作者头像 李华