Переменные и свойства 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), ему нужно что-то добавить в путь включения (INTERFACE_INCLUDE_DIRECTORIES), и есть некоторые исходные файлы, о которых он заботится (мои заголовки, INTERFACE_SOURCES).
Ах, я думаю, я могу понять разницу, поскольку свойства могут быть ограничены, тогда как переменные всегда глобальны. За исключением документации по свойствам, здесь свойства cmake.org/cmake/help/v3.11/manual/cmake-properties.7.html также могут быть глобальными, поэтому в этом случае меня все еще сбивает с толку, и различие кажется произвольным.
@ user1489829 - Признаюсь, я не знал о глобальных свойствах, поэтому мне пришлось бы это выяснить. Мой ответ касается свойств целевых объектов, но сравнение можно расширить для любого неглобального свойства.
Как обозначено user1489829, есть также свойства Global Scope, что делает этот ответ неверным. Так что все же хотелось бы получить правильный и более исчерпывающий ответ. По состоянию на май 2018 года поиск в Google не дал ничего полезного.
Я думаю, что ответ Стивена Ньюэлла отражает основную мотивацию для свойств (и аналогия С ++ переменных-членов и переменных, не являющихся членами, очень полезна).
Однако в дополнение к целевые свойства, которые привязаны к целям, существуют различные другие типы, которые вместо этого могут быть ограничены, например, источник, установка, каталог, глобальный и т. д.
Возможно, чтобы переменная ('Глобальный') и (глобальное) свойство с тем же именем существовали одновременно (но польза от этого не очевидна).
Таким образом, свойства в первую очередь полезны тем, что они «привязаны» к чему-то вроде цели. Глобальные свойства также ограничены одним «глобальным объектом». (По аналогии со Стивеном они могут быть переменными-членами синглтона). Свойства устанавливаются / получают с другим синтаксисом переменных. И свойство с заданной областью действия может одновременно существовать с другими с тем же именем в любой другой области (включая глобальную), а также как обычная переменная с тем же именем.
здесь дает одну возможную пользу от объединения глобальных свойств и переменных:
A global property can be a useful uncached global variable. Many target properties are initialised from a matching variable with CMAKE_ at the front. So setting CMAKE_CXX_STANDARD, for example, will mean that all new targets created will have CXX_STANDARD set to that when they are created
Во-первых, как языки программирования обрабатывают переменные? Переменные в языках программирования можно разделить на две группы. На основе стека или объекта.
Языки сценариев тоже работают так же, но в них есть хитрости для имитации стека. Когда функция вводится на языке сценариев, стек обычно также является одним объектом. Этот объект знает о своем стеке вызывающего абонента. Он работает как дерево, где переменные ветви растут и сжимаются, каждая ветвь знает о своем родителе и имеет листья, которые здесь являются переменными. Время запуска для запуска программ-скриптов не может быть слишком долгим, поэтому время на анализ кода для его оптимизации ограничено. Это дерево стека, которое существует в языках сценариев, является компромиссом и упрощает их синтаксический анализ и анализ по сравнению с языком, который хранит переменные в стеке, поскольку процессор компьютера может с этим справиться.
Итак, как переменные и свойства работают в CMake. Код не проверял, но догадываюсь. Переменные основаны на стеке, свойства основаны на объектах. Для печати значения переменной с сообщением требуется переменная на основе стека, команда сообщения может найти переменные, хранящиеся в стеке. Он не может найти свойства, потому что они являются членами одного объекта в CMake. Чтобы получить значение из свойства, вам также понадобится объект, поэтому вам нужна другая команда, например get_property.
«Я не проверял код, но догадываюсь».
В свойстве вы можете создать имя из составного токена, такого как
<name>:<os_name>:<config_name>:<arch_name>и т. д., И проанализировать его как отдельную переменную, используя регулярное выражение или что угодно. В имени переменной вы не можете использовать этот метод, потому что имя переменной не должно содержать недопустимых символов, таких как:. Таким образом, свойства вместе друг с другом могут использоваться для каких-то значений структурных переменных.