CMake变量和属性似乎完成了非常相似的事情,我无法理解它们之间的区别。
它们各自都有自己的文档部分,但两者都可以影响构建系统,两者都“预先存在”,并且两者都可以基于其他CMake命令动态生成。看起来他们应该有不同的目的。它们是什么?
答案 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。