LINK_WARNING_AS_ERROR property: extend capabilities

Fixes: #26536
This commit is contained in:
Marc Chevrier 2024-12-21 17:32:51 +01:00
parent 216c469214
commit b350f95ecf
13 changed files with 152 additions and 18 deletions

View File

@ -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>`

View File

@ -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));
}
}

View File

@ -508,10 +508,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")

View File

@ -0,0 +1 @@
1

View File

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

View File

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

View File

@ -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")

View File

@ -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()

View File

@ -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()
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/WARNING_AS_ERROR.txt" "${linker_WarnError}")
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" "${WarnErrorFlags}")

View File

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

View File

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

View File

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

View File

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