1
0
Эх сурвалжийг харах

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
friendlyanon 3 жил өмнө
parent
commit
b4fd385c9b

+ 24 - 2
Source/cmMakefile.cxx

@@ -3491,13 +3491,35 @@ void cmMakefile::EnableLanguage(std::vector<std::string> const& languages,
   if (const char* def = this->GetGlobalGenerator()->GetCMakeCFGIntDir()) {
     this->AddDefinition("CMAKE_CFG_INTDIR", def);
   }
+
+  std::vector<std::string> unique_languages;
+  {
+    std::vector<std::string> 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<std::string> languages_without_RC;
   std::vector<std::string> 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 {

+ 10 - 0
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()

+ 11 - 0
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()

+ 5 - 0
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)