浏览代码

Link step: Add LINK_WARNING_AS_ERROR target property

Add a way to specify, in a portable way, to raise an error for any
warning during the link step. For that purpose, define:
* CMAKE_LINK_WARNING_AS_ERROR variable
* LINK_WARNING_AS_ERROR target property

Fixes: #25343
Marc Chevrier 1 年之前
父节点
当前提交
7907c83175
共有 58 个文件被更改,包括 421 次插入28 次删除
  1. 1 0
      Help/manual/cmake-properties.7.rst
  2. 1 0
      Help/manual/cmake-variables.7.rst
  3. 8 0
      Help/manual/cmake.1.rst
  4. 27 0
      Help/prop_tgt/LINK_WARNING_AS_ERROR.rst
  5. 11 0
      Help/release/dev/link-warning-as-error.rst
  6. 9 0
      Help/variable/CMAKE_LINK_WARNING_AS_ERROR.rst
  7. 2 0
      Modules/Linker/AIX.cmake
  8. 2 0
      Modules/Linker/AppleClang.cmake
  9. 5 1
      Modules/Linker/GNU.cmake
  10. 14 2
      Modules/Linker/LLD.cmake
  11. 2 2
      Modules/Linker/MOLD-ASM.cmake
  12. 2 2
      Modules/Linker/MOLD-C.cmake
  13. 2 2
      Modules/Linker/MOLD-CUDA.cmake
  14. 2 2
      Modules/Linker/MOLD-CXX.cmake
  15. 2 2
      Modules/Linker/MOLD-Fortran.cmake
  16. 2 2
      Modules/Linker/MOLD-HIP.cmake
  17. 2 2
      Modules/Linker/MOLD-OBJC.cmake
  18. 2 2
      Modules/Linker/MOLD-OBJCXX.cmake
  19. 23 0
      Modules/Linker/MOLD.cmake
  20. 6 0
      Modules/Linker/MSVC-ASM.cmake
  21. 6 0
      Modules/Linker/MSVC-C.cmake
  22. 6 0
      Modules/Linker/MSVC-CUDA.cmake
  23. 6 0
      Modules/Linker/MSVC-CXX.cmake
  24. 6 0
      Modules/Linker/MSVC-Fortran.cmake
  25. 6 0
      Modules/Linker/MSVC-HIP.cmake
  26. 12 0
      Modules/Linker/MSVC.cmake
  27. 2 0
      Modules/Linker/Solaris.cmake
  28. 6 0
      Source/cmGlobalGenerator.cxx
  29. 1 0
      Source/cmGlobalNinjaGenerator.cxx
  30. 3 0
      Source/cmGlobalVisualStudio8Generator.cxx
  31. 10 8
      Source/cmGlobalXCodeGenerator.cxx
  32. 29 0
      Source/cmLocalGenerator.cxx
  33. 3 0
      Source/cmLocalGenerator.h
  34. 2 0
      Source/cmLocalUnixMakefileGenerator3.cxx
  35. 6 0
      Source/cmLocalVisualStudio7Generator.cxx
  36. 2 0
      Source/cmMakefileTargetGenerator.cxx
  37. 1 0
      Source/cmTarget.cxx
  38. 3 0
      Source/cmVisualStudio10TargetGenerator.cxx
  39. 8 0
      Source/cmake.cxx
  40. 9 0
      Source/cmake.h
  41. 4 1
      Source/cmakemain.cxx
  42. 6 0
      Tests/RunCMake/CMakeLists.txt
  43. 3 0
      Tests/RunCMake/LinkWarningAsError/CMakeLists.txt
  44. 19 0
      Tests/RunCMake/LinkWarningAsError/RunCMakeTest.cmake
  45. 20 0
      Tests/RunCMake/LinkWarningAsError/WarnError-validation.cmake
  46. 54 0
      Tests/RunCMake/LinkWarningAsError/WarnError.cmake
  47. 4 0
      Tests/RunCMake/LinkWarningAsError/WarnErrorOff1-Build-check.cmake
  48. 5 0
      Tests/RunCMake/LinkWarningAsError/WarnErrorOff1.cmake
  49. 4 0
      Tests/RunCMake/LinkWarningAsError/WarnErrorOff2-Build-check.cmake
  50. 5 0
      Tests/RunCMake/LinkWarningAsError/WarnErrorOff2.cmake
  51. 4 0
      Tests/RunCMake/LinkWarningAsError/WarnErrorOn1-Build-check.cmake
  52. 5 0
      Tests/RunCMake/LinkWarningAsError/WarnErrorOn1.cmake
  53. 4 0
      Tests/RunCMake/LinkWarningAsError/WarnErrorOn2-Build-check.cmake
  54. 5 0
      Tests/RunCMake/LinkWarningAsError/WarnErrorOn2.cmake
  55. 4 0
      Tests/RunCMake/LinkWarningAsError/WarnErrorOnIgnore-Build-check.cmake
  56. 5 0
      Tests/RunCMake/LinkWarningAsError/WarnErrorOnIgnore.cmake
  57. 13 0
      Tests/RunCMake/LinkWarningAsError/dump.c
  58. 5 0
      Tests/RunCMake/LinkWarningAsError/main.c

