diff options
-rw-r--r-- | Help/manual/cmake-compile-features.7.rst | 22 | ||||
-rw-r--r-- | Help/release/dev/lang-std-flag-order.rst | 7 | ||||
-rw-r--r-- | Source/cmLocalGenerator.cxx | 27 | ||||
-rw-r--r-- | Tests/CompileFeatures/CMakeLists.txt | 13 | ||||
-rw-r--r-- | Tests/CompileFeatures/msvc_permissive.cxx | 9 |
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]; |