Pārlūkot izejas kodu

Merge topic 'LINK_WARNING_AS_ERROR-extend-capabilities'

b350f95ecf LINK_WARNING_AS_ERROR property: extend capabilities
216c469214 MSVC: Use dash-style flag for LINK_WARNING_AS_ERROR

Acked-by: Kitware Robot <[email protected]>
Tested-by: buildbot <[email protected]>
Merge-request: !10133
Brad King 9 mēneši atpakaļ
vecāks
revīzija
e95fce2849

+ 14 - 0
Help/prop_tgt/LINK_WARNING_AS_ERROR.rst

@@ -8,6 +8,20 @@ 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 takes a :ref:`semicolon-separated-list <CMake Language Lists>` of
+the following values:
+
+* ``LINKER``: treat the linker warnings as errors.
+* ``DRIVER``: treat the compiler warnings as errors when used to drive the link
+  step. See the :prop_tgt:`COMPILE_WARNING_AS_ERROR` target property for more
+  information.
+
+Moreover, for consistency with the :prop_tgt:`COMPILE_WARNING_AS_ERROR` target
+property, a boolean value can be specified:
+
+* ``True`` value: this is equivalent to ``LINKER`` and ``DRIVER`` values.
+* ``False`` value: deactivate this feature for the target.
+
 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>`

+ 1 - 1
Modules/Linker/MSVC.cmake

@@ -8,5 +8,5 @@ include_guard()
 
 macro(__linker_msvc lang)
   # Linker warning as error
-  set(CMAKE_${lang}_LINK_OPTIONS_WARNING_AS_ERROR "LINKER:/WX")
+  set(CMAKE_${lang}_LINK_OPTIONS_WARNING_AS_ERROR "LINKER:-WX")
 endmacro()

+ 47 - 7
Source/cmLocalGenerator.cxx

@@ -3608,14 +3608,54 @@ void cmLocalGenerator::AppendWarningAsErrorLinkerFlags(
   }
 
   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);
+  if (wError.IsOff()) {
+    return;
+  }
+  cmList wErrorOptions;
+  if (wError.IsOn()) {
+    wErrorOptions = { "DRIVER", "LINKER" };
+  } else {
+    wErrorOptions = wError;
+    std::sort(wErrorOptions.begin(), wErrorOptions.end());
+    wErrorOptions.erase(
+      std::unique(wErrorOptions.begin(), wErrorOptions.end()),
+      wErrorOptions.end());
+  }
+
+  auto linkModeIsDriver =
+    this->Makefile->GetDefinition(cmStrCat("CMAKE_", lang, "_LINK_MODE")) ==
+    "DRIVER"_s;
+  std::string errorMessage;
+  for (const auto& option : wErrorOptions) {
+    if (option != "DRIVER"_s && option != "LINKER"_s) {
+      errorMessage += cmStrCat("  ", option, '\n');
+      continue;
+    }
+
+    if (option == "DRIVER"_s && !linkModeIsDriver) {
+      continue;
     }
+
+    const auto wErrorOpts = this->Makefile->GetDefinition(cmStrCat(
+      "CMAKE_", lang, '_', (option == "DRIVER"_s ? "COMPILE" : "LINK"),
+      "_OPTIONS_WARNING_AS_ERROR"));
+    if (wErrorOpts.IsSet()) {
+      auto items =
+        cmExpandListWithBacktrace(wErrorOpts, target->GetBacktrace());
+      if (option == "LINKER"_s) {
+        target->ResolveLinkerWrapper(items, lang);
+      }
+      for (const auto& item : items) {
+        this->AppendFlagEscape(flags, item.Value);
+      }
+    }
+  }
+  if (!errorMessage.empty()) {
+    this->Makefile->GetCMakeInstance()->IssueMessage(
+      MessageType::FATAL_ERROR,
+      cmStrCat(
+        "Erroneous value(s) for 'LINK_WARNING_AS_ERROR' property of target '",
+        target->GetName(), "':\n", errorMessage));
   }
 }
 

+ 2 - 1
Tests/RunCMake/CMakeLists.txt

@@ -511,10 +511,11 @@ 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"
+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"))
+  AND CMAKE_C_COMPILER_LINKER_ID)
   add_RunCMake_test(LinkWarningAsError)
 endif()
 set_property(TEST RunCMake.CompileWarningAsError APPEND PROPERTY LABELS "CUDA")

+ 1 - 0
Tests/RunCMake/LinkWarningAsError/BadValue-result.txt

@@ -0,0 +1 @@
+1

+ 4 - 0
Tests/RunCMake/LinkWarningAsError/BadValue-stderr.txt

@@ -0,0 +1,4 @@
+CMake Error:
+  Erroneous value\(s\) for 'LINK_WARNING_AS_ERROR' property of target 'main':
+
+    FOO

+ 4 - 0
Tests/RunCMake/LinkWarningAsError/BadValue.cmake

@@ -0,0 +1,4 @@
+enable_language(C)
+
+add_executable(main main.c)
+set_property(TARGET main PROPERTY LINK_WARNING_AS_ERROR FOO)

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

@@ -1,5 +1,7 @@
 include(RunCMake)
 
+run_cmake(BadValue)
+
 function(run_link_warn test)
   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build)
   set(RunCMake_TEST_OUTPUT_MERGE 1)
@@ -14,6 +16,8 @@ endfunction()
 
 run_link_warn(WarnErrorOn1)
 run_link_warn(WarnErrorOn2)
+run_link_warn(WarnErrorOn3)
+run_link_warn(WarnErrorOn4)
 run_link_warn(WarnErrorOff1)
 run_link_warn(WarnErrorOff2)
 run_link_warn(WarnErrorOnIgnore "--link-no-warning-as-error")

+ 5 - 6
Tests/RunCMake/LinkWarningAsError/WarnError-validation.cmake

@@ -4,17 +4,16 @@ if (NOT EXISTS "${reference_file}")
   set (RunCMake_TEST_FAILED "${reference_file}: Reference file not found.")
   return()
 endif()
-file(READ "${reference_file}" linker_WarnError)
+file(READ "${reference_file}" WarnErrorFlags)
 
-if(NOT linker_WarnError STREQUAL "UNDEFINED")
+if(NOT WarnErrorFlags STREQUAL "UNDEFINED")
   if(WARNING_AS_ERROR)
-    # Add regex [^-] to avoid matching of MSVC compiler flag /WX-
-    if(NOT actual_stdout MATCHES "${linker_WarnError}[^-]")
+    if(NOT actual_stdout MATCHES "${WarnErrorFlags}")
       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.")
+    if(actual_stdout MATCHES "${WarnErrorFlags}")
+      set (RunCMake_TEST_FAILED "LINK_WARNING_AS_ERROR: flag unexpectedly present: '${WarnErrorFlags}'")
     endif()
   endif()
 endif()

+ 53 - 4
Tests/RunCMake/LinkWarningAsError/WarnError.cmake

@@ -1,6 +1,17 @@
 
-if(NOT CMAKE_C_LINK_OPTIONS_WARNING_AS_ERROR)
-  set(linker_WarnError "UNDEFINED")
+set(linkWarning "${link_warning_as_error}")
+if (DEFINED CMAKE_LINK_WARNING_AS_ERROR)
+  set(linkWarning "${CMAKE_LINK_WARNING_AS_ERROR}")
+endif()
+if (linkWarning STREQUAL "ON")
+  set (linkWarning DRIVER LINKER)
+endif()
+
+if((linkWarning STREQUAL "DRIVER;LINKER" AND NOT CMAKE_C_COMPILE_OPTIONS_WARNING_AS_ERROR
+      AND NOT CMAKE_C_LINK_OPTIONS_WARNING_AS_ERROR)
+    OR (linkWarning STREQUAL "DRIVER" AND NOT CMAKE_C_COMPILE_OPTIONS_WARNING_AS_ERROR)
+    OR (linkWarning STREQUAL "LINKER" AND NOT CMAKE_C_LINK_OPTIONS_WARNING_AS_ERROR))
+  set(WarnErrorFlags "UNDEFINED")
 else()
   set(cfg_dir)
   get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
@@ -26,8 +37,15 @@ else()
 
   add_dependencies(main dump)
 
-
   # generate reference for WARNING_AS_ERROR flag
+  unset(compiler_WarnError)
+  unset(linker_WarnError)
+  unset(WarnErrorFlags)
+  ## DRIVER
+  if (CMAKE_C_LINK_MODE STREQUAL "DRIVER")
+    list(JOIN CMAKE_C_COMPILE_OPTIONS_WARNING_AS_ERROR " " compiler_WarnError)
+  endif()
+  ## LINKER
   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})
@@ -50,5 +68,36 @@ else()
   else()
     string(REPLACE "," " " linker_WarnError "${linker_WarnError}")
   endif()
+
+  # Add regex [^-] to avoid matching of MSVC compiler flag -WX-
+  if(linkWarning STREQUAL "DRIVER;LINKER")
+    set(WarnErrorFlags "${compiler_WarnError}")
+    if (WarnErrorFlags)
+      string(APPEND WarnErrorFlags " ${linker_WarnError}[^-]")
+    else()
+      set(WarnErrorFlags "${linker_WarnError}[^-]")
+    endif()
+  elseif(linkWarning STREQUAL "DRIVER")
+    set(WarnErrorFlags "${compiler_WarnError}[^-]")
+  elseif(linkWarning STREQUAL "LINKER")
+    set(WarnErrorFlags "${linker_WarnError}[^-]")
+  else()
+    # OFF value
+    if(compiler_WarnError AND linker_WarnError)
+        set(WarnErrorFlags "(${compiler_WarnError}[^-]|${linker_WarnError}[^-])+")
+    elseif(compiler_WarnError)
+      set(WarnErrorFlags "${compiler_WarnError}[^-]")
+    elseif(linker_WarnError)
+      set(WarnErrorFlags "${linker_WarnError}[^-]")
+    endif()
+    if(NOT WarnErrorFlags)
+      set(WarnErrorFlags "UNDEFINED")
+    endif()
+  endif()
+endif()
+if(CMAKE_GENERATOR MATCHES "Visual Studio")
+  # replace '-' with '/' for options
+  string(REGEX REPLACE "-([A-Z]+)" "[-/]\\1" WarnErrorFlags "${WarnErrorFlags}")
 endif()
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/WARNING_AS_ERROR.txt" "${linker_WarnError}")
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/WARNING_AS_ERROR.txt" "${WarnErrorFlags}")

+ 4 - 0
Tests/RunCMake/LinkWarningAsError/WarnErrorOn3-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/WarnErrorOn3.cmake

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

+ 4 - 0
Tests/RunCMake/LinkWarningAsError/WarnErrorOn4-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/WarnErrorOn4.cmake

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