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. Выдастся сообщение об ошибке, если компилятор не способен к данной возможности.
Точные флаги компиляции и стандарт языка преднамеренно не являются частью пользовательского интерфейса для этого случая. 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
Однако это может быть неудобно, если нужно абстрагировать много файлов. Необходимо использовать альтернативные каталоги включения в зависимости от возможностей компилятора.
CMake предоставляет 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 компилятор 4.0+. -
PGI: PGI версии 12.10+. -
NVHPC: NVIDIA HPC компиляторы версии 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.23/manual/cmake-compile-features.7.html