From 0e96a20478948c18a677b129c2a1de31261bbcb0 Mon Sep 17 00:00:00 2001 From: Glen Chung Date: Thu, 25 Aug 2022 09:37:12 -0700 Subject: MSVC: Add abstraction for debug information format Replace our hard-coded default for `/Zi` with a first-class abstraction to select the debug information format an enumeration of logical names. We've long hesitated to do this because the idea of "debug information format" touches on related concepts on several platforms. Avoid that scope creep by simply defining an abstraction that applies only when targeting the MSVC ABI on Windows. Removing the old default flag requires a policy because existing projects may rely on string processing to edit them and choose a runtime library under the old behavior. Add policy CMP0141 to provide compatibility. Fixes: #10189 --- Help/command/try_compile.rst | 5 ++ Help/manual/cmake-policies.7.rst | 1 + Help/manual/cmake-properties.7.rst | 1 + Help/manual/cmake-variables.7.rst | 1 + Help/policy/CMP0141.rst | 55 ++++++++++++++++++++++ .../MSVC_DEBUG_INFORMATION_FORMAT-VALUES.txt | 15 ++++++ Help/prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT.rst | 33 +++++++++++++ .../dev/MsvcDebugInformationFormatAbstraction.rst | 7 +++ .../CMAKE_MSVC_DEBUG_INFORMATION_FORMAT.rst | 36 ++++++++++++++ Modules/Platform/Windows-Clang.cmake | 24 +++++++++- Modules/Platform/Windows-Intel-Fortran.cmake | 2 + Modules/Platform/Windows-IntelLLVM-Fortran.cmake | 2 + Modules/Platform/Windows-MSVC.cmake | 21 ++++++++- Modules/Platform/Windows-NVIDIA-CUDA.cmake | 14 +++++- Source/cmCoreTryCompile.cxx | 11 +++++ Source/cmLocalGenerator.cxx | 35 ++++++++++++++ Source/cmPolicies.h | 6 ++- Source/cmTarget.cxx | 1 + Tests/RunCMake/CMakeLists.txt | 1 + .../CMP0141-NEW-result.txt | 1 + .../CMP0141-NEW-stderr.txt | 5 ++ .../MSVCDebugInformationFormat/CMP0141-NEW.cmake | 2 + .../CMP0141-NoEffect.cmake | 4 ++ .../MSVCDebugInformationFormat/CMP0141-OLD.cmake | 2 + .../MSVCDebugInformationFormat/CMP0141-WARN.cmake | 2 + .../CMP0141-common.cmake | 31 ++++++++++++ .../MSVCDebugInformationFormat/CMakeLists.txt | 3 ++ .../MSVCDebugInformationFormat/RunCMakeTest.cmake | 6 +++ .../RunCMake/MSVCDebugInformationFormat/empty.cxx | 0 .../VS10Project/DebugInformationFormat-check.cmake | 46 ++++++++++++++++++ .../VS10Project/DebugInformationFormat.cmake | 24 ++++++++++ Tests/RunCMake/VS10Project/RunCMakeTest.cmake | 1 + 32 files changed, 391 insertions(+), 7 deletions(-) create mode 100644 Help/policy/CMP0141.rst create mode 100644 Help/prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT-VALUES.txt create mode 100644 Help/prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT.rst create mode 100644 Help/release/dev/MsvcDebugInformationFormatAbstraction.rst create mode 100644 Help/variable/CMAKE_MSVC_DEBUG_INFORMATION_FORMAT.rst create mode 100644 Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-NEW-result.txt create mode 100644 Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-NEW-stderr.txt create mode 100644 Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-NEW.cmake create mode 100644 Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-NoEffect.cmake create mode 100644 Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-OLD.cmake create mode 100644 Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-WARN.cmake create mode 100644 Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-common.cmake create mode 100644 Tests/RunCMake/MSVCDebugInformationFormat/CMakeLists.txt create mode 100644 Tests/RunCMake/MSVCDebugInformationFormat/RunCMakeTest.cmake create mode 100644 Tests/RunCMake/MSVCDebugInformationFormat/empty.cxx create mode 100644 Tests/RunCMake/VS10Project/DebugInformationFormat-check.cmake create mode 100644 Tests/RunCMake/VS10Project/DebugInformationFormat.cmake diff --git a/Help/command/try_compile.rst b/Help/command/try_compile.rst index 73dd9d3..710fd21 100644 --- a/Help/command/try_compile.rst +++ b/Help/command/try_compile.rst @@ -244,3 +244,8 @@ a build configuration. .. versionadded:: 3.24 The :variable:`CMAKE_TRY_COMPILE_NO_PLATFORM_VARIABLES` variable may be set to disable passing platform variables into the test project. + +.. versionadded:: 3.25 + If :policy:`CMP0141` is set to ``NEW``, one can use + :variable:`CMAKE_MSVC_DEBUG_INFORMATION_FORMAT` to specify MSVC debug + information format. diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst index a1133b9..c0c37d1 100644 --- a/Help/manual/cmake-policies.7.rst +++ b/Help/manual/cmake-policies.7.rst @@ -58,6 +58,7 @@ Policies Introduced by CMake 3.25 .. toctree:: :maxdepth: 1 + CMP0141: MSVC debug information format flags are selected by an abstraction. CMP0140: The return() command checks its arguments. Policies Introduced by CMake 3.24 diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index d98f7cc..09c3c88 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -340,6 +340,7 @@ Properties on Targets /prop_tgt/MACOSX_RPATH /prop_tgt/MANUALLY_ADDED_DEPENDENCIES /prop_tgt/MAP_IMPORTED_CONFIG_CONFIG + /prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT /prop_tgt/MSVC_RUNTIME_LIBRARY /prop_tgt/NAME /prop_tgt/NO_SONAME diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index ad6bfbc..02706d8 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -486,6 +486,7 @@ Variables that Control the Build /variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG_INIT /variable/CMAKE_MODULE_LINKER_FLAGS_INIT /variable/CMAKE_MSVCIDE_RUN_PATH + /variable/CMAKE_MSVC_DEBUG_INFORMATION_FORMAT /variable/CMAKE_MSVC_RUNTIME_LIBRARY /variable/CMAKE_NINJA_OUTPUT_PATH_PREFIX /variable/CMAKE_NO_BUILTIN_CHRPATH diff --git a/Help/policy/CMP0141.rst b/Help/policy/CMP0141.rst new file mode 100644 index 0000000..51fa5fd --- /dev/null +++ b/Help/policy/CMP0141.rst @@ -0,0 +1,55 @@ +CMP0141 +------- + +.. versionadded:: 3.25 + +MSVC debug information format flags are selected by an abstraction. + +Compilers targeting the MSVC ABI have flags to select the debug information +format. Debug information format selection typically varies with build +configuration. + +In CMake 3.24 and below, debug information format flags are added to +the default :variable:`CMAKE__FLAGS_` cache entries by CMake +automatically. This allows users to edit their cache entries to adjust the +flags. However, the presence of such default flags is problematic for +projects that want to choose a different runtime library programmatically. +In particular, it requires string editing of the +:variable:`CMAKE__FLAGS_` variables with knowledge of the +CMake builtin defaults so they can be replaced. + +CMake 3.25 and above prefer to leave the debug information format flags +out of the default :variable:`CMAKE__FLAGS_` values and instead +offer a first-class abstraction. The +:variable:`CMAKE_MSVC_DEBUG_INFORMATION_FORMAT` variable and +:prop_tgt:`MSVC_DEBUG_INFORMATION_FORMAT` target property may be set to +select the MSVC debug information format. If they are not set, CMake +enables debug information in debug configurations using the default value +``$<$:ProgramDatabase>``, if supported by the +compiler, and otherwise ``$<$:Embedded>``. + +This policy provides compatibility with projects that have not been updated +to be aware of the abstraction. The policy setting takes effect as of the +first :command:`project` or :command:`enable_language` command that enables +a language whose compiler targets the MSVC ABI. + +.. note:: + + Once the policy has taken effect at the top of a project, that choice + will be used throughout the tree. In projects that have nested projects + in subdirectories, be sure to confirm if everything is working with the + selected policy behavior. + +The ``OLD`` behavior for this policy is to place MSVC debug information +format flags in the default :variable:`CMAKE__FLAGS_` cache +entries and ignore the :variable:`CMAKE_MSVC_DEBUG_INFORMATION_FORMAT` +abstraction. The ``NEW`` behavior for this policy is to *not* place MSVC +debug information format flags flags in the default cache entries and use +the abstraction instead. + +This policy was introduced in CMake version 3.25. Use the +:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly. +Unlike many policies, CMake version |release| does *not* warn +when this policy is not set and simply uses ``OLD`` behavior. + +.. include:: DEPRECATED.txt diff --git a/Help/prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT-VALUES.txt b/Help/prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT-VALUES.txt new file mode 100644 index 0000000..9a68460 --- /dev/null +++ b/Help/prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT-VALUES.txt @@ -0,0 +1,15 @@ +``Embedded`` + Compile with ``-Z7`` or equivalent flag(s) to produce object files + with full symbolic debugging information. +``ProgramDatabase`` + Compile with ``-Zi`` or equivalent flag(s) to produce a program + database that contains all the symbolic debugging information. +``EditAndContinue`` + Compile with ``-ZI`` or equivalent flag(s) to produce a program + database that supports the Edit and Continue feature. + +The value is ignored on non-MSVC compilers but an unsupported value will +be rejected as an error when using a compiler targeting the MSVC ABI. + +The value may also be the empty string (``""``) in which case no debug +information format flag will be added explicitly by CMake. diff --git a/Help/prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT.rst b/Help/prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT.rst new file mode 100644 index 0000000..2314cff --- /dev/null +++ b/Help/prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT.rst @@ -0,0 +1,33 @@ +MSVC_DEBUG_INFORMATION_FORMAT +----------------------------- + +.. versionadded:: 3.25 + +Select debug information format targeting the MSVC ABI. + +The allowed values are: + +.. include:: MSVC_DEBUG_INFORMATION_FORMAT-VALUES.txt + +Use :manual:`generator expressions ` to +support per-configuration specification. For example, the code: + +.. code-block:: cmake + + add_executable(foo foo.c) + set_property(TARGET foo PROPERTY + MSVC_DEBUG_INFORMATION_FORMAT "$<$:ProgramDatabase>") + +selects for the target ``foo`` the program database debug information format +for the Debug configuration. + +If this property is not set, CMake selects a debug information format using +the default value ``$<$:ProgramDatabase>``, if +supported by the compiler, and otherwise +``$<$:Embedded>``. + +.. note:: + + This property has effect only when policy :policy:`CMP0141` is set to ``NEW`` + prior to the first :command:`project` or :command:`enable_language` command + that enables a language using a compiler targeting the MSVC ABI. diff --git a/Help/release/dev/MsvcDebugInformationFormatAbstraction.rst b/Help/release/dev/MsvcDebugInformationFormatAbstraction.rst new file mode 100644 index 0000000..d0c077c --- /dev/null +++ b/Help/release/dev/MsvcDebugInformationFormatAbstraction.rst @@ -0,0 +1,7 @@ +MsvcDebugInformationFormatAbstraction +------------------------------------- + +* The :variable:`CMAKE_MSVC_DEBUG_INFORMATION_FORMAT` variable and + :prop_tgt:`MSVC_DEBUG_INFORMATION_FORMAT` target property were introduced + to select the debug information format for compilers targeting the MSVC ABI. + See policy :policy:`CMP0141`. diff --git a/Help/variable/CMAKE_MSVC_DEBUG_INFORMATION_FORMAT.rst b/Help/variable/CMAKE_MSVC_DEBUG_INFORMATION_FORMAT.rst new file mode 100644 index 0000000..80df8fc --- /dev/null +++ b/Help/variable/CMAKE_MSVC_DEBUG_INFORMATION_FORMAT.rst @@ -0,0 +1,36 @@ +CMAKE_MSVC_DEBUG_INFORMATION_FORMAT +----------------------------------- + +.. versionadded:: 3.25 + +Select the MSVC debug information format targeting the MSVC ABI. +This variable is used to initialize the +:prop_tgt:`MSVC_DEBUG_INFORMATION_FORMAT` property on all targets as they are +created. It is also propagated by calls to the :command:`try_compile` command +into the test project. + +The allowed values are: + +.. include:: ../prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT-VALUES.txt + +Use :manual:`generator expressions ` to +support per-configuration specification. For example, the code: + +.. code-block:: cmake + + set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<$:ProgramDatabase>") + +selects for all following targets the program database debug information format +for the Debug configuration. + +If this variable is not set, the :prop_tgt:`MSVC_DEBUG_INFORMATION_FORMAT` +target property will not be set automatically. If that property is not set, +CMake selects a debug information format using the default value +``$<$:ProgramDatabase>``, if supported by the +compiler, and otherwise ``$<$:Embedded>``. + +.. note:: + + This variable has effect only when policy :policy:`CMP0141` is set to ``NEW`` + prior to the first :command:`project` or :command:`enable_language` command + that enables a language using a compiler targeting the MSVC ABI. diff --git a/Modules/Platform/Windows-Clang.cmake b/Modules/Platform/Windows-Clang.cmake index 918c7de..5edcb61 100644 --- a/Modules/Platform/Windows-Clang.cmake +++ b/Modules/Platform/Windows-Clang.cmake @@ -96,10 +96,20 @@ macro(__windows_compiler_clang_gnu lang) set(_RTL_FLAGS " -D_DLL -D_MT -Xclang --dependent-lib=msvcrt") endif() - string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -g -Xclang -gcodeview -O0${_RTL_FLAGS_DEBUG}") + if(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT) + set(_DBG_FLAGS "") + else() + set(_DBG_FLAGS " -g -Xclang -gcodeview") + endif() + + string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -O0${_DBG_FLAGS}${_RTL_FLAGS_DEBUG}") string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -Os -DNDEBUG${_RTL_FLAGS}") string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O3 -DNDEBUG${_RTL_FLAGS}") - string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -g -DNDEBUG -Xclang -gcodeview${_RTL_FLAGS}") + string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -DNDEBUG${_DBG_FLAGS}${_RTL_FLAGS}") + + set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_Embedded -g -Xclang -gcodeview) + #set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_ProgramDatabase) # not supported by Clang + #set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_EditAndContinue) # not supported by Clang endif() set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-isystem ") set(CMAKE_${lang}_LINKER_SUPPORTS_PDB ON) @@ -109,6 +119,7 @@ macro(__windows_compiler_clang_gnu lang) set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Xclang -include-pch -Xclang -Xclang -include -Xclang ) set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH -Xclang -emit-pch -Xclang -include -Xclang -x ${__pch_header_${lang}}) + unset(_DBG_FLAGS) unset(_RTL_FLAGS) unset(_RTL_FLAGS_DEBUG) string(TOLOWER "${CMAKE_BUILD_TYPE}" BUILD_TYPE_LOWER) @@ -190,6 +201,7 @@ if("x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC" macro(__windows_compiler_clang_base lang) set(_COMPILE_${lang} "${_COMPILE_${lang}_MSVC}") __windows_compiler_msvc(${lang}) + unset(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_EditAndContinue) # -ZI not supported by Clang set(CMAKE_${lang}_COMPILE_OPTIONS_WARNING_AS_ERROR "-WX") set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-imsvc") endmacro() @@ -202,6 +214,14 @@ if("x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC" endif() unset(__WINDOWS_CLANG_CMP0091) + cmake_policy(GET CMP0141 __WINDOWS_MSVC_CMP0141) + if(__WINDOWS_MSVC_CMP0141 STREQUAL "NEW") + set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT "$<$:Embedded>") + else() + set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT "") + endif() + unset(__WINDOWS_MSVC_CMP0141) + set(CMAKE_BUILD_TYPE_INIT Debug) __enable_llvm_rc_preprocessing("" "-x c") diff --git a/Modules/Platform/Windows-Intel-Fortran.cmake b/Modules/Platform/Windows-Intel-Fortran.cmake index e3804fb..c9b70d5 100644 --- a/Modules/Platform/Windows-Intel-Fortran.cmake +++ b/Modules/Platform/Windows-Intel-Fortran.cmake @@ -33,6 +33,8 @@ set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded -th set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL -threads -libs:dll) set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug -threads -libs:static -dbglibs) set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -threads -libs:dll -dbglibs) +set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_Embedded -Z7) +set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_ProgramDatabase -Zi) # Intel Fortran for Windows supports single-threaded RTL but it is # not implemented by the Visual Studio integration. diff --git a/Modules/Platform/Windows-IntelLLVM-Fortran.cmake b/Modules/Platform/Windows-IntelLLVM-Fortran.cmake index 06d0a00..202ba23 100644 --- a/Modules/Platform/Windows-IntelLLVM-Fortran.cmake +++ b/Modules/Platform/Windows-IntelLLVM-Fortran.cmake @@ -33,6 +33,8 @@ set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded -th set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL -threads -libs:dll) set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug -threads -libs:static -dbglibs) set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -threads -libs:dll -dbglibs) +set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_Embedded -Z7) +set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_ProgramDatabase -Zi) # Intel Fortran for Windows supports single-threaded RTL but it is # not implemented by the Visual Studio integration. diff --git a/Modules/Platform/Windows-MSVC.cmake b/Modules/Platform/Windows-MSVC.cmake index e74ec9e..8e96bf4 100644 --- a/Modules/Platform/Windows-MSVC.cmake +++ b/Modules/Platform/Windows-MSVC.cmake @@ -331,6 +331,13 @@ else() endif() unset(__WINDOWS_MSVC_CMP0091) +cmake_policy(GET CMP0141 __WINDOWS_MSVC_CMP0141) +if(__WINDOWS_MSVC_CMP0141 STREQUAL "NEW") + set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT "$<$:ProgramDatabase>") +else() + set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT "") +endif() +unset(__WINDOWS_MSVC_CMP0141) # Features for LINK_LIBRARY generator expression if(MSVC_VERSION GREATER "1900") @@ -441,6 +448,12 @@ macro(__windows_compiler_msvc lang) endif() unset(_cmp0092) + if(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT) + set(_Zi "") + else() + set(_Zi " /Zi") + endif() + if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "v[0-9]+_clang_.*") # note: MSVC 14 2015 Update 1 sets -fno-ms-compatibility by default, but this does not allow one to compile many projects # that include MS's own headers. CMake itself is affected project too. @@ -451,20 +464,24 @@ macro(__windows_compiler_msvc lang) string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT "${_MD} -DNDEBUG") # TODO: Add '-Os' once VS generator maps it properly for Clang else() string(APPEND CMAKE_${lang}_FLAGS_INIT " ${_PLATFORM_DEFINES}${_PLATFORM_DEFINES_${lang}} /D_WINDOWS${_W3}${_FLAGS_${lang}}") - string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT "${_MDd} /Zi /Ob0 /Od ${_RTC1}") + string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT "${_MDd}${_Zi} /Ob0 /Od ${_RTC1}") string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT "${_MD} /O2 /Ob2 /DNDEBUG") - string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT "${_MD} /Zi /O2 /Ob1 /DNDEBUG") + string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT "${_MD}${_Zi} /O2 /Ob1 /DNDEBUG") string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT "${_MD} /O1 /Ob1 /DNDEBUG") endif() unset(_Wall) unset(_W3) unset(_MDd) unset(_MD) + unset(_Zi) set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded -MT) set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL -MD) set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug -MTd) set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -MDd) + set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_Embedded -Z7) + set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_ProgramDatabase -Zi) + set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_EditAndContinue -ZI) endif() set(CMAKE_${lang}_LINKER_SUPPORTS_PDB ON) diff --git a/Modules/Platform/Windows-NVIDIA-CUDA.cmake b/Modules/Platform/Windows-NVIDIA-CUDA.cmake index 6c1699b..326e715 100644 --- a/Modules/Platform/Windows-NVIDIA-CUDA.cmake +++ b/Modules/Platform/Windows-NVIDIA-CUDA.cmake @@ -57,6 +57,12 @@ else() set(_MD "-MD ") endif() +if(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT) + set(_Zi "") +else() + set(_Zi " -Zi") +endif() + cmake_policy(GET CMP0092 _cmp0092) if(_cmp0092 STREQUAL "NEW") set(_W3 "") @@ -66,11 +72,12 @@ endif() unset(_cmp0092) string(APPEND CMAKE_CUDA_FLAGS_INIT " ${PLATFORM_DEFINES_CUDA} -D_WINDOWS -Xcompiler=\"${_W3}${_FLAGS_CXX}\"") -string(APPEND CMAKE_CUDA_FLAGS_DEBUG_INIT " -Xcompiler=\"${_MDd}-Zi -Ob0 -Od ${_RTC1}\"") +string(APPEND CMAKE_CUDA_FLAGS_DEBUG_INIT " -Xcompiler=\"${_MDd}${_Zi} -Ob0 -Od ${_RTC1}\"") string(APPEND CMAKE_CUDA_FLAGS_RELEASE_INIT " -Xcompiler=\"${_MD}-O2 -Ob2\" -DNDEBUG") -string(APPEND CMAKE_CUDA_FLAGS_RELWITHDEBINFO_INIT " -Xcompiler=\"${_MD}-Zi -O2 -Ob1\" -DNDEBUG") +string(APPEND CMAKE_CUDA_FLAGS_RELWITHDEBINFO_INIT " -Xcompiler=\"${_MD}${_Zi} -O2 -Ob1\" -DNDEBUG") string(APPEND CMAKE_CUDA_FLAGS_MINSIZEREL_INIT " -Xcompiler=\"${_MD}-O1 -Ob1\" -DNDEBUG") unset(_W3) +unset(_Zi) unset(_MDd) unset(_MD) @@ -78,6 +85,9 @@ set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded -Xcomp set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL -Xcompiler=-MD) set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug -Xcompiler=-MTd) set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -Xcompiler=-MDd) +set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_Embedded -Xcompiler=-Z7) +set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_ProgramDatabase -Xcompiler=-Zi) +set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_EditAndContinue -Xcompiler=-ZI) set(CMAKE_CUDA_STANDARD_LIBRARIES_INIT "${CMAKE_C_STANDARD_LIBRARIES_INIT}") diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index 0a6c359..85ffd3b 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -94,6 +94,8 @@ std::string const kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES = std::string const kCMAKE_WARN_DEPRECATED = "CMAKE_WARN_DEPRECATED"; std::string const kCMAKE_WATCOM_RUNTIME_LIBRARY_DEFAULT = "CMAKE_WATCOM_RUNTIME_LIBRARY_DEFAULT"; +std::string const kCMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT = + "CMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT"; /* GHS Multi platform variables */ std::set const ghs_platform_vars{ @@ -497,6 +499,14 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments, *cmp0123 == "NEW"_s ? "NEW" : "OLD"); } + /* Set MSVC debug information format policy to match our selection. */ + if (cmValue msvcDebugInformationFormatDefault = + this->Makefile->GetDefinition( + kCMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT)) { + fprintf(fout, "cmake_policy(SET CMP0141 %s)\n", + !msvcDebugInformationFormatDefault->empty() ? "NEW" : "OLD"); + } + /* Set cache/normal variable policy to match outer project. It may affect toolchain files. */ if (this->Makefile->GetPolicyStatus(cmPolicies::CMP0126) != @@ -849,6 +859,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments, vars.insert(kCMAKE_WARN_DEPRECATED); vars.emplace("CMAKE_MSVC_RUNTIME_LIBRARY"_s); vars.emplace("CMAKE_WATCOM_RUNTIME_LIBRARY"_s); + vars.emplace("CMAKE_MSVC_DEBUG_INFORMATION_FORMAT"_s); if (cmValue varListStr = this->Makefile->GetDefinition( kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES)) { diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index b44d2a0..defcba3 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -2041,6 +2041,41 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags, } } } + + // Add MSVC debug information format flags. This is activated by the presence + // of a default selection whether or not it is overridden by a property. + cmValue msvcDebugInformationFormatDefault = this->Makefile->GetDefinition( + "CMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT"); + if (cmNonempty(msvcDebugInformationFormatDefault)) { + cmValue msvcDebugInformationFormatValue = + target->GetProperty("MSVC_DEBUG_INFORMATION_FORMAT"); + if (!msvcDebugInformationFormatValue) { + msvcDebugInformationFormatValue = msvcDebugInformationFormatDefault; + } + std::string const msvcDebugInformationFormat = + cmGeneratorExpression::Evaluate(*msvcDebugInformationFormatValue, this, + config, target); + if (!msvcDebugInformationFormat.empty()) { + if (cmValue msvcDebugInformationFormatOptions = + this->Makefile->GetDefinition( + cmStrCat("CMAKE_", lang, + "_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_", + msvcDebugInformationFormat))) { + this->AppendCompileOptions(flags, *msvcDebugInformationFormatOptions); + } else if ((this->Makefile->GetSafeDefinition( + cmStrCat("CMAKE_", lang, "_COMPILER_ID")) == "MSVC"_s || + this->Makefile->GetSafeDefinition( + cmStrCat("CMAKE_", lang, "_SIMULATE_ID")) == "MSVC"_s) && + !cmSystemTools::GetErrorOccurredFlag()) { + // The compiler uses the MSVC ABI so it needs a known runtime library. + this->IssueMessage(MessageType::FATAL_ERROR, + cmStrCat("MSVC_DEBUG_INFORMATION_FORMAT value '", + msvcDebugInformationFormat, + "' not known for this ", lang, + " compiler.")); + } + } + } } void cmLocalGenerator::AddLanguageFlagsForLinking( diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index fdda31e..ea25814 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -423,7 +423,11 @@ class cmMakefile; "The if() command supports path comparisons using PATH_EQUAL operator.", \ 3, 24, 0, cmPolicies::WARN) \ SELECT(POLICY, CMP0140, "The return() command checks its arguments.", 3, \ - 25, 0, cmPolicies::WARN) + 25, 0, cmPolicies::WARN) \ + SELECT( \ + POLICY, CMP0141, \ + "MSVC debug information format flags are selected by an abstraction.", 3, \ + 25, 0, cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) #define CM_FOR_EACH_POLICY_ID(POLICY) \ diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index eb3feaa..df2bdba 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -563,6 +563,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("AUTORCC_OPTIONS"); initProp("LINK_DEPENDS_NO_SHARED"); initProp("LINK_INTERFACE_LIBRARIES"); + initProp("MSVC_DEBUG_INFORMATION_FORMAT"); initProp("MSVC_RUNTIME_LIBRARY"); initProp("WATCOM_RUNTIME_LIBRARY"); initProp("WIN32_EXECUTABLE"); diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 42ff450..db4200b 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -359,6 +359,7 @@ if(MSVC) add_RunCMake_test(MSVCRuntimeLibrary) add_RunCMake_test(MSVCRuntimeTypeInfo) add_RunCMake_test(MSVCWarningFlags) + add_RunCMake_test(MSVCDebugInformationFormat) endif() if(XCODE_VERSION) set(ObjectLibrary_ARGS -DXCODE_VERSION=${XCODE_VERSION}) diff --git a/Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-NEW-result.txt b/Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-NEW-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-NEW-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-NEW-stderr.txt b/Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-NEW-stderr.txt new file mode 100644 index 0000000..fb61d4b --- /dev/null +++ b/Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-NEW-stderr.txt @@ -0,0 +1,5 @@ +^CMake Error in CMakeLists.txt: + MSVC_DEBUG_INFORMATION_FORMAT value 'BogusValue' not known for this (C|CXX) + compiler. ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-NEW.cmake b/Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-NEW.cmake new file mode 100644 index 0000000..165ea38 --- /dev/null +++ b/Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-NEW.cmake @@ -0,0 +1,2 @@ +cmake_policy(SET CMP0141 NEW) +include(CMP0141-common.cmake) diff --git a/Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-NoEffect.cmake b/Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-NoEffect.cmake new file mode 100644 index 0000000..82754a9 --- /dev/null +++ b/Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-NoEffect.cmake @@ -0,0 +1,4 @@ +include(CMP0141-common.cmake) + +# Setting this policy after enable_language command has no effect. +cmake_policy(SET CMP0141 NEW) diff --git a/Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-OLD.cmake b/Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-OLD.cmake new file mode 100644 index 0000000..7bbe586 --- /dev/null +++ b/Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-OLD.cmake @@ -0,0 +1,2 @@ +cmake_policy(SET CMP0141 OLD) +include(CMP0141-common.cmake) diff --git a/Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-WARN.cmake b/Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-WARN.cmake new file mode 100644 index 0000000..912112a --- /dev/null +++ b/Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-WARN.cmake @@ -0,0 +1,2 @@ + +include(CMP0141-common.cmake) diff --git a/Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-common.cmake b/Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-common.cmake new file mode 100644 index 0000000..8e43a25 --- /dev/null +++ b/Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-common.cmake @@ -0,0 +1,31 @@ +enable_language(CXX) + +cmake_policy(GET CMP0141 cmp0141) +if(cmp0141 STREQUAL "NEW") + if(NOT CMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT) + message(SEND_ERROR "CMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT not set under NEW behavior") + endif() +else() + if(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT) + message(SEND_ERROR "CMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT is set under OLD behavior") + endif() +endif() + +if(cmp0141 STREQUAL "NEW") + if(CMAKE_CXX_FLAGS_DEBUG MATCHES "[/-]Zi( |$)") + message(SEND_ERROR "CMAKE_CXX_FLAGS_DEBUG has -Zi flags under NEW behavior.") + endif() + if(CMAKE_CXX_FLAGS_RELWITHDEBINFO MATCHES "[/-]Zi( |$)") + message(SEND_ERROR "CMAKE_CXX_FLAGS_RELWITHDEBINFO has -Zi flags under NEW behavior.") + endif() +else() + if(NOT (CMAKE_CXX_FLAGS_DEBUG MATCHES "[/-]Zi( |$)")) + message(SEND_ERROR "CMAKE_CXX_FLAGS_DEBUG does not have -Zi flags under OLD behavior.") + endif() + if(NOT (CMAKE_CXX_FLAGS_RELWITHDEBINFO MATCHES "[/-]Zi( |$)")) + message(SEND_ERROR "CMAKE_CXX_FLAGS_RELWITHDEBINFO does not have -Zi flags under OLD behavior.") + endif() +endif() + +set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT BogusValue) +add_library(foo empty.cxx) diff --git a/Tests/RunCMake/MSVCDebugInformationFormat/CMakeLists.txt b/Tests/RunCMake/MSVCDebugInformationFormat/CMakeLists.txt new file mode 100644 index 0000000..aba1016 --- /dev/null +++ b/Tests/RunCMake/MSVCDebugInformationFormat/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.24) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/MSVCDebugInformationFormat/RunCMakeTest.cmake b/Tests/RunCMake/MSVCDebugInformationFormat/RunCMakeTest.cmake new file mode 100644 index 0000000..f678acf --- /dev/null +++ b/Tests/RunCMake/MSVCDebugInformationFormat/RunCMakeTest.cmake @@ -0,0 +1,6 @@ +include(RunCMake) + +run_cmake(CMP0141-WARN) +run_cmake(CMP0141-OLD) +run_cmake(CMP0141-NEW) +run_cmake(CMP0141-NoEffect) diff --git a/Tests/RunCMake/MSVCDebugInformationFormat/empty.cxx b/Tests/RunCMake/MSVCDebugInformationFormat/empty.cxx new file mode 100644 index 0000000..e69de29 diff --git a/Tests/RunCMake/VS10Project/DebugInformationFormat-check.cmake b/Tests/RunCMake/VS10Project/DebugInformationFormat-check.cmake new file mode 100644 index 0000000..46af974 --- /dev/null +++ b/Tests/RunCMake/VS10Project/DebugInformationFormat-check.cmake @@ -0,0 +1,46 @@ +macro(DebugInformationFormat_check tgt Debug_expect Release_expect MinSizeRel_expect RelWithDebInfo_expect) + 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(Debug_actual "") + set(Release_actual "") + set(MinSizeRel_actual "") + set(RelWithDebInfo_actual "") + + file(STRINGS "${vcProjectFile}" lines) + foreach(line IN LISTS lines) + if(line MATCHES "^ *]+)\\|[A-Za-z0-9_]+'\">") + set(Configuration "${CMAKE_MATCH_1}") + endif() + if(line MATCHES "^ *([^<>]+)") + set(${Configuration}_actual "${CMAKE_MATCH_1}") + endif() + endforeach() + + if (NOT "${Debug_actual}" STREQUAL "${Debug_expect}") + set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj Debug Configuration has DebugInformationFormat '${Debug_actual}', not '${Debug_expect}'.") + endif() + if (NOT "${Release_actual}" STREQUAL "${Release_expect}") + set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj Release Configuration has DebugInformationFormat '${Release_actual}', not '${Release_expect}'.") + endif() + if (NOT "${MinSizeRel_actual}" STREQUAL "${MinSizeRel_expect}") + set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj MinSizeRel Configuration has DebugInformationFormat '${MinSizeRel_actual}', not '${MinSizeRel_expect}'.") + endif() + if (NOT "${RelWithDebInfo_actual}" STREQUAL "${RelWithDebInfo_expect}") + set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj RelWithDebInfo Configuration has DebugInformationFormat '${RelWithDebInfo_actual}', not '${RelWithDebInfo_expect}'.") + endif() +endmacro() + +DebugInformationFormat_check(default-C ProgramDatabase "" "" ProgramDatabase) +DebugInformationFormat_check(default-CXX ProgramDatabase "" "" ProgramDatabase) +DebugInformationFormat_check(empty-C "" "" "" "") +DebugInformationFormat_check(empty-CXX "" "" "" "") +DebugInformationFormat_check(Embedded-C OldStyle OldStyle OldStyle OldStyle) +DebugInformationFormat_check(Embedded-CXX OldStyle OldStyle OldStyle OldStyle) +DebugInformationFormat_check(ProgramDatabase-C ProgramDatabase ProgramDatabase ProgramDatabase ProgramDatabase) +DebugInformationFormat_check(ProgramDatabase-CXX ProgramDatabase ProgramDatabase ProgramDatabase ProgramDatabase) +DebugInformationFormat_check(EditAndContinue-C EditAndContinue EditAndContinue EditAndContinue EditAndContinue) +DebugInformationFormat_check(EditAndContinue-CXX EditAndContinue EditAndContinue EditAndContinue EditAndContinue) diff --git a/Tests/RunCMake/VS10Project/DebugInformationFormat.cmake b/Tests/RunCMake/VS10Project/DebugInformationFormat.cmake new file mode 100644 index 0000000..f670166 --- /dev/null +++ b/Tests/RunCMake/VS10Project/DebugInformationFormat.cmake @@ -0,0 +1,24 @@ +set(CMAKE_CONFIGURATION_TYPES Debug Release MinSizeRel RelWithDebInfo) +cmake_policy(SET CMP0141 NEW) +enable_language(C) +enable_language(CXX) + +add_library(default-C empty.c) +add_library(default-CXX empty.cxx) + +set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "") +add_library(empty-C empty.c) +add_library(empty-CXX empty.cxx) + +set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "Embedded") +add_library(Embedded-C empty.c) +add_library(Embedded-CXX empty.cxx) + +set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "ProgramDatabase") +add_library(ProgramDatabase-C empty.c) +add_library(ProgramDatabase-CXX empty.cxx) + +add_library(EditAndContinue-C empty.c) +set_property(TARGET EditAndContinue-C PROPERTY MSVC_DEBUG_INFORMATION_FORMAT "EditAndContinue") +add_library(EditAndContinue-CXX empty.cxx) +set_property(TARGET EditAndContinue-CXX PROPERTY MSVC_DEBUG_INFORMATION_FORMAT "EditAndContinue") diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake index e540b9f..f027e94 100644 --- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake +++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake @@ -88,3 +88,4 @@ run_cmake(VsDotnetStartupObject) run_cmake(VsDotnetTargetFramework) run_cmake(VsDotnetTargetFrameworkVersion) run_cmake(VsNoCompileBatching) +run_cmake(DebugInformationFormat) -- cgit v0.12