+ 1 - 0
Help/manual/cmake-properties.7.rst

@@ -342,6 +342,7 @@ Properties on Targets
    /prop_tgt/LINK_OPTIONS
    /prop_tgt/LINK_SEARCH_END_STATIC
    /prop_tgt/LINK_SEARCH_START_STATIC
+   /prop_tgt/LINK_WARNING_AS_ERROR
    /prop_tgt/LINK_WHAT_YOU_USE
    /prop_tgt/LINKER_LANGUAGE
    /prop_tgt/LINKER_TYPE

+ 1 - 0
Help/manual/cmake-variables.7.rst

@@ -499,6 +499,7 @@ Variables that Control the Build
    /variable/CMAKE_LINK_LIBRARY_FLAG
    /variable/CMAKE_LINK_LIBRARY_USING_FEATURE
    /variable/CMAKE_LINK_LIBRARY_USING_FEATURE_SUPPORTED
+   /variable/CMAKE_LINK_WARNING_AS_ERROR
    /variable/CMAKE_LINK_WHAT_YOU_USE
    /variable/CMAKE_LINK_WHAT_YOU_USE_CHECK
    /variable/CMAKE_LINKER_TYPE

+ 8 - 0
Help/manual/cmake.1.rst

@@ -513,6 +513,14 @@ Options
  :variable:`CMAKE_COMPILE_WARNING_AS_ERROR`, preventing warnings from being
  treated as errors on compile.
 
+.. option:: --link-no-warning-as-error
+
+ .. versionadded:: 3.32
+
+ Ignore target property :prop_tgt:`LINK_WARNING_AS_ERROR` and variable
+ :variable:`CMAKE_LINK_WARNING_AS_ERROR`, preventing warnings from being
+ treated as errors on link.
+
 .. option:: --profiling-output=<path>
 
  .. versionadded:: 3.18

+ 27 - 0
Help/prop_tgt/LINK_WARNING_AS_ERROR.rst

