cmake-compile-features(7)
Введение
Исходный код проекта может зависеть от или быть условным в зависимости от наличия определенных функций компилятора. Возникают три сценария: Требования к функциям компиляции, Дополнительные функции компиляции и Условные параметры компиляции.
Хотя функции обычно определяются в стандартах программирования, CMake предоставляет основной интерфейс пользователя, основанный на подробной обработке функций, а не на языке стандарта, который ввел эту функцию.
Глобальные свойства CMAKE_C_KNOWN_FEATURES, CMAKE_CUDA_KNOWN_FEATURES и CMAKE_CXX_KNOWN_FEATURES содержат все функции, известные CMake, независимо от поддержки компилятором этих функций. Переменные CMAKE_C_COMPILE_FEATURES, CMAKE_CUDA_COMPILE_FEATURES и CMAKE_CXX_COMPILE_FEATURES содержат все функции, известные CMake, как известные компилятору, независимо от языкового стандарта или флагов компиляции, необходимых для их использования.
Функции, известные CMake, в основном называются так же, как и макросы проверки функций Clang. Есть некоторые исключения, такие как CMake использующий cxx_final и cxx_override вместо единственного cxx_override_control используемого Clang.
Обратите внимание, что для языков OBJC или OBJCXX нет отдельных свойств или переменных функций компиляции. Они основаны соответственно на C или C++, поэтому вместо этого следует использовать свойства и переменные для соответствующего базового языка.
Требования к функциям компиляции
Требования к функциям компиляции могут быть указаны с помощью команды target_compile_features(). Например, если цель должна быть скомпилирована с поддержкой компилятором функции cxx_constexpr:
add_library(mylib requires_constexpr.cpp) target_compile_features(mylib PRIVATE cxx_constexpr)
При обработке требования к функции cxx_constexpr, cmake(1) будет проверять, способен ли используемый C++ компилятор на эту функцию, и добавит любые необходимые флаги, такие как -std=gnu++11, к строкам компиляции C++ файлов в целевой mylib. Будет выведено сообщение FATAL_ERROR, если компилятор не способен на эту функцию.
Точные флаги компиляции и языковой стандарт намеренно не являются частью интерфейса пользователя для этого случая. CMake вычислит соответствующие флаги компиляции, рассмотрев указанные функции для каждой цели.
Эти флаги компиляции добавляются даже если компилятор поддерживает конкретную функцию без флага. Например, GNU компилятор поддерживает вариативные шаблоны (с предупреждением), даже если -std=gnu++98 используется. CMake добавляет флаг -std=gnu++11 если cxx_variadic_templates указано как требование.
В приведенном выше примере mylib требует cxx_constexpr при собственном построении, но потребители mylib не обязаны использовать компилятор, поддерживающий cxx_constexpr. Если интерфейс mylib требует функцию cxx_constexpr (или любую другую известную функцию), это можно указать с помощью сигнатур PUBLIC или INTERFACE команды target_compile_features().
add_library(mylib requires_constexpr.cpp) # cxx_constexpr is a usage-requirement target_compile_features(mylib PUBLIC cxx_constexpr) # main.cpp will be compiled with -std=gnu++11 on GNU for cxx_constexpr. add_executable(myexe main.cpp) target_link_libraries(myexe mylib)
Требования к функциям вычисляются транзитивно, используя реализацию связи. См. cmake-buildsystem(7) для получения дополнительной информации о транзитивном поведении свойств сборки и требованиях к использованию.
Требование к языковым стандартам
В проектах, использующих большое количество общедоступных функций из конкретного языкового стандарта (например, C++ 11), можно указать метафункцию (например, cxx_std_11), которая требует использования режима компилятора, по крайней мере, осознающего этот стандарт, но может быть и более новым. Это проще, чем указывать все функции индивидуально, но не гарантирует существование какой-либо конкретной функции. Диагностика использования неподдерживаемых функций будет отложена до времени компиляции.
Например, если C++ 11 функции широко используются в заголовочных файлах проекта, тогда клиенты должны использовать режим компилятора, не ниже C++ 11. Это можно запросить с помощью кода:
target_compile_features(mylib PUBLIC cxx_std_11)
В этом примере CMake обеспечит вызов компилятора в режиме не ниже C++ 11 (или C++ 14, C++ 17, ...), добавляя флаги, такие как -std=gnu++11 при необходимости. Это относится к исходным файлам внутри mylib, а также к любым зависимостям (которые могут включать заголовки из mylib).
Примечание
Если уровень стандартного режима компилятора по умолчанию не ниже требуемой функции, CMake может опустить флаг -std=. Флаг все еще может быть добавлен, если режим расширений компилятора по умолчанию не соответствует свойству цели <LANG>_EXTENSIONS, или если свойство цели <LANG>_STANDARD установлено.
Доступность расширений компилятора
Свойство цели <LANG>_EXTENSIONS по умолчанию принимает значение по умолчанию для компилятора (см. CMAKE_<LANG>_EXTENSIONS_DEFAULT). Обратите внимание, что поскольку большинство компиляторов включают расширения по умолчанию, это может привести к ошибкам переносимости в пользовательском коде или в заголовках зависимостей третьих сторон.
Свойство <LANG>_EXTENSIONS по умолчанию было ON. См. CMP0128.
Дополнительные функции компиляции
Функции компиляции могут быть предпочтительны при их наличии, без создания жесткого требования. Это можно сделать, не указывая функции с помощью target_compile_features(), а вместо этого, проверяя возможности компилятора с помощью препроцессорных условий в проекте.
В этом случае проект может установить конкретный языковой стандарт, если он доступен от компилятора, и использовать условия препроцессора для определения фактически доступных функций. Языковой стандарт может быть установлен путем Требования к языковым стандартам с помощью target_compile_features() с мета-функциями, такими как cxx_std_11, или путем установки свойства цели CXX_STANDARD или переменной CMAKE_CXX_STANDARD.
См. также политику CMP0120 и документацию по наследию по Примеры использования устаревшего модуля WriteCompilerDetectionHeader.
Условные параметры компиляции
Библиотеки могут предоставлять совершенно разные заголовочные файлы в зависимости от запрашиваемых функций компилятора.
Например, заголовок по адресу with_variadics/interface.h может содержать:
template<int I, int... Is>
struct Interface;
template<int I>
struct Interface<I>
{
static int accumulate()
{
return I;
}
};
template<int I, int... Is>
struct Interface
{
static int accumulate()
{
return I + Interface<Is...>::accumulate();
}
};
в то время как заголовок по адресу no_variadics/interface.h может содержать:
template<int I1, int I2 = 0, int I3 = 0, int I4 = 0>
struct Interface
{
static int accumulate() { return I1 + I2 + I3 + I4; }
};
Возможно создание абстрактного заголовка interface.h с чем-то подобным:
#ifdef HAVE_CXX_VARIADIC_TEMPLATES #include "with_variadics/interface.h" #else #include "no_variadics/interface.h" #endif
Однако это может быть не поддерживаемо, если нужно абстрагировать множество файлов. Необходимо использовать альтернативные каталоги включения в зависимости от возможностей компилятора.
END_OF_DOCUMENT_MARKERCMake предоставляет COMPILE_FEATURES generator expression для реализации таких условий. Это можно использовать с командами свойств сборки, такими как target_include_directories() и target_link_libraries() для установки соответствующих buildsystem свойств:
add_library(foo INTERFACE)
set(with_variadics ${CMAKE_CURRENT_SOURCE_DIR}/with_variadics)
set(no_variadics ${CMAKE_CURRENT_SOURCE_DIR}/no_variadics)
target_include_directories(foo
INTERFACE
"$<$<COMPILE_FEATURES:cxx_variadic_templates>:${with_variadics}>"
"$<$<NOT:$<COMPILE_FEATURES:cxx_variadic_templates>>:${no_variadics}>"
)
Код, потребляющий эти данные, затем просто связывается с целевым объектом foo как обычно и использует каталог включаемых файлов, соответствующий данной функции.
add_executable(consumer_with consumer_with.cpp) target_link_libraries(consumer_with foo) set_property(TARGET consumer_with CXX_STANDARD 11) add_executable(consumer_no consumer_no.cpp) target_link_libraries(consumer_no foo)
Поддерживаемые компиляторы
CMake в настоящее время поддерживает C++ standards и compile features, доступные из следующих compiler ids, начиная с указанных версий:
-
AppleClang: Apple Clang для версий Xcode 4.4+. -
Clang: Версии компилятора Clang 2.9+. -
GNU: Версии компилятора GNU 4.4+. -
MSVC: Версии Microsoft Visual Studio 2010+. -
SunPro: Версии Oracle SolarisStudio 12.4+. -
Intel: Версии компилятора Intel 12.1+.
CMake в настоящее время поддерживает C standards и compile features, доступные из следующих compiler ids, начиная с указанных версий:
- все компиляторы и версии, перечисленные выше, для C++.
-
GNU: Версии компилятора GNU 3.4+.
CMake в настоящее время поддерживает C++ standards и их связанные мета-функции (например, cxx_std_11) доступные из следующих compiler ids, начиная с указанных версий:
-
Cray: Cray Compiler Environment версии 8.1+. -
Fujitsu: Fujitsu HPC compiler 4.0+. -
PGI: PGI версии 12.10+. -
NVHPC: NVIDIA HPC compilers версии 11.0+. -
TI: Компилятор Texas Instruments. -
XL: IBM XL версии 10.1+.
CMake в настоящее время поддерживает C standards и их связанные мета-функции (например, c_std_99) доступные из следующих compiler ids, начиная с указанных версий:
- все компиляторы и версии, перечисленные выше, только с мета-функциями для C++.
CMake в настоящее время поддерживает CUDA standards и их связанные мета-функции (например, cuda_std_11) доступные из следующих compiler ids, начиная с указанных версий:
-
Clang: Компилятор Clang 5.0+. -
NVIDIA: Компилятор NVIDIA nvcc 7.5+.
© 2000–2022 Kitware, Inc. and Contributors
Licensed under the BSD 3-clause License.
https://cmake.org/cmake/help/v3.24/manual/cmake-compile-features.7.html