CMake 变量和属性似乎都能实现非常类似的功能,让我无法理解它们之间的不同。
虽然它们各自都有自己的文档部分,但两者都可以影响构建系统,都是“预存在”的,都可以根据其他 CMake 命令动态生成。它们似乎应该有单独的目的。它们是什么?
CMake 变量和属性似乎都能实现非常类似的功能,让我无法理解它们之间的不同。
虽然它们各自都有自己的文档部分,但两者都可以影响构建系统,都是“预存在”的,都可以根据其他 CMake 命令动态生成。它们似乎应该有单独的目的。它们是什么?
一个非常简短且简单的方法来思考它,就是属性是针对目标作用域的变量。例如:
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(INTERFACE_COMPILE_FEATURES
),它需要将一些东西添加到 include 路径中(INTERFACE_INCLUDE_DIRECTORIES
),并且有一些源文件是必要的(我的头文件,INTERFACE_SOURCES
)。
我对其他答案并不完全满意,所以必须去找到自己的答案。经过一些阅读和咨询,我相信 CMake 为变量和属性指定的角色确实是不同的,并且实际上更或多少是直接的。
变量是任意命名的内存单元,您可以在计算过程中使用它们并传递值。也可以在命令行中分配它们并公开为GUI选项,以便从脚本外接受输入。
属性是预定义的槽位,共同描述了环境、状态和正在配置的项目的所有方面。请记住,运行 CMake 的目的是让所选的生成器输出一组 makefile (或IDE项目文件)。反过来,配置阶段的目的是评估和记录生成器制定决策时可能想要知道的所有事实。
因此,通常情况下,值会通过 CMake 流动如下:
命令行/选项 > 变量 > 某些处理 > 属性 > 生成器 > makefile
例如,可以通过 set_property() 设置 CXX_STANDARD 属性,但如果给定了一个值,则还将从 CMAKE_CXX_STANDARD 变量 初始化。
在“现代” CMake 中,我们被鼓励以目标及其属性为中心思考,而不是将值设置为一个无组织的变量集合,但似乎最初并没有属性,因此某些方面仍然可以使用变量进行配置。例如,可以将 CMAKE_CXX_FLAGS 变量 设置为“-std=c++11”,然后将直接影响生成。现代方法是设置 CXX_STANDARD 属性。
首先,编程语言如何处理变量?编程语言中的变量可以分为两组。
脚本语言也是这样工作的,但它们有模拟堆栈的技巧。当一个函数在脚本语言中被输入时,堆栈通常也是一个对象。该对象知道它的调用者堆栈。 它的工作方式类似于一棵树,变量分支会增长和缩小,每个分支都知道它的父级,并且具有变量叶子。 运行脚本程序的启动时间不能太长,因此在分析代码以进行优化时有限的时间。脚本语言中存在的这个堆栈树是一种权衡,使它们比将变量存储在堆栈上的语言更简单解析和分析,因为计算机处理器可以处理它。
那么在CMake中变量和属性如何工作呢?我还没有检查过代码,但我可以猜测。变量是基于堆栈的,属性是基于对象的。使用message打印变量值需要一个基于堆栈的变量,message命令可以找到存储在堆栈上的变量。它无法找到属性,因为它们是CMake中一个对象的成员。要从属性中获取值,您还需要该对象,这就是为什么需要另一个命令来获取它,例如get_property。
<name>:<os_name>:<config_name>:<arch_name>
等,并使用正则表达式或其他任何方法将其解析为独立变量。在变量名称中,您不能使用此技术,因为变量名称不得包含无效字符,如:
。因此,属性可以与彼此结合使用,以形成某种结构变量值。 - Andry