mirror of
https://github.com/Kitware/CMake.git
synced 2026-02-25 00:59:19 -06:00
Merge topic 'doc-compile-features-wcdh'
1f4ec3f4a7Help: Do not recommend WCDH in cmake-compile-features(7)1cc63f2cd5Help: Fix typos in cmake-compile-features(7) Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !6037
This commit is contained in:
@@ -130,118 +130,21 @@ 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:
|
||||
requirement. This can be achieved by *not* specifying features with
|
||||
:command:`target_compile_features` and instead checking the compiler
|
||||
capabilities with preprocessor conditions in project code.
|
||||
|
||||
.. code-block:: c++
|
||||
In this use-case, the project may wish to establish a particular language
|
||||
standard if available from the compiler, and use preprocessor conditions
|
||||
to detect the features actually available. A language standard may be
|
||||
established by `Requiring Language Standards`_ using
|
||||
:command:`target_compile_features` with meta-features like ``cxx_std_11``,
|
||||
or by setting the :prop_tgt:`CXX_STANDARD` target property or
|
||||
:variable:`CMAKE_CXX_STANDARD` variable.
|
||||
|
||||
#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_FINAL {
|
||||
void Execute() Foo_OVERRIDE;
|
||||
};
|
||||
|
||||
In this case, ``Foo_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_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)
|
||||
|
||||
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.
|
||||
See also policy :policy:`CMP0120` and legacy documentation on
|
||||
:ref:`Example Usage <WCDH Example Usage>` of the deprecated
|
||||
:module:`WriteCompilerDetectionHeader` module.
|
||||
|
||||
Conditional Compilation Options
|
||||
===============================
|
||||
@@ -284,13 +187,12 @@ while a header at ``no_variadics/interface.h`` may contain:
|
||||
static int accumulate() { return I1 + I2 + I3 + I4; }
|
||||
};
|
||||
|
||||
It would be possible to write a abstraction ``interface.h`` header
|
||||
It may be possible to write an abstraction ``interface.h`` header
|
||||
containing something like:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#include "foo_compiler_detection.h"
|
||||
#if Foo_COMPILER_CXX_VARIADIC_TEMPLATES
|
||||
#ifdef HAVE_CXX_VARIADIC_TEMPLATES
|
||||
#include "with_variadics/interface.h"
|
||||
#else
|
||||
#include "no_variadics/interface.h"
|
||||
|
||||
@@ -245,6 +245,131 @@ library:
|
||||
PRIVATE
|
||||
CompatSupport_DEPRECATED=
|
||||
)
|
||||
|
||||
.. _`WCDH Example Usage`:
|
||||
|
||||
Example Usage
|
||||
=============
|
||||
|
||||
.. note::
|
||||
|
||||
This section was migrated from the :manual:`cmake-compile-features(7)`
|
||||
manual since it relies on the ``WriteCompilerDetectionHeader`` module
|
||||
which is removed by policy :policy:`CMP0120`.
|
||||
|
||||
Compile features may be preferred if available, without creating a hard
|
||||
requirement. For example, a library may provide 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_FINAL {
|
||||
void Execute() Foo_OVERRIDE;
|
||||
};
|
||||
|
||||
In this case, ``Foo_FINAL`` will expand to ``final`` if the
|
||||
compiler supports the keyword, or to empty otherwise.
|
||||
|
||||
In this use-case, the project code may wish to enable a particular language
|
||||
standard if available from the compiler. The :prop_tgt:`CXX_STANDARD`
|
||||
target property may be set to the desired language standard for a particular
|
||||
target, and the :variable:`CMAKE_CXX_STANDARD` variable 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_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)
|
||||
|
||||
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.
|
||||
#]=======================================================================]
|
||||
|
||||
# Guard against inclusion by absolute path.
|
||||
|
||||
Reference in New Issue
Block a user