From 66bfe14309e9e8968a159d1eda7ed00322d5559d Mon Sep 17 00:00:00 2001 From: friendlyanon Date: Thu, 30 Jun 2022 20:27:42 +0200 Subject: cmMakefile: Refactor parameter and variable names for EnableLanguage In commit 731369ef9c (ENH: try to initialize all languages at the same time, 2004-08-27, v2.4.0~2899) the languages parameter name for cmMakefile::EnableLanguage() was changed to "std::vector languages" in the declaration, however the definition had "std::vector lang". Furthermore, the variable names in the definition had confusing names, such as the "i" variable in the loop which referred to an iterator at one point, but no longer does. --- Source/cmMakefile.cxx | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 62ea427..79a56c1 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -3479,7 +3479,7 @@ void cmMakefile::AddTargetObject(std::string const& tgtName, #endif } -void cmMakefile::EnableLanguage(std::vector const& lang, +void cmMakefile::EnableLanguage(std::vector const& languages, bool optional) { if (this->DeferRunning) { @@ -3494,21 +3494,23 @@ void cmMakefile::EnableLanguage(std::vector const& lang, // If RC is explicitly listed we need to do it after other languages. // On some platforms we enable RC implicitly while enabling others. // Do not let that look like recursive enable_language(RC). - std::vector langs; - std::vector langsRC; - langs.reserve(lang.size()); - for (std::string const& i : lang) { - if (i == "RC") { - langsRC.push_back(i); + std::vector languages_without_RC; + std::vector languages_for_RC; + languages_without_RC.reserve(languages.size()); + for (std::string const& language : languages) { + if (language == "RC") { + languages_for_RC.push_back(language); } else { - langs.push_back(i); + languages_without_RC.push_back(language); } } - if (!langs.empty()) { - this->GetGlobalGenerator()->EnableLanguage(langs, this, optional); + if (!languages_without_RC.empty()) { + this->GetGlobalGenerator()->EnableLanguage(languages_without_RC, this, + optional); } - if (!langsRC.empty()) { - this->GetGlobalGenerator()->EnableLanguage(langsRC, this, optional); + if (!languages_for_RC.empty()) { + this->GetGlobalGenerator()->EnableLanguage(languages_for_RC, this, + optional); } } -- cgit v0.12 From b4fd385c9b467182d3572854168e2afa037210bc Mon Sep 17 00:00:00 2001 From: friendlyanon Date: Thu, 30 Jun 2022 20:51:18 +0200 Subject: cmMakefile: Dedupe languages when enabling them cmMakefile::EnableLanguage() now deduplicates the languages argument and emits an author warning listing the languages that were defined multiple times in a single call. Fixes: #23596 --- Source/cmMakefile.cxx | 26 ++++++++++++++++++++-- .../project/LanguagesDuplicate-check.cmake | 10 +++++++++ Tests/RunCMake/project/LanguagesDuplicate.cmake | 11 +++++++++ Tests/RunCMake/project/RunCMakeTest.cmake | 5 +++++ 4 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 Tests/RunCMake/project/LanguagesDuplicate-check.cmake create mode 100644 Tests/RunCMake/project/LanguagesDuplicate.cmake diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 79a56c1..208d907 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -3491,13 +3491,35 @@ void cmMakefile::EnableLanguage(std::vector const& languages, if (const char* def = this->GetGlobalGenerator()->GetCMakeCFGIntDir()) { this->AddDefinition("CMAKE_CFG_INTDIR", def); } + + std::vector unique_languages; + { + std::vector duplicate_languages; + for (std::string const& language : languages) { + if (!cm::contains(unique_languages, language)) { + unique_languages.push_back(language); + } else if (!cm::contains(duplicate_languages, language)) { + duplicate_languages.push_back(language); + } + } + if (!duplicate_languages.empty()) { + auto quantity = duplicate_languages.size() == 1 ? std::string(" has") + : std::string("s have"); + this->IssueMessage(MessageType::AUTHOR_WARNING, + "Languages to be enabled may not be specified more " + "than once at the same time. The following language" + + quantity + " been specified multiple times: " + + cmJoin(duplicate_languages, ", ")); + } + } + // If RC is explicitly listed we need to do it after other languages. // On some platforms we enable RC implicitly while enabling others. // Do not let that look like recursive enable_language(RC). std::vector languages_without_RC; std::vector languages_for_RC; - languages_without_RC.reserve(languages.size()); - for (std::string const& language : languages) { + languages_without_RC.reserve(unique_languages.size()); + for (std::string const& language : unique_languages) { if (language == "RC") { languages_for_RC.push_back(language); } else { diff --git a/Tests/RunCMake/project/LanguagesDuplicate-check.cmake b/Tests/RunCMake/project/LanguagesDuplicate-check.cmake new file mode 100644 index 0000000..31c7da3 --- /dev/null +++ b/Tests/RunCMake/project/LanguagesDuplicate-check.cmake @@ -0,0 +1,10 @@ +if(NOT actual_stderr MATCHES "The following language has been specified multiple times: C\n") + set(RunCMake_TEST_FAILED "'LANGUAGES C C C' should report only 'C' and only once.") +endif() + +if(NOT actual_stderr MATCHES "The following languages have been specified multiple times: C, CXX\n") + if(RunCMake_TEST_FAILED) + string(APPEND RunCMake_TEST_FAILED "\n") + endif() + string(APPEND RunCMake_TEST_FAILED "'LANGUAGES C C CXX CXX' should report 'C' and 'CXX'.") +endif() diff --git a/Tests/RunCMake/project/LanguagesDuplicate.cmake b/Tests/RunCMake/project/LanguagesDuplicate.cmake new file mode 100644 index 0000000..97a79d0 --- /dev/null +++ b/Tests/RunCMake/project/LanguagesDuplicate.cmake @@ -0,0 +1,11 @@ +cmake_policy(SET CMP0057 NEW) + +project(ProjectA C C C) +project(ProjectB C C CXX CXX) + +get_property(langs GLOBAL PROPERTY ENABLED_LANGUAGES) +foreach(lang C CXX) + if(NOT lang IN_LIST langs) + message(FATAL_ERROR "Expected language '${lang}' to be enabled.") + endif() +endforeach() diff --git a/Tests/RunCMake/project/RunCMakeTest.cmake b/Tests/RunCMake/project/RunCMakeTest.cmake index 945d9ed..6d9f52f 100644 --- a/Tests/RunCMake/project/RunCMakeTest.cmake +++ b/Tests/RunCMake/project/RunCMakeTest.cmake @@ -12,6 +12,11 @@ run_cmake_with_options(CodeInjection if(CMake_TEST_RESOURCES) run_cmake(ExplicitRC) endif() + +set(RunCMake_DEFAULT_stderr .) +run_cmake(LanguagesDuplicate) +unset(RunCMake_DEFAULT_stderr) + run_cmake(LanguagesImplicit) run_cmake(LanguagesEmpty) run_cmake(LanguagesNONE) -- cgit v0.12 From e3c8012ccd067c90408502eef7631badd60f67e0 Mon Sep 17 00:00:00 2001 From: friendlyanon Date: Wed, 29 Jun 2022 22:25:08 +0200 Subject: Help: Document enable_language accepting multiple languages --- Help/command/enable_language.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Help/command/enable_language.rst b/Help/command/enable_language.rst index d2acbc8..d9103b8 100644 --- a/Help/command/enable_language.rst +++ b/Help/command/enable_language.rst @@ -1,13 +1,14 @@ enable_language --------------- -Enable a language (CXX/C/OBJC/OBJCXX/Fortran/etc) + +Enable languages (CXX/C/OBJC/OBJCXX/Fortran/etc) .. code-block:: cmake - enable_language( [OPTIONAL] ) + enable_language(... [OPTIONAL]) -Enables support for the named language in CMake. This is -the same as the :command:`project` command but does not create any of the extra +Enables support for the named languages in CMake. This is the same as +the :command:`project` command but does not create any of the extra variables that are created by the project command. Example languages are ``CXX``, ``C``, ``CUDA``, ``OBJC``, ``OBJCXX``, ``Fortran``, ``HIP``, ``ISPC``, and ``ASM``. -- cgit v0.12