|
|
@@ -0,0 +1,297 @@
|
|
|
+.. cmake-manual-description: CMake Compile Features Reference
|
|
|
+
|
|
|
+cmake-compile-features(7)
|
|
|
+*************************
|
|
|
+
|
|
|
+.. only:: html or latex
|
|
|
+
|
|
|
+ .. contents::
|
|
|
+
|
|
|
+Introduction
|
|
|
+============
|
|
|
+
|
|
|
+Project source code may depend on, or be conditional on, the availability
|
|
|
+of certain features of the compiler. There are three use-cases which arise:
|
|
|
+`Compile Feature Requirements`_, `Optional Compile Features`_
|
|
|
+and `Conditional Compilation Options`_.
|
|
|
+
|
|
|
+While features are typically specified in programming language standards,
|
|
|
+CMake provides a primary user interface based on granular handling of
|
|
|
+the features, not the language standard that introduced the feature.
|
|
|
+
|
|
|
+The :prop_gbl:`CMAKE_C_KNOWN_FEATURES` and
|
|
|
+:prop_gbl:`CMAKE_CXX_KNOWN_FEATURES` global properties contain all the
|
|
|
+features known to CMake, regardless of compiler support for the feature.
|
|
|
+The :variable:`CMAKE_C_COMPILE_FEATURES` and
|
|
|
+:variable:`CMAKE_CXX_COMPILE_FEATURES` variables contain all features
|
|
|
+CMake knows are known to the compiler, regardless of language standard
|
|
|
+or compile flags needed to use them.
|
|
|
+
|
|
|
+Features known to CMake are named mostly following the same convention
|
|
|
+as the Clang feature test macros. The are some execptions, such as
|
|
|
+CMake using ``cxx_final`` and ``cxx_override`` instead of the single
|
|
|
+``cxx_override_control`` used by Clang.
|
|
|
+
|
|
|
+Compile Feature Requirements
|
|
|
+============================
|
|
|
+
|
|
|
+Compile feature requirements may be specified with the
|
|
|
+:command:`target_compile_features` command. For example, if a target must
|
|
|
+be compiled with compiler support for the
|
|
|
+:prop_gbl:`cxx_constexpr <CMAKE_CXX_KNOWN_FEATURES>` feature:
|
|
|
+
|
|
|
+.. code-block:: cmake
|
|
|
+
|
|
|
+ add_library(mylib requires_constexpr.cpp)
|
|
|
+ target_compile_features(mylib PRIVATE cxx_constexpr)
|
|
|
+
|
|
|
+In processing the requirement for the ``cxx_constexpr`` feature,
|
|
|
+:manual:`cmake(1)` will ensure that the in-use C++ compiler is capable
|
|
|
+of the feature, and will add any necessary flags such as ``-std=c++11``
|
|
|
+to the compile lines of C++ files in the ``mylib`` target. A
|
|
|
+``FATAL_ERROR`` is issued if the compiler is not capable of the
|
|
|
+feature.
|
|
|
+
|
|
|
+The exact compile flags and language standard are deliberately not part
|
|
|
+of the user interface for this use-case. CMake will compute the
|
|
|
+appropriate compile flags to use by considering the features specified
|
|
|
+for each target.
|
|
|
+
|
|
|
+Such compile flags are added even if the compiler supports the
|
|
|
+particular feature without the flag. For example, the GNU compiler
|
|
|
+supports variadic templates (with a warning) even if ``-std=c++98`` is
|
|
|
+used. CMake adds the ``-std=c++11`` flag if ``cxx_variadic_templates``
|
|
|
+is specified as a requirement.
|
|
|
+
|
|
|
+In the above example, ``mylib`` requires ``cxx_constexpr`` when it
|
|
|
+is built itself, but consumers of ``mylib`` are not required to use a
|
|
|
+compiler which supports ``cxx_constexpr``. If the interface of
|
|
|
+``mylib`` does require the ``cxx_constexpr`` feature (or any other
|
|
|
+known feature), that may be specified with the ``PUBLIC`` or
|
|
|
+``INTERFACE`` signatures of :command:`target_compile_features`:
|
|
|
+
|
|
|
+.. code-block:: cmake
|
|
|
+
|
|
|
+ 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=c++11 on GNU for cxx_constexpr.
|
|
|
+ add_executable(myexe main.cpp)
|
|
|
+ target_link_libraries(myexe mylib)
|
|
|
+
|
|
|
+Feature requirements are evaluated transitively by consuming the link
|
|
|
+implementation. See :manual:`cmake-buildsystem(7)` for more on
|
|
|
+transitive behavior of build properties and usage requirements.
|
|
|
+
|
|
|
+Note that new use of compile feature requirements may expose
|
|
|
+cross-platform bugs in user code. For example, the GNU compiler uses the
|
|
|
+``gnu++98`` language by default as of GCC version 4.8. User code may
|
|
|
+be relying on that by expecting the ``typeof`` GNU extension to work.
|
|
|
+However, if the :command:`target_compile_features` command is used to
|
|
|
+specify the requirement for ``cxx_constexpr``, a ``-std=c++11`` flag may
|
|
|
+be added, and the ``typeof`` extension would no longer be available. The
|
|
|
+solution is to specify that compiler extensions are relied upon by setting
|
|
|
+the :prop_tgt:`CXX_EXTENSIONS` target property to ``ON`` when starting to
|
|
|
+use the :command:`target_compile_features` command.
|
|
|
+
|
|
|
+Optional Compile Features
|
|
|
+=========================
|
|
|
+
|
|
|
+Compile features may be preferred if available, without creating a hard
|
|
|
+requirement. For example, a library may provides alternative
|
|
|
+implementations depending on whether the ``cxx_variadic_templates``
|
|
|
+feature is available:
|
|
|
+
|
|
|
+.. code-block:: c++
|
|
|
+
|
|
|
+ #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
|
|
|
+
|
|
|
+Such an interface depends on using the correct preprocessor defines for the
|
|
|
+compiler features. CMake can generate a header file containing such
|
|
|
+defines using the :module:`WriteCompilerDetectionHeader` module. The
|
|
|
+module contains the ``write_compiler_detection_header`` function which
|
|
|
+accepts parameters to control the content of the generated header file:
|
|
|
+
|
|
|
+.. code-block:: cmake
|
|
|
+
|
|
|
+ write_compiler_detection_header(
|
|
|
+ FILE "${CMAKE_CURRENT_BINARY_DIR}/foo_compiler_detection.h"
|
|
|
+ PREFIX Foo
|
|
|
+ COMPILERS GNU
|
|
|
+ FEATURES
|
|
|
+ cxx_variadic_templates
|
|
|
+ )
|
|
|
+
|
|
|
+Such a header file may be used internally in the source code of a project,
|
|
|
+and it may be installed and used in the interface of library code.
|
|
|
+
|
|
|
+For each feature listed in ``FEATURES``, a preprocessor definition
|
|
|
+is created in the header file, and defined to either ``1`` or ``0``.
|
|
|
+
|
|
|
+Additionally, some features call for additional defines, such as the
|
|
|
+``cxx_final`` and ``cxx_override`` features. Rather than being used in
|
|
|
+``#ifdef`` code, the ``final`` keyword is abstracted by a symbol
|
|
|
+which is defined to either ``final``, a compiler-specific equivalent, or
|
|
|
+to empty. That way, C++ code can be written to unconditionally use the
|
|
|
+symbol, and compiler support determines what it is expanded to:
|
|
|
+
|
|
|
+.. code-block:: c++
|
|
|
+
|
|
|
+ struct Interface {
|
|
|
+ virtual void Execute() = 0;
|
|
|
+ };
|
|
|
+
|
|
|
+ struct Concrete Foo_CXX_FINAL {
|
|
|
+ void Execute() Foo_CXX_OVERRIDE;
|
|
|
+ };
|
|
|
+
|
|
|
+In this case, ``Foo_CXX_FINAL`` will expand to ``final`` if the
|
|
|
+compiler supports the keyword, or to empty otherwise.
|
|
|
+
|
|
|
+In this use-case, the CMake code will wish to enable a particular language
|
|
|
+standard if available from the compiler. The :prop_tgt:`CXX_STANDARD`
|
|
|
+target property variable may be set to the desired language standard
|
|
|
+for a particular target, and the :variable:`CMAKE_CXX_STANDARD` may be
|
|
|
+set to influence all following targets:
|
|
|
+
|
|
|
+.. code-block:: cmake
|
|
|
+
|
|
|
+ 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_DECL_CXX_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_DECL_CXX_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)
|
|
|
+
|
|
|
+The ``write_compiler_detection_header`` function also creates compatibility
|
|
|
+code for other features which have standard equivalents. For example, the
|
|
|
+``cxx_static_assert`` feature is emulated with a template and abstracted
|
|
|
+via the ``<PREFIX>_STATIC_ASSERT`` and ``<PREFIX>_STATIC_ASSERT_MSG``
|
|
|
+function-macros.
|
|
|
+
|
|
|
+Conditional Compilation Options
|
|
|
+===============================
|
|
|
+
|
|
|
+Libraries may provide entirely different header files depending on
|
|
|
+requested compiler features.
|
|
|
+
|
|
|
+For example, a header at ``with_variadics/interface.h`` may contain:
|
|
|
+
|
|
|
+.. code-block:: c++
|
|
|
+
|
|
|
+ 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();
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+while a header at ``no_variadics/interface.h`` may contain:
|
|
|
+
|
|
|
+.. code-block:: c++
|
|
|
+
|
|
|
+ template<int I1, int I2 = 0, int I3 = 0, int I4 = 0>
|
|
|
+ struct Interface
|
|
|
+ {
|
|
|
+ static int accumulate() { return I1 + I2 + I3 + I4; }
|
|
|
+ };
|
|
|
+
|
|
|
+It would be possible to write a abstraction ``interface.h`` header
|
|
|
+containing something like:
|
|
|
+
|
|
|
+.. code-block:: c++
|
|
|
+
|
|
|
+ #include "foo_compiler_detection.h"
|
|
|
+ #if Foo_COMPILER_CXX_VARIADIC_TEMPLATES
|
|
|
+ #include "with_variadics/interface.h"
|
|
|
+ #else
|
|
|
+ #include "no_variadics/interface.h"
|
|
|
+ #endif
|
|
|
+
|
|
|
+However this could be unmaintainable if there are many files to
|
|
|
+abstract. What is needed is to use alternative include directories
|
|
|
+depending on the compiler capabilities.
|
|
|
+
|
|
|
+CMake provides a ``COMPILE_FEATURES``
|
|
|
+:manual:`generator expression <cmake-generator-expressions(7)>` to implement
|
|
|
+such conditions. This may be used with the build-property commands such as
|
|
|
+:command:`target_include_directories` and :command:`target_link_libraries`
|
|
|
+to set the appropriate :manual:`buildsystem <cmake-buildsystem(7)>`
|
|
|
+properties:
|
|
|
+
|
|
|
+.. code-block:: cmake
|
|
|
+
|
|
|
+ add_library(foo INTERFACE)
|
|
|
+ target_link_libraries(foo
|
|
|
+ INTERFACE
|
|
|
+ "$<$<COMPILE_FEATURES:cxx_variadic_templates>:${CMAKE_CURRENT_SOURCE_DIR}/with_variadics>"
|
|
|
+ "$<$<NOT:$<COMPILE_FEATURES:cxx_variadic_templates>>:${CMAKE_CURRENT_SOURCE_DIR}/no_variadics>")
|
|
|
+
|
|
|
+Consuming code then simply links to the ``foo`` target as usual and uses
|
|
|
+the feature-appropriate include directory
|
|
|
+
|
|
|
+.. code-block:: cmake
|
|
|
+
|
|
|
+ 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)
|