Ver Fonte

Merge topic 'enable_language-deduplicate'

e3c8012ccd Help: Document enable_language accepting multiple languages
b4fd385c9b cmMakefile: Dedupe languages when enabling them
66bfe14309 cmMakefile: Refactor parameter and variable names for EnableLanguage

Acked-by: Kitware Robot <[email protected]>
Acked-by: buildbot <[email protected]>
Merge-request: !7426
Brad King há 3 anos atrás
pai
commit
b80ccea686

+ 5 - 4
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(<lang> [OPTIONAL] )
+  enable_language(<lang>... [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``.

+ 36 - 12
Source/cmMakefile.cxx

@@ -3479,7 +3479,7 @@ void cmMakefile::AddTargetObject(std::string const& tgtName,
 #endif
 }
 
-void cmMakefile::EnableLanguage(std::vector<std::string> const& lang,
+void cmMakefile::EnableLanguage(std::vector<std::string> const& languages,
                                 bool optional)
 {
   if (this->DeferRunning) {
@@ -3491,24 +3491,48 @@ void cmMakefile::EnableLanguage(std::vector<std::string> const& lang,
   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> langs;
-  std::vector<std::string> langsRC;
-  langs.reserve(lang.size());
-  for (std::string const& i : lang) {
-    if (i == "RC") {
-      langsRC.push_back(i);
+  std::vector<std::string> languages_without_RC;
+  std::vector<std::string> languages_for_RC;
+  languages_without_RC.reserve(unique_languages.size());
+  for (std::string const& language : unique_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);
   }
 }
 

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