summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/manual/cmake-compile-features.7.rst22
-rw-r--r--Help/release/dev/lang-std-flag-order.rst7
-rw-r--r--Source/cmLocalGenerator.cxx27
-rw-r--r--Tests/CompileFeatures/CMakeLists.txt13
-rw-r--r--Tests/CompileFeatures/msvc_permissive.cxx9
5 files changed, 63 insertions, 15 deletions
diff --git a/Help/manual/cmake-compile-features.7.rst b/Help/manual/cmake-compile-features.7.rst
index 8073511..1e87ec6 100644
--- a/Help/manual/cmake-compile-features.7.rst
+++ b/Help/manual/cmake-compile-features.7.rst
@@ -282,3 +282,25 @@ versions specified for each:
* ``Clang``: Clang compiler 5.0+.
* ``NVIDIA``: NVIDIA nvcc compiler 7.5+.
+
+.. _`Language Standard Flags`:
+
+Language Standard Flags
+=======================
+
+In order to satisfy requirements specified by the
+:command:`target_compile_features` command or the
+:variable:`CMAKE_<LANG>_STANDARD` variable, CMake may pass a
+language standard flag to the compiler, such as ``-std=c++11``.
+
+For :ref:`Visual Studio Generators`, CMake cannot precisely control
+the placement of the language standard flag on the compiler command line.
+For :ref:`Ninja Generators`, :ref:`Makefile Generators`, and
+:generator:`Xcode`, CMake places the language standard flag just after
+the language-wide flags from :variable:`CMAKE_<LANG>_FLAGS`
+and :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>`.
+
+.. versionchanged:: 3.26
+ The language standard flag is placed before flags specified by other
+ abstractions such as the :command:`target_compile_options` command.
+ Prior to CMake 3.26, the language standard flag was placed after them.
diff --git a/Help/release/dev/lang-std-flag-order.rst b/Help/release/dev/lang-std-flag-order.rst
new file mode 100644
index 0000000..4ef4123
--- /dev/null
+++ b/Help/release/dev/lang-std-flag-order.rst
@@ -0,0 +1,7 @@
+lang-std-flag-order
+-------------------
+
+* :ref:`Language Standard Flags`, such as ``-std=c++11``, when generated due
+ to :command:`target_compile_features` or :variable:`CMAKE_<LANG>_STANDARD`,
+ are now placed before flags added by :command:`target_compile_options`,
+ rather than after them.
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 9745142..550141f 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -1021,12 +1021,6 @@ void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags,
}
}
- std::string compReqFlag;
- this->AddCompilerRequirementFlag(compReqFlag, target, lang, config);
- if (!compReqFlag.empty()) {
- flags.emplace_back(std::move(compReqFlag));
- }
-
// Add Warning as errors flags
if (!this->GetCMakeInstance()->GetIgnoreWarningAsError()) {
const cmValue wError = target->GetProperty("COMPILE_WARNING_AS_ERROR");
@@ -1932,6 +1926,18 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags,
this->AddConfigVariableFlags(flags, cmStrCat("CMAKE_", lang, "_FLAGS"),
config);
+ // Add the language standard flag for compiling, and sometimes linking.
+ if (compileOrLink == cmBuildStep::Compile ||
+ (compileOrLink == cmBuildStep::Link &&
+ // Some toolchains require use of the language standard flag
+ // when linking in order to use the matching standard library.
+ // FIXME: If CMake gains an abstraction for standard library
+ // selection, this will have to be reconciled with it.
+ this->Makefile->IsOn(
+ cmStrCat("CMAKE_", lang, "_LINK_WITH_STANDARD_COMPILE_OPTION")))) {
+ this->AddCompilerRequirementFlag(flags, target, lang, config);
+ }
+
std::string compiler = this->Makefile->GetSafeDefinition(
cmStrCat("CMAKE_", lang, "_COMPILER_ID"));
@@ -2076,15 +2082,6 @@ void cmLocalGenerator::AddLanguageFlagsForLinking(
std::string& flags, cmGeneratorTarget const* target, const std::string& lang,
const std::string& config)
{
- if (this->Makefile->IsOn("CMAKE_" + lang +
- "_LINK_WITH_STANDARD_COMPILE_OPTION")) {
- // This toolchain requires use of the language standard flag
- // when linking in order to use the matching standard library.
- // FIXME: If CMake gains an abstraction for standard library
- // selection, this will have to be reconciled with it.
- this->AddCompilerRequirementFlag(flags, target, lang, config);
- }
-
this->AddLanguageFlags(flags, target, cmBuildStep::Link, lang, config);
if (target->IsIPOEnabled(lang, config)) {
diff --git a/Tests/CompileFeatures/CMakeLists.txt b/Tests/CompileFeatures/CMakeLists.txt
index f3d3a73..17f4408 100644
--- a/Tests/CompileFeatures/CMakeLists.txt
+++ b/Tests/CompileFeatures/CMakeLists.txt
@@ -374,3 +374,16 @@ else()
target_link_libraries(CompileFeaturesGenex3 PRIVATE std_11_iface)
target_compile_definitions(CompileFeaturesGenex3 PRIVATE ${genex_test_defs} ALLOW_LATER_STANDARDS=1)
endif()
+
+if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC"
+ AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.30
+ # The MSVC 14.29.30133 toolset supports C++20,
+ # but MSBuild puts the flags in the wrong order.
+ OR (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.29.30129 AND NOT CMAKE_GENERATOR MATCHES "Visual Studio")
+ )
+ )
+ add_library(msvc_permissive msvc_permissive.cxx)
+ target_compile_features(msvc_permissive PRIVATE cxx_std_20)
+ # The `-std:c++20` flag implies `-permissive-`. Test passing `-permissive` afterward.
+ target_compile_options(msvc_permissive PRIVATE -permissive)
+endif()
diff --git a/Tests/CompileFeatures/msvc_permissive.cxx b/Tests/CompileFeatures/msvc_permissive.cxx
new file mode 100644
index 0000000..a8f2ff3
--- /dev/null
+++ b/Tests/CompileFeatures/msvc_permissive.cxx
@@ -0,0 +1,9 @@
+#if !defined(_MSVC_LANG) || _MSVC_LANG < 202002L
+# error "This source must be compiled with MSVC as C++20 or later."
+#endif
+// Test a construct that is allowed by MSVC only with 'cl -permissive'.
+enum class X
+{
+ Y = 1
+};
+int array[X::Y];