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

时间:2018-04-21 17:06:18

标签: cmake

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

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

3 个答案:

答案 0 :(得分:4)

考虑它的一个非常简单和简单的方法是属性是作用于目标的变量。例如:

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
)

如果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);

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

// 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};

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

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"
)

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

答案 1 :(得分:0)

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

但是,除了目标属性外,还有其他各种类型(例如,源,安装,目录,全局等)将这些变量限定范围。

属性的一个明显区别是用于设置/获取属性的语法与具有相同名称的变量的语法不同。这也适用于全局属性。可能同时存在一个('global')变量和一个具有相同名称的(global)属性(但是这种用法的作用并不明显)。

因此,属性对于将它们“作用域”到诸如目标之类的东西而言非常有用。全局属性也作用于单个“全局对象”。 (按照斯蒂芬的类比,它们可能是单例的成员变量)。使用与变量不同的语法来设置/获取属性。具有给定范围的属性可以与其他任何范围(包括全局范围)以及同名常规变量中的同名其他属性同时存在。

here给出了组合全局属性和变量的一种可能的用途:

  

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

答案 2 :(得分:0)

首先,编程语言如何处理变量?编程语言中的变量可以分为两组。 基于堆栈或基于对象。

  • 基于堆栈的变量是存储在每个函数保留的内存(在堆栈中找到的内存)中的变量。调用函数时,堆栈上的保留区域一直在增长和缩小。输入新函数后,该函数将为堆栈顶部的变量保留内存。离开函数会破坏该区域并擦除变量。
  • 基于对象的变量存储在为对象保留的存储区中。当销毁对象时,将销毁基于对象的变量。它们通常被某种类型的操作/命令破坏。这类对象变量有时称为成员变量。

脚本语言也是如此,但是它们具有模拟堆栈的技巧。用脚本语言输入函数时,堆栈通常也是一个对象。该对象知道它的调用者堆栈。 它的工作原理就像一棵树,其中可变的分支不断增长和收缩,每个分支都知道其父级,并且叶子在这里是可变的。 运行脚本程序的启动时间不能太长,因此在分析代码以对其进行优化时只有有限的时间。脚本语言中存在的堆栈树是一种折衷方案,与计算机可以处理的将变量存储在堆栈中的语言相比,它可以更轻松地解析和分析它们。

那么变量和属性在CMake中如何工作。我没有检查代码,但我可以猜到。变量是基于堆栈的,属性是基于对象的。使用message打印变量值需要基于堆栈的变量,message命令可以找到存储在堆栈中的变量。它找不到属性,因为它们是CMake中一个对象的成员。为了从属性中获取值,您还需要对象,这就是为什么您需要另一个命令来获取它的原因,例如get_property。

Here is a CMake tutorial