Merge topic 'vs-UseDebugLibraries'

b814641444 VS: Add [CMAKE_]VS_USE_DEBUG_LIBRARIES options to control UseDebugLibraries
67de5b7b82 VS: Suppress MSBuild default settings affected by UseDebugLibraries
0ae372daee VS: Factor out common MS tool configuration

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !9270
This commit is contained in:
Brad King
2024-02-20 15:37:18 +00:00
committed by Kitware Robot
22 changed files with 242 additions and 22 deletions
+1
View File
@@ -445,6 +445,7 @@ Properties on Targets
/prop_tgt/VS_SDK_REFERENCES
/prop_tgt/VS_SOLUTION_DEPLOY
/prop_tgt/VS_SOURCE_SETTINGS_tool
/prop_tgt/VS_USE_DEBUG_LIBRARIES
/prop_tgt/VS_USER_PROPS
/prop_tgt/VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION
/prop_tgt/VS_WINRT_COMPONENT
+1
View File
@@ -137,6 +137,7 @@ Variables that Provide Information
/variable/CMAKE_VS_TARGET_FRAMEWORK_IDENTIFIER
/variable/CMAKE_VS_TARGET_FRAMEWORK_TARGETS_VERSION
/variable/CMAKE_VS_TARGET_FRAMEWORK_VERSION
/variable/CMAKE_VS_USE_DEBUG_LIBRARIES
/variable/CMAKE_VS_VERSION_BUILD_NUMBER
/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION
/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION
@@ -0,0 +1,18 @@
Indicate to :ref:`Visual Studio Generators` what configurations are considered
debug configurations. This controls the ``UseDebugLibraries`` setting in
each configuration of a ``.vcxproj`` file.
The "Use Debug Libraries" setting in Visual Studio projects, despite its
specific-sounding name, is a general-purpose indicator of what configurations
are considered debug configurations. In standalone projects, this may affect
MSBuild's default selection of MSVC runtime library, optimization flags,
runtime checks, and similar settings. In CMake projects those settings are
typically generated explicitly based on the project's specification, e.g.,
the MSVC runtime library is controlled by |MSVC_RUNTIME_LIBRARY|. However,
the ``UseDebugLibraries`` indicator is useful for reference by both humans
and tools, and may also affect the behavior of platform-specific SDKs.
Set |VS_USE_DEBUG_LIBRARIES| to a true or false value to indicate whether
each configuration is considered a debug configuration. The value may also
be the empty string (``""``) in which case no ``UseDebugLibraries`` will be
added explicitly by CMake, and MSBuild will use its default value, ``false``.
+27
View File
@@ -0,0 +1,27 @@
VS_USE_DEBUG_LIBRARIES
----------------------
.. versionadded:: 3.30
.. |VS_USE_DEBUG_LIBRARIES| replace:: ``VS_USE_DEBUG_LIBRARIES``
.. |MSVC_RUNTIME_LIBRARY| replace:: :prop_tgt:`MSVC_RUNTIME_LIBRARY`
.. include:: VS_USE_DEBUG_LIBRARIES-PURPOSE.txt
Use :manual:`generator expressions <cmake-generator-expressions(7)>`
for per-configuration specification. For example, the code:
.. code-block:: cmake
add_executable(foo foo.c)
set_property(TARGET foo PROPERTY
VS_USE_DEBUG_LIBRARIES "$<CONFIG:Debug,Custom>")
indicates that target ``foo`` considers its "Debug" and "Custom"
configurations to be debug configurations, and its other configurations
to be non-debug configurations.
The property is initialized from the value of the
:variable:`CMAKE_VS_USE_DEBUG_LIBRARIES` variable, if it is set.
If the property is not set, then CMake does not generate any
``UseDebugLibraries`` indicator.
@@ -0,0 +1,6 @@
vs-UseDebugLibraries
--------------------
* The :variable:`CMAKE_VS_USE_DEBUG_LIBRARIES` variable and corresponding
:prop_tgt:`VS_USE_DEBUG_LIBRARIES` target property were added to explicitly
control ``UseDebugLibraries`` indicators in ``.vcxproj`` files.
@@ -0,0 +1,28 @@
CMAKE_VS_USE_DEBUG_LIBRARIES
----------------------------
.. versionadded:: 3.30
.. |VS_USE_DEBUG_LIBRARIES| replace:: ``CMAKE_VS_USE_DEBUG_LIBRARIES``
.. |MSVC_RUNTIME_LIBRARY| replace:: :variable:`CMAKE_MSVC_RUNTIME_LIBRARY`
.. include:: ../prop_tgt/VS_USE_DEBUG_LIBRARIES-PURPOSE.txt
Use :manual:`generator expressions <cmake-generator-expressions(7)>`
for per-configuration specification. For example, the code:
.. code-block:: cmake
set(CMAKE_VS_USE_DEBUG_LIBRARIES "$<CONFIG:Debug,Custom>")
indicates that all following targets consider their "Debug" and "Custom"
configurations to be debug configurations, and their other configurations
to be non-debug configurations.
This variable is used to initialize the :prop_tgt:`VS_USE_DEBUG_LIBRARIES`
property on all targets as they are created. It is also propagated by
calls to the :command:`try_compile` command into its test project.
If this variable is not set then the :prop_tgt:`VS_USE_DEBUG_LIBRARIES`
property will not be set automatically. If that property is not set
then CMake does not generate any ``UseDebugLibraries`` indicator.
+1
View File
@@ -1151,6 +1151,7 @@ cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode(
vars.emplace("CMAKE_WATCOM_RUNTIME_LIBRARY"_s);
vars.emplace("CMAKE_MSVC_DEBUG_INFORMATION_FORMAT"_s);
vars.emplace("CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS"_s);
vars.emplace("CMAKE_VS_USE_DEBUG_LIBRARIES"_s);
if (cmValue varListStr = this->Makefile->GetDefinition(
kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES)) {
+1
View File
@@ -404,6 +404,7 @@ TargetProperty const StaticTargetProperties[] = {
{ "VS_DEBUGGER_COMMAND_ARGUMENTS"_s, IC::ExecutableTarget },
{ "VS_DEBUGGER_ENVIRONMENT"_s, IC::ExecutableTarget },
{ "VS_DEBUGGER_WORKING_DIRECTORY"_s, IC::ExecutableTarget },
{ "VS_USE_DEBUG_LIBRARIES"_s, IC::NonImportedTarget },
// ---- OpenWatcom
{ "WATCOM_RUNTIME_LIBRARY"_s, IC::CanCompileSources },
// -- Language
+56 -16
View File
@@ -1512,7 +1512,6 @@ void cmVisualStudio10TargetGenerator::WriteCEDebugProjectConfigurationValues(
void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues(
Elem& e1, std::string const& config)
{
cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
cmValue mfcFlag = this->Makefile->GetDefinition("CMAKE_MFC_FLAG");
if (mfcFlag) {
std::string const mfcFlagValue =
@@ -1543,12 +1542,9 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues(
} else {
e1.Element("CharacterSet", "MultiByte");
}
if (cmValue projectToolsetOverride =
this->GeneratorTarget->GetProperty("VS_PLATFORM_TOOLSET")) {
e1.Element("PlatformToolset", *projectToolsetOverride);
} else if (const char* toolset = gg->GetPlatformToolset()) {
e1.Element("PlatformToolset", toolset);
}
this->WriteMSToolConfigurationValuesCommon(e1, config);
if (this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT") ||
this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_EXTENSIONS")) {
e1.Element("WindowsAppContainer", "true");
@@ -1579,8 +1575,6 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesManaged(
return;
}
cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
Options& o = *(this->ClOptions[config]);
if (o.IsDebug()) {
@@ -1598,12 +1592,7 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesManaged(
o.RemoveFlag("Platform");
}
if (cmValue projectToolsetOverride =
this->GeneratorTarget->GetProperty("VS_PLATFORM_TOOLSET")) {
e1.Element("PlatformToolset", *projectToolsetOverride);
} else if (const char* toolset = gg->GetPlatformToolset()) {
e1.Element("PlatformToolset", toolset);
}
this->WriteMSToolConfigurationValuesCommon(e1, config);
std::string postfixName =
cmStrCat(cmSystemTools::UpperCase(config), "_POSTFIX");
@@ -1623,6 +1612,37 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesManaged(
oh.OutputFlagMap();
}
void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesCommon(
Elem& e1, std::string const& config)
{
cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
if (cmValue projectToolsetOverride =
this->GeneratorTarget->GetProperty("VS_PLATFORM_TOOLSET")) {
e1.Element("PlatformToolset", *projectToolsetOverride);
} else if (const char* toolset = gg->GetPlatformToolset()) {
e1.Element("PlatformToolset", toolset);
}
cm::optional<bool> maybeUseDebugLibraries;
if (cmValue useDebugLibrariesProp =
this->GeneratorTarget->GetProperty("VS_USE_DEBUG_LIBRARIES")) {
// The project explicitly specified a value for this target.
// An empty string suppresses generation of the setting altogether.
std::string const useDebugLibraries = cmGeneratorExpression::Evaluate(
*useDebugLibrariesProp, this->LocalGenerator, config);
if (!useDebugLibraries.empty()) {
maybeUseDebugLibraries = cmIsOn(useDebugLibraries);
}
}
if (maybeUseDebugLibraries) {
if (*maybeUseDebugLibraries) {
e1.Element("UseDebugLibraries", "true");
} else {
e1.Element("UseDebugLibraries", "false");
}
}
}
//----------------------------------------------------------------------------
void cmVisualStudio10TargetGenerator::WriteNsightTegraConfigurationValues(
Elem& e1, std::string const&)
@@ -3154,7 +3174,10 @@ void cmVisualStudio10TargetGenerator::OutputLinkIncremental(
Options& linkOptions = *(this->LinkOptions[configName]);
const std::string cond = this->CalcCondition(configName);
if (this->IPOEnabledConfigurations.count(configName) == 0) {
if (this->IPOEnabledConfigurations.count(configName) > 0) {
// Suppress LinkIncremental in favor of WholeProgramOptimization.
e1.WritePlatformConfigTag("LinkIncremental", cond, "");
} else {
const char* incremental = linkOptions.GetFlag("LinkIncremental");
e1.WritePlatformConfigTag("LinkIncremental", cond,
(incremental ? incremental : "true"));
@@ -3499,6 +3522,23 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
clOptions.RemoveFlag("CompileAs");
}
if (this->ProjectType == VsProjectType::vcxproj && this->MSTools) {
// Suppress Microsoft.Cl.Common.props default settings for which the
// project specifies no flags. Do not let UseDebugLibraries affect them.
if (!clOptions.HasFlag("BasicRuntimeChecks")) {
clOptions.AddFlag("BasicRuntimeChecks", "Default");
}
if (!clOptions.HasFlag("Optimization")) {
clOptions.AddFlag("Optimization", "");
}
if (!clOptions.HasFlag("RuntimeLibrary")) {
clOptions.AddFlag("RuntimeLibrary", "");
}
if (!clOptions.HasFlag("SupportJustMyCode")) {
clOptions.AddFlag("SupportJustMyCode", "");
}
}
this->ClOptions[configName] = std::move(pOptions);
return true;
}
+2
View File
@@ -72,6 +72,8 @@ private:
void WriteCEDebugProjectConfigurationValues(Elem& e0);
void WriteMSToolConfigurationValuesManaged(Elem& e1,
std::string const& config);
void WriteMSToolConfigurationValuesCommon(Elem& e1,
std::string const& config);
void WriteHeaderSource(Elem& e1, cmSourceFile const* sf,
ConfigToSettings const& toolSettings);
void WriteExtraSource(Elem& e1, cmSourceFile const* sf,
-4
View File
@@ -57,10 +57,6 @@ function(verify lang src)
# VS 2005 and above default to multi-threaded.
target_compile_definitions(empty-${lang} PRIVATE VERIFY_MT)
endif()
if(CMAKE_GENERATOR MATCHES "Visual Studio ([^9]|9[0-9])")
# VS 2010 and above have a different default runtime library for projects than 'cl'.
target_compile_definitions(empty-${lang} PRIVATE VERIFY_DLL)
endif()
endif()
endfunction()
+1
View File
@@ -731,6 +731,7 @@ if("${CMAKE_GENERATOR}" MATCHES "Visual Studio ([^9]|9[0-9])")
-DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
-DCMAKE_C_COMPILER_VERSION=${CMAKE_C_COMPILER_VERSION}
)
add_RunCMake_test(VS10ProjectUseDebugLibraries)
if( vs12 AND wince )
add_RunCMake_test( VS10ProjectWinCE "-DRunCMake_GENERATOR_PLATFORM=${wince_sdk}")
endif()
@@ -9,7 +9,7 @@ macro(RuntimeLibrary_check tgt rtl_expect)
file(STRINGS "${vcProjectFile}" lines)
foreach(line IN LISTS lines)
if(line MATCHES "^ *<RuntimeLibrary>([^<>]+)</RuntimeLibrary>")
if(line MATCHES "^ *<RuntimeLibrary>([^<>]*)</RuntimeLibrary>")
set(rtl_actual "${CMAKE_MATCH_1}")
if(NOT "${rtl_actual}" STREQUAL "${rtl_expect}")
set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj has RuntimeLibrary '${rtl_actual}', not '${rtl_expect}'.")
@@ -9,7 +9,7 @@ macro(VsJustMyCode_check tgt jmc_expect)
file(STRINGS "${vcProjectFile}" lines)
foreach(line IN LISTS lines)
if(line MATCHES "^ *<SupportJustMyCode>([^<>]+)</SupportJustMyCode>")
if(line MATCHES "^ *<SupportJustMyCode>([^<>]*)</SupportJustMyCode>")
set(jmc_actual "${CMAKE_MATCH_1}")
if(NOT "${jmc_actual}" STREQUAL "${jmc_expect}")
set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj has <SupportJustMyCode> '${jmc_actual}', not '${jmc_expect}'.")
@@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 3.29)
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)
@@ -0,0 +1,8 @@
include(${CMAKE_CURRENT_LIST_DIR}/check-common.cmake)
UseDebugLibraries_check(default "" "")
UseDebugLibraries_check(defaultCLR "" "")
UseDebugLibraries_check(defaultUtil "" "")
UseDebugLibraries_check(defaultRTL "" "")
UseDebugLibraries_check(ALL_BUILD "" "")
UseDebugLibraries_check(ZERO_CHECK "" "")
@@ -0,0 +1,10 @@
set(CMAKE_CONFIGURATION_TYPES Debug Release)
enable_language(CXX)
# Test several generator code paths covering different target types.
add_library(default empty.cxx)
add_library(defaultCLR empty.cxx)
set_property(TARGET defaultCLR PROPERTY COMMON_LANGUAGE_RUNTIME "")
add_library(defaultRTL empty.cxx)
set_property(TARGET defaultRTL PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreadedDLL")
add_custom_target(defaultUtil)
@@ -0,0 +1,10 @@
include(${CMAKE_CURRENT_LIST_DIR}/check-common.cmake)
UseDebugLibraries_check(empty "" "")
UseDebugLibraries_check(emptyCLR "" "")
UseDebugLibraries_check(emptyUtil "" "")
UseDebugLibraries_check(genex "true" "false")
UseDebugLibraries_check(genexCLR "true" "false")
UseDebugLibraries_check(genexUtil "true" "false")
UseDebugLibraries_check(ALL_BUILD "false" "false")
UseDebugLibraries_check(ZERO_CHECK "false" "false")
@@ -0,0 +1,20 @@
set(CMAKE_CONFIGURATION_TYPES Debug Release)
enable_language(CXX)
# An empty string suppresses generation of the setting.
set(CMAKE_VS_USE_DEBUG_LIBRARIES "")
add_library(empty empty.cxx)
add_library(emptyCLR empty.cxx)
set_property(TARGET emptyCLR PROPERTY COMMON_LANGUAGE_RUNTIME "")
add_custom_target(emptyUtil)
# A generator expression can encode per-config values.
set(CMAKE_VS_USE_DEBUG_LIBRARIES "$<CONFIG:Debug>")
add_library(genex empty.cxx)
add_library(genexCLR empty.cxx)
set_property(TARGET genexCLR PROPERTY COMMON_LANGUAGE_RUNTIME "")
add_custom_target(genexUtil)
# The last setting in the top-level directcory affects
# the builtin targets like ALL_BUILD and ZERO_CHECK.
set(CMAKE_VS_USE_DEBUG_LIBRARIES 0)
@@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.29)
include(RunCMake)
run_cmake(Default)
run_cmake(Explicit)
@@ -0,0 +1,42 @@
cmake_policy(SET CMP0140 NEW)
function(UseDebugLibraries_check tgt udl_expect_debug udl_expect_release)
set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/${tgt}.vcxproj")
if(NOT EXISTS "${vcProjectFile}")
set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not exist.")
return()
endif()
set(have_udl_debug 0)
set(have_udl_release 0)
set(inConfig "")
file(STRINGS "${vcProjectFile}" lines)
foreach(line IN LISTS lines)
if(line MATCHES [[^ *<PropertyGroup Condition="'\$\(Configuration\)\|\$\(Platform\)'=='([^"|]+)\|[^"]+" Label="Configuration">.*$]])
string(TOLOWER "${CMAKE_MATCH_1}" inConfig)
elseif(inConfig)
if(line MATCHES "^ *</PropertyGroup>.*$")
set(inConfig "")
elseif(line MATCHES "^ *<UseDebugLibraries>([^<>]+)</UseDebugLibraries>")
set(udl_actual "${CMAKE_MATCH_1}")
set(have_udl_${inConfig} 1)
if (NOT "${udl_expect_${inConfig}}" STREQUAL "")
if(NOT "${udl_actual}" STREQUAL "${udl_expect_${inConfig}}")
string(APPEND RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj has ${inConfig} UseDebugLibraries '${udl_actual}', not '${udl_expect_${inConfig}}'.\n")
endif()
else()
string(APPEND RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj has ${inConfig} UseDebugLibraries '${udl_actual}', but should not have one.\n")
endif()
unset(udl_actual)
endif()
endif()
endforeach()
if(NOT have_udl_debug AND NOT "${udl_expect_debug}" STREQUAL "")
string(APPEND RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not have a debug UseDebugLibraries field, but should have one.\n")
endif()
if(NOT have_udl_release AND NOT "${udl_expect_release}" STREQUAL "")
string(APPEND RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not have a release UseDebugLibraries field, but should have one.\n")
endif()
return(PROPAGATE RunCMake_TEST_FAILED)
endfunction()