diff options
Diffstat (limited to 'Help/manual/cmake-compile-features.7.rst')
-rw-r--r-- | Help/manual/cmake-compile-features.7.rst | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/Help/manual/cmake-compile-features.7.rst b/Help/manual/cmake-compile-features.7.rst new file mode 100644 index 0000000..c014846 --- /dev/null +++ b/Help/manual/cmake-compile-features.7.rst @@ -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) |