CMake变量和属性之间有什么区别?

use*_*829 6 cmake

CMake变量和属性似乎完成了非常相似的事情,而我一直无法理解它们之间的区别。

它们每个都有自己的文档部分,但是两者都可以影响构建系统,两者都是“预先存在的”,并且都可以基于其他CMake命令动态生成。似乎他们应该有不同的目的。这些是什么?

Ste*_*ell 6

一种简短而又简单的思考方式是,属性是作用于目标的变量。例如:

add_executable(foo foo.cpp)
set_target_properties(foo PROPERTIES
    CXX_STANDARD 14
    CXX_EXTENSIONS OFF
)
# Build foo with c++11 for some reason
add_executable(foo11 foo.cpp)
set_target_properties(foo11 PROPERTIES
    CXX_STANDARD 11
    CXX_EXTENSIONS OFF
)
Run Code Online (Sandbox Code Playgroud)

如果CMakeLists.txt是用C ++编写的,则可能看起来像这样:

const char * src_files[] = { "foo.cpp" };
executable foo{src_files};
foo.setCxxStandard(14);
foo.setCxxExtensions(false);

executable foo11{src_files};
foo.setCxxStandard(11);
foo.setCxxExtensions(false);
Run Code Online (Sandbox Code Playgroud)

如果我们将变量用于这些事情,它将看起来像这样:

// globals
int CMAKE_CXX_STANDARD = 14;
bool CMAKE_CXX_EXTENSIONS = false;

// later, in a function
const char * src_files[] = { "foo.cpp" };
executable foo{src_files}; // foo copies global settings

CMAKE_CXX_STANDARD = 11;
executable foo11{src_files};
Run Code Online (Sandbox Code Playgroud)

因为属性是目标的一部分,而不是全局变量,所以这也意味着可以导出它们。从我的项目之一中消毒:

set_target_properties(Foo::bar PROPERTIES
    INTERFACE_COMPILE_FEATURES "cxx_std_14"
    INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include/"
    INTERFACE_SOURCES "${_IMPORT_PREFIX}/include/foo/bar.hpp"
)
Run Code Online (Sandbox Code Playgroud)

这意味着如果您导入Foo::bar(可能通过find_package(Foo)),您的项目已经知道要链接的东西Foo::bar需要使用C ++ 14(INTERFACE_COMPILE_FEATURES),它需要在include路径(INTERFACE_INCLUDE_DIRECTORIES)中添加一些内容,并且需要一些源文件关于(我的标题INTERFACE_SOURCES)。

  • 啊,我想我可以理解其中的区别,因为属性可能有范围,而变量始终是全局的。除了根据这里的属性文档 https://cmake.org/cmake/help/v3.11/manual/cmake-properties.7.html 属性也可能是全局的,所以在这种情况下,它仍然让我和区分似乎是任意的。 (4认同)
  • 正如 user1489829 所指出的,还有 Global Scope 的属性,这使得这个答案不正确。所以,我还是想得到一个正确的、更全面的答案。截至 2018 年 5 月,谷歌搜索这个问题没有提供任何有用的信息。 (2认同)

Dec*_*lan 6

我认为 Stephen Newell 的答案抓住了属性的主要动机(成员变量与非成员变量的 C++ 类比非常有帮助)。

然而,除了目标属性(其作用域为目标)之外,还有各种其他类型的属性,其作用域可以为例如源、安装、目录、全局等。

可以同时存在同名的 ( 'global' ) 变量和(全局)属性(但其用处并不明显)。

总之,属性主要用于将其“范围”限定为目标之类的东西。全局属性的范围也仅限于单个“全局对象”。(在斯蒂芬的类比中,它们可能是单例的成员变量)。属性的设置/获取与变量的语法不同。具有给定范围的属性可以与任何其他范围(包括全局)中的同名属性以及同名常规变量同时存在。

这里给出了组合全局属性和变量的一种可能的用处 :

全局属性可以是有用的未缓存全局变量。许多目标属性是从前面带有 CMAKE_ 的匹配变量初始化的。因此,例如,设置 CMAKE_CXX_STANDARD 意味着创建的所有新目标都将 CXX_STANDARD 设置为创建时的值


Анд*_*шев 4

我对其他答案并不完全满意,所以我不得不去寻找我自己的答案。经过一些阅读和咨询,我相信 CMake 对于变量和属性的作用确实不同,而且实际上或多或少是简单的。

变量是您在计算期间使用并传递值的任意命名的存储单元。它们还可以在命令行中分配并作为 GUI 选项公开,以接受来自脚本外部的输入。

属性是预定义的槽,它们一起描述环境、状态和正在配置的项目的所有方面。请记住,运行 CMake 的目的是让所选生成器输出一组 makefile(或 IDE 项目文件)。反过来,配置阶段的重点是评估并记下生成器在做出决策时可能想要知道的所有事实。

所以一般来说,值会像这样通过 cmake 流动:

命令行/选项 > 变量 > 某些处理 > 属性 > 生成器 > makefile

例如,CXX_STANDARD prop可以通过 set_property() 设置,但如果给定了值,也将从CMAKE_CXX_STANDARD var初始化。

在“现代”CMake 中,我们被鼓励考虑目标及其拥有的属性,而不是将值设置为一堆杂乱无章的变量,但属性最初似乎并不存在,因此某些方面仍然可以使用变量进行配置。例如,CMAKE_CXX_FLAGS var 可以设置为“-std=c++11”,然后将直接影响生成。现代方法是设置 CXX_STANDARD 属性。