@@ -0,0 +1,27 @@
+LINK_WARNING_AS_ERROR
+---------------------
+
+.. versionadded:: 3.32
+
+Specify whether to treat warnings on link as errors.
+If enabled, adds a flag to treat warnings on link as errors.
+If the :option:`cmake --link-no-warning-as-error` option is given
+on the :manual:`cmake(1)` command line, this property is ignored.
+
+This property is not implemented for all linkers.  It is silently ignored
+if there is no implementation for the linker being used.  The currently
+implemented :variable:`compiler linker IDs <CMAKE_<LANG>_COMPILER_LINKER_ID>`
+are:
+
+* ``AIX``
+* ``AppleClang``
+* ``GNU``
+* ``GNUgold``
+* ``LLD``
+* ``MOLD``
+* ``MSVC``
+* ``Solaris``
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_LINK_WARNING_AS_ERROR` if it is set when a target is
+created.

+ 11 - 0
Help/release/dev/link-warning-as-error.rst

@@ -0,0 +1,11 @@
+link-warning-as-error
+---------------------
+
+* The :variable:`CMAKE_LINK_WARNING_AS_ERROR` variable and corresponding
+  :prop_tgt:`LINK_WARNING_AS_ERROR` target property were added to enable
+  link with a linker-specific flag to treat warnings as errors.
+* The :manual:`cmake(1)` command line gained the
+  :option:`--link-no-warning-as-error <cmake --link-no-warning-as-error>`
+  option which causes the effects of the :prop_tgt:`LINK_WARNING_AS_ERROR`
+  target property and :variable:`CMAKE_LINK_WARNING_AS_ERROR` variable to be
+  ignored.

+ 9 - 0
Help/variable/CMAKE_LINK_WARNING_AS_ERROR.rst

@@ -0,0 +1,9 @@
+CMAKE_LINK_WARNING_AS_ERROR
+---------------------------
+
+.. versionadded:: 3.32
+
+Specify whether to treat warnings on link as errors.
+
+This variable is used to initialize the
+:prop_tgt:`LINK_WARNING_AS_ERROR` property on all the targets.

+ 2 - 0
Modules/Linker/AIX.cmake

@@ -6,4 +6,6 @@
 include_guard()
 
 macro(__linker_aix lang)
+  # Linker warning as error
+  set(CMAKE_${lang}_LINK_OPTIONS_WARNING_AS_ERROR "LINKER:-bhalt:0")
 endmacro()

+ 2 - 0
Modules/Linker/AppleClang.cmake

@@ -7,4 +7,6 @@
 include_guard()
 
 macro(__linker_appleclang lang)
+  # Linker warning as error
+  set(CMAKE_${lang}_LINK_OPTIONS_WARNING_AS_ERROR "LINKER:-fatal_warnings")
 endmacro()

+ 5 - 1
Modules/Linker/GNU.cmake

@@ -65,10 +65,14 @@ function(__linker_gnu lang)
     set(CMAKE_${lang}_LINK_DEPENDS_USE_LINKER FALSE)
   endif()
 
+  # Linker warning as error
+  set(CMAKE_${lang}_LINK_OPTIONS_WARNING_AS_ERROR "LINKER:--fatal-warnings")
+
   return(PROPAGATE CMAKE_${lang}_LINKER_DEPFILE_FLAGS
     CMAKE_${lang}_LINKER_DEPFILE_FORMAT
     CMAKE_${lang}_LINKER_DEPFILE_SUPPORTED
-    CMAKE_${lang}_LINK_DEPENDS_USE_LINKER)
+    CMAKE_${lang}_LINK_DEPENDS_USE_LINKER
+    CMAKE_${lang}_LINK_OPTIONS_WARNING_AS_ERROR)
 endfunction()
 
 endblock()

+ 14 - 2
Modules/Linker/LLD.cmake

@@ -3,8 +3,20 @@
 
 include_guard()
 
-include(Linker/GNU)
+
+block(SCOPE_FOR POLICIES)
+cmake_policy(SET CMP0054 NEW)
 
 macro(__linker_lld lang)
-  __linker_gnu(${lang})
+  if(CMAKE_${lang}_COMPILER_LINKER_FRONTEND_VARIANT STREQUAL "MSVC")
+    include(Linker/MSVC)
+
+    __linker_msvc(${lang})
+  else()
+    include(Linker/GNU)
+
+    __linker_gnu(${lang})
+  endif()
 endmacro()
+
+endblock()

+ 2 - 2
Modules/Linker/MOLD-ASM.cmake

@@ -1,6 +1,6 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file Copyright.txt or https://cmake.org/licensing for details.
 
-include(Linker/GNU)
+include(Linker/MOLD)
 
-__linker_gnu(ASM)
+__linker_mold(ASM)

+ 2 - 2
Modules/Linker/MOLD-C.cmake

@@ -1,6 +1,6 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file Copyright.txt or https://cmake.org/licensing for details.
 
-include(Linker/GNU)
+include(Linker/MOLD)
 
-__linker_gnu(C)
+__linker_mold(C)

+ 2 - 2
Modules/Linker/MOLD-CUDA.cmake

@@ -1,6 +1,6 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file Copyright.txt or https://cmake.org/licensing for details.
 
-include(Linker/GNU)
+include(Linker/MOLD)
 
-__linker_gnu(CUDA)
+__linker_mold(CUDA)

+ 2 - 2
Modules/Linker/MOLD-CXX.cmake

@@ -1,6 +1,6 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file Copyright.txt or https://cmake.org/licensing for details.
 
-include(Linker/GNU)
+include(Linker/MOLD)
 
-__linker_gnu(CXX)
+__linker_mold(CXX)

+ 2 - 2
Modules/Linker/MOLD-Fortran.cmake

@@ -1,6 +1,6 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file Copyright.txt or https://cmake.org/licensing for details.
 
-include(Linker/GNU)
+include(Linker/MOLD)
 
-__linker_gnu(Fortran)
+__linker_mold(Fortran)

+ 2 - 2
Modules/Linker/MOLD-HIP.cmake

@@ -1,6 +1,6 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file Copyright.txt or https://cmake.org/licensing for details.
 
-include(Linker/GNU)
+include(Linker/MOLD)
 
-__linker_gnu(HIP)
+__linker_mold(HIP)

+ 2 - 2
Modules/Linker/MOLD-OBJC.cmake

@@ -1,6 +1,6 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file Copyright.txt or https://cmake.org/licensing for details.
 
-include(Linker/GNU)
+include(Linker/MOLD)
 
-__linker_gnu(OBJC)
+__linker_mold(OBJC)

+ 2 - 2
Modules/Linker/MOLD-OBJCXX.cmake

@@ -1,6 +1,6 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file Copyright.txt or https://cmake.org/licensing for details.
 
-include(Linker/GNU)
+include(Linker/MOLD)
 
-__linker_gnu(OBJCXX)
+__linker_mold(OBJCXX)

+ 23 - 0
Modules/Linker/MOLD.cmake

@@ -0,0 +1,23 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple linkers; use include blocker.
+include_guard()
+
+block(SCOPE_FOR POLICIES)
+cmake_policy(SET CMP0054 NEW)
+
+macro(__linker_mold lang)
+  if(CMAKE_EFFECTIVE_SYSTEM_NAME STREQUAL "Apple")
+    include(Linker/AppleClang)
+
+    __linker_appleclang(${lang})
+  else()
+    include(Linker/GNU)
+
+    __linker_gnu(${lang})
+  endif()
+endmacro()
+
+endblock()

+ 6 - 0
Modules/Linker/MSVC-ASM.cmake

@@ -0,0 +1,6 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+include(Linker/MSVC)
+
+__linker_msvc(ASM)

+ 6 - 0
Modules/Linker/MSVC-C.cmake

@@ -0,0 +1,6 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+include(Linker/MSVC)
+
+__linker_msvc(C)

+ 6 - 0
Modules/Linker/MSVC-CUDA.cmake

@@ -0,0 +1,6 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+include(Linker/MSVC)
+
+__linker_msvc(CUDA)

+ 6 - 0
Modules/Linker/MSVC-CXX.cmake

@@ -0,0 +1,6 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+include(Linker/MSVC)
+
+__linker_msvc(CXX)

+ 6 - 0
Modules/Linker/MSVC-Fortran.cmake

@@ -0,0 +1,6 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+include(Linker/MSVC)
+
+__linker_msvc(Fortran)

+ 6 - 0
Modules/Linker/MSVC-HIP.cmake

@@ -0,0 +1,6 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+include(Linker/MSVC)
+
+__linker_msvc(HIP)

+ 12 - 0
Modules/Linker/MSVC.cmake

@@ -0,0 +1,12 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple linkers; use include blocker.
+include_guard()
+
+
+macro(__linker_msvc lang)
+  # Linker warning as error
+  set(CMAKE_${lang}_LINK_OPTIONS_WARNING_AS_ERROR "LINKER:/WX")
+endmacro()

+ 2 - 0
Modules/Linker/Solaris.cmake

@@ -6,4 +6,6 @@
 include_guard()
 
 macro(__linker_solaris lang)
+  # Linker warning as error
+  set(CMAKE_${lang}_LINK_OPTIONS_WARNING_AS_ERROR "LINKER:-z,fatal-warnings")
 endmacro()

+ 6 - 0
Source/cmGlobalGenerator.cxx

@@ -3069,6 +3069,9 @@ void cmGlobalGenerator::AddGlobalTarget_EditCache(
     if (this->GetCMakeInstance()->GetIgnoreCompileWarningAsError()) {
       singleLine.push_back("--compile-no-warning-as-error");
     }
+    if (this->GetCMakeInstance()->GetIgnoreLinkWarningAsError()) {
+      singleLine.push_back("--link-no-warning-as-error");
+    }
     singleLine.push_back("-S$(CMAKE_SOURCE_DIR)");
     singleLine.push_back("-B$(CMAKE_BINARY_DIR)");
     gti.Message = "Running CMake cache editor...";
@@ -3105,6 +3108,9 @@ void cmGlobalGenerator::AddGlobalTarget_RebuildCache(
   if (this->GetCMakeInstance()->GetIgnoreCompileWarningAsError()) {
     singleLine.push_back("--compile-no-warning-as-error");
   }
+  if (this->GetCMakeInstance()->GetIgnoreLinkWarningAsError()) {
+    singleLine.push_back("--link-no-warning-as-error");
+  }
   singleLine.push_back("-S$(CMAKE_SOURCE_DIR)");
   singleLine.push_back("-B$(CMAKE_BINARY_DIR)");
   gti.CommandLines.push_back(std::move(singleLine));

+ 1 - 0
Source/cmGlobalNinjaGenerator.cxx

@@ -1958,6 +1958,7 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
       this->CMakeCmd(), " --regenerate-during-build",
       cm->GetIgnoreCompileWarningAsError() ? " --compile-no-warning-as-error"
                                            : "",
+      cm->GetIgnoreLinkWarningAsError() ? " --link-no-warning-as-error" : "",
       " -S",
       lg->ConvertToOutputFormat(lg->GetSourceDirectory(),
                                 cmOutputConverter::SHELL),

+ 3 - 0
Source/cmGlobalVisualStudio8Generator.cxx

@@ -328,6 +328,9 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget()
     if (cm->GetIgnoreCompileWarningAsError()) {
       commandLines[0].emplace_back("--compile-no-warning-as-error");
     }
+    if (cm->GetIgnoreLinkWarningAsError()) {
+      commandLines[0].emplace_back("--link-no-warning-as-error");
+    }
 
     // Add the rule.  Note that we cannot use the CMakeLists.txt
     // file as the main dependency because it would get

+ 10 - 8
Source/cmGlobalXCodeGenerator.cxx

@@ -777,14 +777,14 @@ void cmGlobalXCodeGenerator::CreateReRunCMakeFile(
   }
 
   makefileStream << ConvertToMakefilePath(checkCache) << ": $(TARGETS)\n";
-  makefileStream << '\t'
-                 << ConvertToMakefilePath(cmSystemTools::GetCMakeCommand())
-                 << " -S" << ConvertToMakefilePath(root->GetSourceDirectory())
-                 << " -B" << ConvertToMakefilePath(root->GetBinaryDirectory())
-                 << (cm->GetIgnoreCompileWarningAsError()
-                       ? " --compile-no-warning-as-error"
-                       : "")
-                 << '\n';
+  makefileStream
+    << '\t' << ConvertToMakefilePath(cmSystemTools::GetCMakeCommand()) << " -S"
+    << ConvertToMakefilePath(root->GetSourceDirectory()) << " -B"
+    << ConvertToMakefilePath(root->GetBinaryDirectory())
+    << (cm->GetIgnoreCompileWarningAsError() ? " --compile-no-warning-as-error"
+                                             : "")
+    << (cm->GetIgnoreLinkWarningAsError() ? " --link-no-warning-as-error" : "")
+    << '\n';
 }
 
 static bool objectIdLessThan(const std::unique_ptr<cmXCodeObject>& l,
@@ -2551,6 +2551,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
   } else {
     this->CurrentLocalGenerator->AppendLinkerTypeFlags(extraLinkOptions, gtgt,
                                                        configName, llang);
+    this->CurrentLocalGenerator->AppendWarningAsErrorLinkerFlags(
+      extraLinkOptions, gtgt, llang);
 
     cmValue targetLinkFlags = gtgt->GetProperty("LINK_FLAGS");
     if (targetLinkFlags) {

+ 29 - 0
Source/cmLocalGenerator.cxx

@@ -1675,6 +1675,7 @@ void cmLocalGenerator::GetTargetFlags(
   this->AppendLinkerTypeFlags(extraLinkFlags, target, config, linkLanguage);
   this->AppendPositionIndependentLinkerFlags(extraLinkFlags, target, config,
                                              linkLanguage);
+  this->AppendWarningAsErrorLinkerFlags(extraLinkFlags, target, linkLanguage);
   this->AppendIPOLinkerFlags(extraLinkFlags, target, config, linkLanguage);
   this->AppendDependencyInfoLinkerFlags(extraLinkFlags, target, config,
                                         linkLanguage);
@@ -3609,6 +3610,34 @@ void cmLocalGenerator::AppendPositionIndependentLinkerFlags(
   }
 }
 
+void cmLocalGenerator::AppendWarningAsErrorLinkerFlags(
+  std::string& flags, cmGeneratorTarget* target, const std::string& lang)
+{
+  if (this->GetCMakeInstance()->GetIgnoreLinkWarningAsError()) {
+    return;
+  }
+
+  switch (target->GetType()) {
+    case cmStateEnums::EXECUTABLE:
+    case cmStateEnums::SHARED_LIBRARY:
+    case cmStateEnums::MODULE_LIBRARY:
+      break;
+    default:
+      return;
+  }
+
+  const auto wError = target->GetProperty("LINK_WARNING_AS_ERROR");
+  const auto wErrorOpts = this->Makefile->GetDefinition(
+    cmStrCat("CMAKE_", lang, "_LINK_OPTIONS_WARNING_AS_ERROR"));
+  if (wError.IsOn() && wErrorOpts.IsSet()) {
+    auto items = cmExpandListWithBacktrace(wErrorOpts, target->GetBacktrace());
+    target->ResolveLinkerWrapper(items, lang);
+    for (const auto& item : items) {
+      this->AppendFlagEscape(flags, item.Value);
+    }
+  }
+}
+
 void cmLocalGenerator::AppendDependencyInfoLinkerFlags(
   std::string& flags, cmGeneratorTarget* target, const std::string& config,
   const std::string& linkLanguage)

+ 3 - 0
Source/cmLocalGenerator.h

@@ -185,6 +185,9 @@ public:
                                             cmGeneratorTarget* target,
                                             const std::string& config,
                                             const std::string& lang);
+  void AppendWarningAsErrorLinkerFlags(std::string& flags,
+                                       cmGeneratorTarget* target,
+                                       const std::string& lang);
   void AppendDependencyInfoLinkerFlags(std::string& flags,
                                        cmGeneratorTarget* target,
                                        const std::string& config,

+ 2 - 0
Source/cmLocalUnixMakefileGenerator3.cxx

@@ -831,6 +831,7 @@ void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsBottom(
       "$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) ",
       cm->GetIgnoreCompileWarningAsError() ? "--compile-no-warning-as-error "
                                            : "",
+      cm->GetIgnoreLinkWarningAsError() ? "--link-no-warning-as-error " : "",
       "--check-build-system ",
       this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL),
       " 0");
@@ -1834,6 +1835,7 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules(
         "$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) ",
         cm->GetIgnoreCompileWarningAsError() ? "--compile-no-warning-as-error "
                                              : "",
+        cm->GetIgnoreLinkWarningAsError() ? "--link-no-warning-as-error " : "",
         "--check-build-system ",
         this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL),
         " 1");

+ 6 - 0
Source/cmLocalVisualStudio7Generator.cxx

@@ -262,6 +262,9 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule()
   if (cm->GetIgnoreCompileWarningAsError()) {
     commandLines[0].emplace_back("--compile-no-warning-as-error");
   }
+  if (cm->GetIgnoreLinkWarningAsError()) {
+    commandLines[0].emplace_back("--link-no-warning-as-error");
+  }
   std::string comment = cmStrCat("Building Custom Rule ", makefileIn);
   auto cc = cm::make_unique<cmCustomCommand>();
   cc->SetOutputs(stampName);
@@ -1007,6 +1010,9 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
   // LINK_OPTIONS are escaped.
   this->AppendCompileOptions(extraLinkOptions, opts);
 
+  this->AppendWarningAsErrorLinkerFlags(extraLinkOptions, target,
+                                        linkLanguage);
+
   Options linkOptions(this, Options::Linker);
   if (this->FortranProject) {
     linkOptions.AddTable(cmLocalVisualStudio7GeneratorFortranLinkFlagTable);

+ 2 - 0
Source/cmMakefileTargetGenerator.cxx

@@ -158,6 +158,8 @@ void cmMakefileTargetGenerator::GetTargetLinkFlags(
     flags, this->GeneratorTarget, this->GetConfigName(), linkLanguage);
   this->LocalGenerator->AppendPositionIndependentLinkerFlags(
     flags, this->GeneratorTarget, this->GetConfigName(), linkLanguage);
+  this->LocalGenerator->AppendWarningAsErrorLinkerFlags(
+    flags, this->GeneratorTarget, linkLanguage);
   this->LocalGenerator->AppendDependencyInfoLinkerFlags(
     flags, this->GeneratorTarget, this->GetConfigName(), linkLanguage);
 }

+ 1 - 0
Source/cmTarget.cxx

@@ -466,6 +466,7 @@ TargetProperty const StaticTargetProperties[] = {
 
   // Linking properties
   { "LINKER_TYPE"_s, IC::CanCompileSources },
+  { "LINK_WARNING_AS_ERROR"_s, IC::CanCompileSources },
   { "ENABLE_EXPORTS"_s, IC::TargetWithSymbolExports },
   { "LINK_LIBRARIES_ONLY_TARGETS"_s, IC::NormalNonImportedTarget },
   { "LINK_LIBRARIES_STRATEGY"_s, IC::NormalNonImportedTarget },

+ 3 - 0
Source/cmVisualStudio10TargetGenerator.cxx

@@ -4448,6 +4448,9 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
   // LINK_OPTIONS are escaped.
   this->LocalGenerator->AppendCompileOptions(flags, opts);
 
+  this->LocalGenerator->AppendWarningAsErrorLinkerFlags(
+    flags, this->GeneratorTarget, linkLanguage);
+
   cmComputeLinkInformation* pcli =
     this->GeneratorTarget->GetLinkInformation(config);
   if (!pcli) {

+ 8 - 0
Source/cmake.cxx

@@ -1244,6 +1244,14 @@ void cmake::SetArgs(const std::vector<std::string>& args)
         state->SetIgnoreCompileWarningAsError(true);
         return true;
       } },
+    CommandArgument{
+      "--link-no-warning-as-error", CommandArgument::Values::Zero,
+      [](std::string const&, cmake* state) -> bool {
+        std::cout << "Ignoring LINK_WARNING_AS_ERROR target property and "
+                     "CMAKE_LINK_WARNING_AS_ERROR variable.\n";
+        state->SetIgnoreLinkWarningAsError(true);
+        return true;
+      } },
     CommandArgument{ "--debugger", CommandArgument::Values::Zero,
                      [](std::string const&, cmake* state) -> bool {
 #ifdef CMake_ENABLE_DEBUGGER

+ 9 - 0
Source/cmake.h

@@ -550,6 +550,14 @@ public:
   {
     this->IgnoreCompileWarningAsError = b;
   }
+  bool GetIgnoreLinkWarningAsError() const
+  {
+    return this->IgnoreLinkWarningAsError;
+  }
+  void SetIgnoreLinkWarningAsError(bool b)
+  {
+    this->IgnoreLinkWarningAsError = b;
+  }
 
   void MarkCliAsUsed(const std::string& variable);
 
@@ -760,6 +768,7 @@ private:
   bool WarnUnusedCli = true;
   bool CheckSystemVars = false;
   bool IgnoreCompileWarningAsError = false;
+  bool IgnoreLinkWarningAsError = false;
   std::map<std::string, bool> UsedCliVariables;
   std::string CMakeEditCommand;
   std::string CXXEnvironment;

+ 4 - 1
Source/cmakemain.cxx

@@ -71,7 +71,7 @@ const cmDocumentationEntry cmDocumentationUsageNote = {
   "Run 'cmake --help' for more information."
 };
 
-const cmDocumentationEntry cmDocumentationOptions[34] = {
+const cmDocumentationEntry cmDocumentationOptions[35] = {
   { "--preset <preset>,--preset=<preset>", "Specify a configure preset." },
   { "--list-presets[=<type>]", "List available presets." },
   { "--workflow [<options>]", "Run a workflow preset." },
@@ -123,6 +123,9 @@ const cmDocumentationEntry cmDocumentationOptions[34] = {
   { "--compile-no-warning-as-error",
     "Ignore COMPILE_WARNING_AS_ERROR property and "
     "CMAKE_COMPILE_WARNING_AS_ERROR variable." },
+  { "--link-no-warning-as-error",
+    "Ignore LINK_WARNING_AS_ERROR property and "
+    "CMAKE_LINK_WARNING_AS_ERROR variable." },
   { "--profiling-format=<fmt>",
     "Output data for profiling CMake scripts. Supported formats: "
     "google-trace" },

+ 6 - 0
Tests/RunCMake/CMakeLists.txt

@@ -506,6 +506,12 @@ add_RunCMake_test(ToolchainFile)
 add_RunCMake_test(find_dependency)
 add_RunCMake_test(CompileDefinitions)
 add_RunCMake_test(CompileWarningAsError -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
+if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|MSVC"
+    OR (CMAKE_SYSTEM_NAME MATCHES "Linux|Windows" AND CMAKE_C_COMPILER_ID MATCHES "Clang|GNU")
+    OR (CMAKE_SYSTEM_NAME STREQUAL "SunOS" AND CMAKE_C_COMPILER_ID STREQUAL "SunPro")
+    OR (CMAKE_SYSTEM_NAME STREQUAL "AIX" AND CMAKE_C_COMPILER_ID STREQUAL "XL"))
+  add_RunCMake_test(LinkWarningAsError)
+endif()
 set_property(TEST RunCMake.CompileWarningAsError APPEND PROPERTY LABELS "CUDA")
 add_RunCMake_test(CompileFeatures -DCMake_NO_C_STANDARD=${CMake_NO_C_STANDARD} -DCMake_NO_CXX_STANDARD=${CMake_NO_CXX_STANDARD})
 add_RunCMake_test(Policy)

+ 3 - 0
Tests/RunCMake/LinkWarningAsError/CMakeLists.txt

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.31...3.32)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)

+ 19 - 0
Tests/RunCMake/LinkWarningAsError/RunCMakeTest.cmake

@@ -0,0 +1,19 @@
+include(RunCMake)
+
+function(run_link_warn test)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build)
+  set(RunCMake_TEST_OUTPUT_MERGE 1)
+  run_cmake_with_options(${test} ${ARGN})
+  set(RunCMake_TEST_NO_CLEAN 1)
+  if(ARGN MATCHES "--link-no-warning-as-error")
+    # Cause the build system to re-run CMake to verify that this option is preserved.
+    run_cmake_command(${test}-Touch ${CMAKE_COMMAND} -E touch_nocreate CMakeCache.txt)
+  endif()
+  run_cmake_command(${test}-Build ${CMAKE_COMMAND} --build . --verbose)
+endfunction()
+
+run_link_warn(WarnErrorOn1)
+run_link_warn(WarnErrorOn2)
+run_link_warn(WarnErrorOff1)
+run_link_warn(WarnErrorOff2)
+run_link_warn(WarnErrorOnIgnore "--link-no-warning-as-error")

+ 20 - 0
Tests/RunCMake/LinkWarningAsError/WarnError-validation.cmake

@@ -0,0 +1,20 @@
+
+set(reference_file "${RunCMake_TEST_BINARY_DIR}/WARNING_AS_ERROR.txt")
+if (NOT EXISTS "${reference_file}")
+  set (RunCMake_TEST_FAILED "${reference_file}: Reference file not found.")
+  return()
+endif()
+file(READ "${reference_file}" linker_WarnError)
+
+if(NOT linker_WarnError STREQUAL "UNDEFINED")
+  if(WARNING_AS_ERROR)
+    # Add regex [^-] to avoid matching of MSVC compiler flag /WX-
+    if(NOT actual_stdout MATCHES "${linker_WarnError}[^-]")
+      set (RunCMake_TEST_FAILED "LINK_WARNING_AS_ERROR: flag is missing.")
+    endif()
+  else()
+    if(actual_stdout MATCHES "${linker_WarnError}[^-]")
+      set (RunCMake_TEST_FAILED "LINK_WARNING_AS_ERROR: flag unexpectedly present.")
+    endif()
+  endif()
+endif()

+ 54 - 0
Tests/RunCMake/LinkWarningAsError/WarnError.cmake

@@ -0,0 +1,54 @@
+
+if(NOT CMAKE_C_LINK_OPTIONS_WARNING_AS_ERROR)
+  set(linker_WarnError "UNDEFINED")
+else()
+  set(cfg_dir)
+  get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+  if(_isMultiConfig)
+    set(cfg_dir /Debug)
+  endif()
+  set(DUMP_EXE "${CMAKE_CURRENT_BINARY_DIR}${cfg_dir}/dump${CMAKE_EXECUTABLE_SUFFIX}")
+
+  add_executable(dump dump.c)
+  set_property(TARGET dump PROPERTY LINK_WARNING_AS_ERROR OFF)
+
+  # ensure no temp file nor response file will be used
+  set(CMAKE_C_USE_RESPONSE_FILE_FOR_LIBRARIES 0)
+  string(REPLACE "${CMAKE_START_TEMP_FILE}" "" CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE}")
+  string(REPLACE "${CMAKE_END_TEMP_FILE}" "" CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE}")
+
+  add_executable(main main.c)
+  if (NOT DEFINED CMAKE_LINK_WARNING_AS_ERROR)
+    set_property(TARGET main PROPERTY LINK_WARNING_AS_ERROR ${link_warning_as_error})
+  endif()
+  # use LAUNCH facility to dump linker command
+  set_property(TARGET main PROPERTY RULE_LAUNCH_LINK "\"${DUMP_EXE}\"")
+
+  add_dependencies(main dump)
+
+
+  # generate reference for WARNING_AS_ERROR flag
+  string(REPLACE "LINKER:" "" linker_WarnError "${CMAKE_C_LINK_OPTIONS_WARNING_AS_ERROR}")
+  if (CMAKE_C_LINKER_WRAPPER_FLAG)
+    set(linker_flag ${CMAKE_C_LINKER_WRAPPER_FLAG})
+    list(GET linker_flag -1 linker_space)
+    if (linker_space STREQUAL " ")
+      list(REMOVE_AT linker_flag -1)
+    else()
+      set(linker_space)
+    endif()
+    list(JOIN linker_flag " " linker_flag)
+    if (CMAKE_C_LINKER_WRAPPER_FLAG_SEP)
+      string(REPLACE "," "${CMAKE_C_LINKER_WRAPPER_FLAG_SEP}" linker_WarnError "${linker_WarnError}")
+      set(linker_WarnError "${linker_flag}${linker_space}${linker_WarnError}")
+    else()
+      set(linker_prefix "${linker_flag}${linker_space}")
+      string(REPLACE "," ";" linker_WarnError "${linker_WarnError}")
+      list(TRANSFORM linker_WarnError PREPEND "${linker_prefix}")
+      list(JOIN linker_WarnError " " linker_WarnError)
+    endif()
+  else()
+    string(REPLACE "," " " linker_WarnError "${linker_WarnError}")
+  endif()
+endif()
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/WARNING_AS_ERROR.txt" "${linker_WarnError}")

+ 4 - 0
Tests/RunCMake/LinkWarningAsError/WarnErrorOff1-Build-check.cmake

@@ -0,0 +1,4 @@
+
+set(WARNING_AS_ERROR OFF)
+
+include("${CMAKE_CURRENT_LIST_DIR}/WarnError-validation.cmake")

+ 5 - 0
Tests/RunCMake/LinkWarningAsError/WarnErrorOff1.cmake

@@ -0,0 +1,5 @@
+enable_language(C)
+
+set(link_warning_as_error OFF)
+
+include(WarnError.cmake)

+ 4 - 0
Tests/RunCMake/LinkWarningAsError/WarnErrorOff2-Build-check.cmake

@@ -0,0 +1,4 @@
+
+set(WARNING_AS_ERROR OFF)
+
+include("${CMAKE_CURRENT_LIST_DIR}/WarnError-validation.cmake")

+ 5 - 0
Tests/RunCMake/LinkWarningAsError/WarnErrorOff2.cmake

@@ -0,0 +1,5 @@
+enable_language(C)
+
+set(CMAKE_LINK_WARNING_AS_ERROR OFF)
+
+include(WarnError.cmake)

+ 4 - 0
Tests/RunCMake/LinkWarningAsError/WarnErrorOn1-Build-check.cmake

@@ -0,0 +1,4 @@
+
+set(WARNING_AS_ERROR ON)
+
+include("${CMAKE_CURRENT_LIST_DIR}/WarnError-validation.cmake")

+ 5 - 0
Tests/RunCMake/LinkWarningAsError/WarnErrorOn1.cmake

@@ -0,0 +1,5 @@
+enable_language(C)
+
+set(link_warning_as_error ON)
+
+include(WarnError.cmake)

+ 4 - 0
Tests/RunCMake/LinkWarningAsError/WarnErrorOn2-Build-check.cmake

@@ -0,0 +1,4 @@
+
+set(WARNING_AS_ERROR ON)
+
+include("${CMAKE_CURRENT_LIST_DIR}/WarnError-validation.cmake")

+ 5 - 0
Tests/RunCMake/LinkWarningAsError/WarnErrorOn2.cmake

@@ -0,0 +1,5 @@
+enable_language(C)
+
+set(CMAKE_LINK_WARNING_AS_ERROR ON)
+
+include(WarnError.cmake)

+ 4 - 0
Tests/RunCMake/LinkWarningAsError/WarnErrorOnIgnore-Build-check.cmake

@@ -0,0 +1,4 @@
+
+set(WARNING_AS_ERROR OFF)
+
+include("${CMAKE_CURRENT_LIST_DIR}/WarnError-validation.cmake")

+ 5 - 0
Tests/RunCMake/LinkWarningAsError/WarnErrorOnIgnore.cmake

@@ -0,0 +1,5 @@
+enable_language(C)
+
+set(link_warning_as_error ON)
+
+include(WarnError.cmake)

+ 13 - 0
Tests/RunCMake/LinkWarningAsError/dump.c

@@ -0,0 +1,13 @@
+
+#include "stdio.h"
+
+int main(int argc, char* argv[])
+{
+  int i;
+
+  for (i = 1; i < argc; i++)
+    printf("%s ", argv[i]);
+  printf("\n");
+
+  return 0;
+}

+ 5 - 0
Tests/RunCMake/LinkWarningAsError/main.c

@@ -0,0 +1,5 @@
+
+int main(void)
+{
+  return 0;
+}