Commit e106a6ea authored by Brad King's avatar Brad King Committed by Kitware Robot

Merge topic 'compile-features-for-language-standards'

9a8d758c Help: Document language standard meta-features
df252db1 Features: Test cycle diagnostic with language standard meta-feature
6d5fb0e0 Features: Test feature propagation with language standard meta-feature
a34b98a8 WCDH: Ignore language standard meta-features
b0996a3f Features: Add meta-features requesting awareness of a particular standard
8b6cc251 Features: Centralize per-compiler recording macros
2d23f7b2 Features: Do not record features on MSVC < 2010
parents 90e09fb9 9a8d758c
......@@ -84,6 +84,33 @@ 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.
Requiring Language Standards
----------------------------
In projects that use a large number of commonly available features from
a particular language standard (e.g. C++ 11) one may specify a
meta-feature (e.g. ``cxx_std_11``) that requires use of a compiler mode
aware of that standard. This is simpler than specifying all the
features individually, but does not guarantee the existence of any
particular feature. Diagnosis of use of unsupported features will be
delayed until compile time.
For example, if C++ 11 features are used extensively in a project's
header files, then clients must use a compiler mode aware of C++ 11
or above. This can be requested with the code:
.. code-block:: cmake
target_compile_features(mylib PUBLIC cxx_std_11)
In this example, CMake will ensure the compiler is invoked in a mode
that is aware of C++ 11 (or above), adding flags such as
``-std=gnu++11`` if necessary. This applies to sources within ``mylib``
as well as any dependents (that may include headers from ``mylib``).
Availability of Compiler Extensions
-----------------------------------
Because the :prop_tgt:`CXX_EXTENSIONS` target property is ``ON`` by default,
CMake uses extended variants of language dialects by default, such as
``-std=gnu++11`` instead of ``-std=c++11``. That target property may be
......
......@@ -14,6 +14,15 @@ compile features and a list of supported compilers.
The features known to this version of CMake are:
``cxx_std_98``
Compiler mode is aware of C++ 98.
``cxx_std_11``
Compiler mode is aware of C++ 11.
``cxx_std_14``
Compiler mode is aware of C++ 14.
``cxx_aggregate_default_initializers``
Aggregate default initializers, as defined in N3605_.
......
......@@ -13,6 +13,15 @@ compile features and a list of supported compilers.
The features known to this version of CMake are:
``c_std_90``
Compiler mode is aware of C 90.
``c_std_99``
Compiler mode is aware of C 99.
``c_std_11``
Compiler mode is aware of C 11.
``c_function_prototypes``
Function prototypes, as defined in ``ISO/IEC 9899:1990``.
......
compile-features-for-language-standards
---------------------------------------
* The :manual:`Compile Features <cmake-compile-features(7)>` functionality
now offers meta-features that request compiler modes for specific language
standard levels. See :prop_gbl:`CMAKE_C_KNOWN_FEATURES` and
:prop_gbl:`CMAKE_CXX_KNOWN_FEATURES`.
......@@ -25,18 +25,14 @@ if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.0)
endif()
macro(cmake_record_c_compile_features)
macro(_get_appleclang_features std_version list)
record_compiler_features(C "${std_version}" ${list})
endmacro()
set(_result 0)
if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.0)
_get_appleclang_features(${CMAKE_C11_STANDARD_COMPILE_OPTION} CMAKE_C11_COMPILE_FEATURES)
_record_compiler_features_c(11)
if (_result EQUAL 0)
_get_appleclang_features(${CMAKE_C99_STANDARD_COMPILE_OPTION} CMAKE_C99_COMPILE_FEATURES)
_record_compiler_features_c(99)
endif()
if (_result EQUAL 0)
_get_appleclang_features(${CMAKE_C90_STANDARD_COMPILE_OPTION} CMAKE_C90_COMPILE_FEATURES)
_record_compiler_features_c(90)
endif()
endif()
endmacro()
......@@ -36,21 +36,17 @@ endif()
macro(cmake_record_cxx_compile_features)
macro(_get_appleclang_features std_version list)
record_compiler_features(CXX "${std_version}" ${list})
endmacro()
set(_result 0)
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.0)
set(_result 0)
if(CMAKE_CXX14_STANDARD_COMPILE_OPTION)
_get_appleclang_features(${CMAKE_CXX14_STANDARD_COMPILE_OPTION} CMAKE_CXX14_COMPILE_FEATURES)
_record_compiler_features_cxx(14)
endif()
if (_result EQUAL 0)
_get_appleclang_features(${CMAKE_CXX11_STANDARD_COMPILE_OPTION} CMAKE_CXX11_COMPILE_FEATURES)
_record_compiler_features_cxx(11)
endif()
if (_result EQUAL 0)
_get_appleclang_features(${CMAKE_CXX98_STANDARD_COMPILE_OPTION} CMAKE_CXX98_COMPILE_FEATURES)
_record_compiler_features_cxx(98)
endif()
endif()
endmacro()
......@@ -34,18 +34,14 @@ if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.4)
endif()
macro(cmake_record_c_compile_features)
macro(_get_clang_features std_version list)
record_compiler_features(C "${std_version}" ${list})
endmacro()
set(_result 0)
if (UNIX AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.4)
_get_clang_features(${CMAKE_C11_STANDARD_COMPILE_OPTION} CMAKE_C11_COMPILE_FEATURES)
_record_compiler_features_c(11)
if (_result EQUAL 0)
_get_clang_features(${CMAKE_C99_STANDARD_COMPILE_OPTION} CMAKE_C99_COMPILE_FEATURES)
_record_compiler_features_c(99)
endif()
if (_result EQUAL 0)
_get_clang_features(${CMAKE_C90_STANDARD_COMPILE_OPTION} CMAKE_C90_COMPILE_FEATURES)
_record_compiler_features_c(90)
endif()
endif()
endmacro()
......@@ -44,18 +44,14 @@ if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4)
endif()
macro(cmake_record_cxx_compile_features)
macro(_get_clang_features std_version list)
record_compiler_features(CXX "${std_version}" ${list})
endmacro()
set(_result 0)
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4)
_get_clang_features(${CMAKE_CXX14_STANDARD_COMPILE_OPTION} CMAKE_CXX14_COMPILE_FEATURES)
_record_compiler_features_cxx(14)
if (_result EQUAL 0)
_get_clang_features(${CMAKE_CXX11_STANDARD_COMPILE_OPTION} CMAKE_CXX11_COMPILE_FEATURES)
_record_compiler_features_cxx(11)
endif()
if (_result EQUAL 0)
_get_clang_features(${CMAKE_CXX98_STANDARD_COMPILE_OPTION} CMAKE_CXX98_COMPILE_FEATURES)
_record_compiler_features_cxx(98)
endif()
endif()
endmacro()
......@@ -40,20 +40,16 @@ endif()
macro(cmake_record_c_compile_features)
macro(_get_gcc_features std_version list)
record_compiler_features(C "${std_version}" ${list})
endmacro()
set(_result 0)
if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.6)
_get_gcc_features(${CMAKE_C11_STANDARD_COMPILE_OPTION} CMAKE_C11_COMPILE_FEATURES)
_record_compiler_features_c(11)
endif()
if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.4)
if (_result EQUAL 0)
_get_gcc_features(${CMAKE_C99_STANDARD_COMPILE_OPTION} CMAKE_C99_COMPILE_FEATURES)
_record_compiler_features_c(99)
endif()
if (_result EQUAL 0)
_get_gcc_features(${CMAKE_C90_STANDARD_COMPILE_OPTION} CMAKE_C90_COMPILE_FEATURES)
_record_compiler_features_c(90)
endif()
endif()
endmacro()
......@@ -47,20 +47,16 @@ if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4)
endif()
macro(cmake_record_cxx_compile_features)
macro(_get_gcc_features std_version list)
record_compiler_features(CXX "${std_version}" ${list})
endmacro()
set(_result 0)
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8)
_get_gcc_features(${CMAKE_CXX14_STANDARD_COMPILE_OPTION} CMAKE_CXX14_COMPILE_FEATURES)
_record_compiler_features_cxx(14)
endif()
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4)
if (_result EQUAL 0)
_get_gcc_features(${CMAKE_CXX11_STANDARD_COMPILE_OPTION} CMAKE_CXX11_COMPILE_FEATURES)
_record_compiler_features_cxx(11)
endif()
if (_result EQUAL 0)
_get_gcc_features(${CMAKE_CXX98_STANDARD_COMPILE_OPTION} CMAKE_CXX98_COMPILE_FEATURES)
_record_compiler_features_cxx(98)
endif()
endif()
endmacro()
......@@ -47,20 +47,16 @@ unset(_std)
unset(_ext)
macro(cmake_record_c_compile_features)
macro(_get_intel_c_features std_version list)
record_compiler_features(C "${std_version}" ${list})
endmacro()
set(_result 0)
if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 12.1)
if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 15.0.0)
_get_intel_c_features(${CMAKE_C11_STANDARD_COMPILE_OPTION} CMAKE_C11_COMPILE_FEATURES)
_record_compiler_features_C(11)
endif()
if (_result EQUAL 0)
_get_intel_c_features(${CMAKE_C99_STANDARD_COMPILE_OPTION} CMAKE_C99_COMPILE_FEATURES)
_record_compiler_features_C(99)
endif()
if (_result EQUAL 0)
_get_intel_c_features(${CMAKE_C90_STANDARD_COMPILE_OPTION} CMAKE_C90_COMPILE_FEATURES)
_record_compiler_features_C(90)
endif()
endif()
endmacro()
......
......@@ -60,20 +60,16 @@ unset(_std)
unset(_ext)
macro(cmake_record_cxx_compile_features)
macro(_get_intel_features std_version list)
record_compiler_features(CXX "${std_version}" ${list})
endmacro()
set(_result 0)
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.1)
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0)
_get_intel_features("${CMAKE_CXX14_STANDARD_COMPILE_OPTION}" CMAKE_CXX14_COMPILE_FEATURES)
_record_compiler_features_cxx(14)
endif()
if (_result EQUAL 0)
_get_intel_features("${CMAKE_CXX11_STANDARD_COMPILE_OPTION}" CMAKE_CXX11_COMPILE_FEATURES)
_record_compiler_features_cxx(11)
endif()
if (_result EQUAL 0)
_get_intel_features("${CMAKE_CXX98_STANDARD_COMPILE_OPTION}" CMAKE_CXX98_COMPILE_FEATURES)
_record_compiler_features_cxx(98)
endif()
endif()
endmacro()
......
......@@ -5,5 +5,12 @@ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16.0)
endif()
macro(cmake_record_cxx_compile_features)
record_compiler_features(CXX "" CMAKE_CXX_COMPILE_FEATURES)
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16.0)
list(APPEND CMAKE_CXX_COMPILE_FEATURES
cxx_std_98
cxx_std_11
cxx_std_14
)
_record_compiler_features(CXX "" CMAKE_CXX_COMPILE_FEATURES)
endif()
endmacro()
......@@ -32,6 +32,8 @@ set(CMAKE_CXX_CREATE_STATIC_LIBRARY
"<CMAKE_RANLIB> <TARGET> ")
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.13)
set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")
set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=c++11")
endif()
......@@ -49,15 +51,11 @@ if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.13)
endif()
macro(cmake_record_cxx_compile_features)
macro(_get_solaris_studio_features std_version list)
record_compiler_features(CXX "${std_version}" ${list})
endmacro()
set(_result 0)
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.13)
_get_solaris_studio_features(${CMAKE_CXX11_STANDARD_COMPILE_OPTION} CMAKE_CXX11_COMPILE_FEATURES)
_record_compiler_features_cxx(11)
if (_result EQUAL 0)
_get_solaris_studio_features("" CMAKE_CXX98_COMPILE_FEATURES)
_record_compiler_features_cxx(98)
endif()
endif()
endmacro()
macro(record_compiler_features lang compile_flags feature_list)
macro(_record_compiler_features lang compile_flags feature_list)
include("${CMAKE_ROOT}/Modules/Compiler/${CMAKE_${lang}_COMPILER_ID}-${lang}-FeatureTests.cmake" OPTIONAL)
string(TOLOWER ${lang} lang_lc)
......@@ -58,3 +58,13 @@ macro(record_compiler_features lang compile_flags feature_list)
"Detecting ${lang} [${compile_flags}] compiler features failed to compile with the following output:\n${_output}\n${_copy_error}\n\n")
endif()
endmacro()
macro(_record_compiler_features_c std)
list(APPEND CMAKE_C${std}_COMPILE_FEATURES c_std_${std})
_record_compiler_features(C "${CMAKE_C${std}_STANDARD_COMPILE_OPTION}" CMAKE_C${std}_COMPILE_FEATURES)
endmacro()
macro(_record_compiler_features_cxx std)
list(APPEND CMAKE_CXX${std}_COMPILE_FEATURES cxx_std_${std})
_record_compiler_features(CXX "${CMAKE_CXX${std}_STANDARD_COMPILE_OPTION}" CMAKE_CXX${std}_COMPILE_FEATURES)
endmacro()
......@@ -76,6 +76,7 @@
# Available features in this version of CMake are listed in the
# :prop_gbl:`CMAKE_C_KNOWN_FEATURES` and
# :prop_gbl:`CMAKE_CXX_KNOWN_FEATURES` global properties.
# The ``{c,cxx}_std_*`` meta-features are ignored if requested.
#
# See the :manual:`cmake-compile-features(7)` manual for information on
# compile features.
......@@ -358,7 +359,11 @@ function(write_compiler_detection_header
endif()
foreach(feature ${_WCD_FEATURES})
if (feature MATCHES "^cxx_")
if (feature MATCHES "^c_std_")
# ignored
elseif (feature MATCHES "^cxx_std_")
# ignored
elseif (feature MATCHES "^cxx_")
list(APPEND _langs CXX)
list(APPEND CXX_features ${feature})
elseif (feature MATCHES "^c_")
......
......@@ -535,12 +535,18 @@ private:
}
#define FOR_EACH_C_FEATURE(F) \
F(c_std_90) \
F(c_std_99) \
F(c_std_11) \
F(c_function_prototypes) \
F(c_restrict) \
F(c_static_assert) \
F(c_variadic_macros)
#define FOR_EACH_CXX_FEATURE(F) \
F(cxx_std_98) \
F(cxx_std_11) \
F(cxx_std_14) \
F(cxx_aggregate_default_initializers) \
F(cxx_alias_templates) \
F(cxx_alignas) \
......
......@@ -23,10 +23,12 @@ macro(run_test feature lang)
endmacro()
get_property(c_features GLOBAL PROPERTY CMAKE_C_KNOWN_FEATURES)
list(REMOVE_ITEM c_features c_std_90 c_std_99 c_std_11)
foreach(feature ${c_features})
run_test(${feature} C)
endforeach()
get_property(cxx_features GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES)
list(REMOVE_ITEM cxx_features cxx_std_98 cxx_std_11 cxx_std_14)
foreach(feature ${cxx_features})
run_test(${feature} CXX)
endforeach()
......@@ -396,7 +398,7 @@ if (CMAKE_CXX_COMPILE_FEATURES)
)
add_executable(CompileFeaturesGenex2 genex_test.cpp)
target_compile_features(CompileFeaturesGenex2 PRIVATE cxx_static_assert)
target_compile_features(CompileFeaturesGenex2 PRIVATE cxx_std_11)
target_compile_definitions(CompileFeaturesGenex2 PRIVATE
HAVE_OVERRIDE_CONTROL=$<COMPILE_FEATURES:cxx_final,cxx_override>
HAVE_AUTO_TYPE=$<COMPILE_FEATURES:cxx_auto_type>
......@@ -405,10 +407,10 @@ if (CMAKE_CXX_COMPILE_FEATURES)
HAVE_INHERITING_CONSTRUCTORS_AND_FINAL=$<COMPILE_FEATURES:cxx_inheriting_constructors,cxx_final>
)
add_library(static_assert_iface INTERFACE)
target_compile_features(static_assert_iface INTERFACE cxx_static_assert)
add_library(std_11_iface INTERFACE)
target_compile_features(std_11_iface INTERFACE cxx_std_11)
add_executable(CompileFeaturesGenex3 genex_test.cpp)
target_link_libraries(CompileFeaturesGenex3 PRIVATE static_assert_iface)
target_link_libraries(CompileFeaturesGenex3 PRIVATE std_11_iface)
target_compile_definitions(CompileFeaturesGenex3 PRIVATE
HAVE_OVERRIDE_CONTROL=$<COMPILE_FEATURES:cxx_final,cxx_override>
HAVE_AUTO_TYPE=$<COMPILE_FEATURES:cxx_auto_type>
......
......@@ -3,13 +3,13 @@ add_library(empty1 empty.cpp)
add_library(empty2 INTERFACE)
add_library(empty3 INTERFACE)
target_compile_features(empty3 INTERFACE cxx_static_assert)
target_compile_features(empty3 INTERFACE cxx_std_11)
target_link_libraries(empty1
# When starting, $<COMPILE_FEATURES:cxx_auto_type> is '0', so 'freeze' the
# CXX_STANDARD at 98 during computation.
$<$<COMPILE_FEATURES:cxx_auto_type>:empty2>
# This would add cxx_static_assert, but that would require CXX_STANDARD = 11,
# This would add cxx_std_11, but that would require CXX_STANDARD = 11,
# which is not allowed after freeze. Report an error.
empty3
)
......@@ -3,7 +3,7 @@ add_library(empty1 empty.cpp)
add_library(empty2 INTERFACE)
add_library(empty3 INTERFACE)
target_compile_features(empty3 INTERFACE cxx_static_assert)
target_compile_features(empty3 INTERFACE cxx_std_11)
target_link_libraries(empty1
$<$<COMPILE_FEATURES:cxx_nullptr>:empty2>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment