Spec-Zone.ru › CMake 3.6

cmake-compile-features(7)

  • Введение
  • Требования к функциям компиляции
  • Дополнительные функции компиляции
  • Параметры условной компиляции
  • Поддерживаемые компиляторы

Введение

Исходный код проекта может зависеть от наличия или быть условным в зависимости от наличия определенных функций компилятора. Возникают три сценария использования: требования к функциям компиляции, дополнительные функции компиляции и параметры условной компиляции.

Хотя функции обычно указываются в стандартах языков программирования, CMake предоставляет основной пользовательский интерфейс, основанный на поштучной обработке функций, а не на стандарте языка, который ввел эту функцию.

Глобальные свойства CMAKE_C_KNOWN_FEATURES и CMAKE_CXX_KNOWN_FEATURES содержат все известные CMake функции, независимо от поддержки компилятора. Переменные CMAKE_C_COMPILE_FEATURES и CMAKE_CXX_COMPILE_FEATURES содержат все функции, известные CMake, известные компилятору, независимо от стандарта языка или флагов компиляции, необходимых для их использования.

Функции, известные CMake, в основном следуют той же соглашения об именах, что и макросы тестирования функций Clang. Есть некоторые исключения, такие как CMake использует cxx_final и cxx_override вместо единого cxx_override_control, используемого Clang.

Требования к функциям компиляции

Требования к функциям компиляции могут быть указаны с помощью команды 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) для получения дополнительной информации о транзитивном поведении свойств сборки и требованиях к использованию.

Поскольку свойство целевого объекта CXX_EXTENSIONS по умолчанию ON, CMake использует расширенные варианты диалектов языка по умолчанию, такие как -std=gnu++11 вместо -std=c++11. Это свойство целевого объекта можно установить в OFF для использования нерасширенной версии флага диалекта. Обратите внимание, что поскольку большинство компиляторов включают расширения по умолчанию, это может привести к ошибкам кросс-платформенного кода в пользовательском коде или заголовках сторонних зависимостей.

Дополнительные функции компиляции

Функции компиляции могут быть предпочтительны, если они доступны, без создания жесткого требования. Например, библиотека может предоставить альтернативные реализации в зависимости от наличия функции cxx_variadic_templates.

#if Foo_COMPILER_CXX_VARIADIC_TEMPLATES
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();
  }
};
#else
template<int I1, int I2 = 0, int I3 = 0, int I4 = 0>
struct Interface
{
  static int accumulate() { return I1 + I2 + I3 + I4; }
};
#endif

Такой интерфейс зависит от использования правильных предопределений препроцессора для функций компилятора. CMake может создать файл заголовка, содержащий такие определения, используя модуль WriteCompilerDetectionHeader. Модуль содержит функцию write_compiler_detection_header, которая принимает параметры для управления содержимым генерируемого файла заголовка:

write_compiler_detection_header(
  FILE "${CMAKE_CURRENT_BINARY_DIR}/foo_compiler_detection.h"
  PREFIX Foo
  COMPILERS GNU
  FEATURES
    cxx_variadic_templates
)

Такой файл заголовка может использоваться внутри исходного кода проекта, а также может быть установлен и использован в интерфейсе кода библиотеки.

Для каждой функции, указанной в FEATURES, в файле заголовка создается определение препроцессора, определенное как 1 или 0.

Кроме того, некоторые функции требуют дополнительных определений, таких как функции cxx_final и cxx_override. Вместо использования в коде #ifdef, ключевое слово final абстрагируется символом, который определен как final, эквивалент для конкретного компилятора, или пустой строкой. Таким образом, код C++ может быть написан для безусловного использования символа, а поддержка компилятора определяет, к чему он будет расширен:

struct Interface {
  virtual void Execute() = 0;
};

struct Concrete Foo_FINAL {
  void Execute() Foo_OVERRIDE;
};

В этом случае, Foo_FINAL будет расширено до final, если компилятор поддерживает ключевое слово, или до пустой строки в противном случае.

В этом случае код CMake должен включить конкретный стандарт языка, если он доступен от компилятора. Свойство целевого объекта CXX_STANDARD может быть установлено в желаемый стандарт языка для определенного целевого объекта, а CMAKE_CXX_STANDARD может быть установлено для влияния на все последующие целевые объекты:

write_compiler_detection_header(
  FILE "${CMAKE_CURRENT_BINARY_DIR}/foo_compiler_detection.h"
  PREFIX Foo
  COMPILERS GNU
  FEATURES
    cxx_final cxx_override
)

# Includes foo_compiler_detection.h and uses the Foo_FINAL symbol
# which will expand to 'final' if the compiler supports the requested
# CXX_STANDARD.
add_library(foo foo.cpp)
set_property(TARGET foo PROPERTY CXX_STANDARD 11)

# Includes foo_compiler_detection.h and uses the Foo_FINAL symbol
# which will expand to 'final' if the compiler supports the feature,
# even though CXX_STANDARD is not set explicitly.  The requirement of
# cxx_constexpr causes CMake to set CXX_STANDARD internally, which
# affects the compile flags.
add_library(foo_impl foo_impl.cpp)
target_compile_features(foo_impl PRIVATE cxx_constexpr)

Функция write_compiler_detection_header также создает код совместимости для других функций, которые имеют стандартные эквиваленты. Например, функция cxx_static_assert эмулируется с помощью шаблона и абстрагируется через функции-макросы <PREFIX>_STATIC_ASSERT и <PREFIX>_STATIC_ASSERT_MSG.

Параметры условной компиляции

Библиотеки могут предоставлять совершенно разные файлы заголовков в зависимости от запрошенных функций компилятора.

Например, заголовок в 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 содержащий что-то вроде:

#include "foo_compiler_detection.h"
#if Foo_COMPILER_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 знает о language standards и compile features, доступных от следующих compiler ids по состоянию на указанные версии:

  • AppleClang: Apple Clang для Xcode версий 4.4 — 6.2.
  • Clang: Компилятор Clang версий 2.9 — 3.4.
  • GNU: Компилятор GNU версий 4.4 — 5.0.
  • MSVC: Microsoft Visual Studio версий 2010 — 2015.
  • SunPro: Oracle SolarisStudio версии 12.4.
  • Intel: Компилятор Intel версий 12.1 — 16.0 на платформах UNIX.

© 2000–2019 Kitware, Inc. and Contributors
Licensed under the BSD 3-clause License.
https://cmake.org/cmake/help/v3.6/manual/cmake-compile-features.7.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API