Browse Source

Merge topic 'MsvcDebugInformationFormatAbstraction'

a858466aac MSVC: Add test for debug information format
0e96a20478 MSVC: Add abstraction for debug information format
d4c8111da4 Clang/Windows: Clarify name of internal runtime library flags variables

Acked-by: Kitware Robot <[email protected]>
Merge-request: !7606
Brad King 3 years ago
parent
commit
c3e68020d6
43 changed files with 546 additions and 15 deletions
  1. 5 0
      Help/command/try_compile.rst
  2. 1 0
      Help/manual/cmake-policies.7.rst
  3. 1 0
      Help/manual/cmake-properties.7.rst
  4. 1 0
      Help/manual/cmake-variables.7.rst
  5. 55 0
      Help/policy/CMP0141.rst
  6. 15 0
      Help/prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT-VALUES.txt
  7. 33 0
      Help/prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT.rst
  8. 7 0
      Help/release/dev/MsvcDebugInformationFormatAbstraction.rst
  9. 36 0
      Help/variable/CMAKE_MSVC_DEBUG_INFORMATION_FORMAT.rst
  10. 30 10
      Modules/Platform/Windows-Clang.cmake
  11. 2 0
      Modules/Platform/Windows-Intel-Fortran.cmake
  12. 2 0
      Modules/Platform/Windows-IntelLLVM-Fortran.cmake
  13. 19 2
      Modules/Platform/Windows-MSVC.cmake
  14. 12 2
      Modules/Platform/Windows-NVIDIA-CUDA.cmake
  15. 11 0
      Source/cmCoreTryCompile.cxx
  16. 35 0
      Source/cmLocalGenerator.cxx
  17. 5 1
      Source/cmPolicies.h
  18. 1 0
      Source/cmTarget.cxx
  19. 9 0
      Tests/CMakeLists.txt
  20. 81 0
      Tests/MSVCDebugInformationFormat/CMakeLists.txt
  21. 7 0
      Tests/MSVCDebugInformationFormat/override-C.cmake
  22. 6 0
      Tests/MSVCDebugInformationFormat/override-CUDA.cmake
  23. 7 0
      Tests/MSVCDebugInformationFormat/override-CXX.cmake
  24. 4 0
      Tests/MSVCDebugInformationFormat/override-Fortran.cmake
  25. 1 0
      Tests/MSVCDebugInformationFormat/verify.F90
  26. 1 0
      Tests/MSVCDebugInformationFormat/verify.c
  27. 1 0
      Tests/MSVCDebugInformationFormat/verify.cu
  28. 1 0
      Tests/MSVCDebugInformationFormat/verify.cxx
  29. 29 0
      Tests/MSVCDebugInformationFormat/verify.h
  30. 1 0
      Tests/RunCMake/CMakeLists.txt
  31. 1 0
      Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-NEW-result.txt
  32. 5 0
      Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-NEW-stderr.txt
  33. 2 0
      Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-NEW.cmake
  34. 4 0
      Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-NoEffect.cmake
  35. 2 0
      Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-OLD.cmake
  36. 2 0
      Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-WARN.cmake
  37. 31 0
      Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-common.cmake
  38. 3 0
      Tests/RunCMake/MSVCDebugInformationFormat/CMakeLists.txt
  39. 6 0
      Tests/RunCMake/MSVCDebugInformationFormat/RunCMakeTest.cmake
  40. 0 0
      Tests/RunCMake/MSVCDebugInformationFormat/empty.cxx
  41. 46 0
      Tests/RunCMake/VS10Project/DebugInformationFormat-check.cmake
  42. 24 0
      Tests/RunCMake/VS10Project/DebugInformationFormat.cmake
  43. 1 0
      Tests/RunCMake/VS10Project/RunCMakeTest.cmake

+ 5 - 0
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.

+ 1 - 0
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. </policy/CMP0141>
    CMP0140: The return() command checks its arguments. </policy/CMP0140>
 
 Policies Introduced by CMake 3.24

+ 1 - 0
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

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

@@ -484,6 +484,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

+ 55 - 0
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_<LANG>_FLAGS_<CONFIG>` 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_<LANG>_FLAGS_<CONFIG>` 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_<LANG>_FLAGS_<CONFIG>` 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
+``$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>``, if supported by the
+compiler, and otherwise ``$<$<CONFIG:Debug,RelWithDebInfo>: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_<LANG>_FLAGS_<CONFIG>` 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

+ 15 - 0
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.

+ 33 - 0
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 <cmake-generator-expressions(7)>` 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 "$<$<CONFIG:Debug,RelWithDebInfo>: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 ``$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>``, if
+supported by the compiler, and otherwise
+``$<$<CONFIG:Debug,RelWithDebInfo>: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.

+ 7 - 0
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`.

+ 36 - 0
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 <cmake-generator-expressions(7)>` to
+support per-configuration specification.  For example, the code:
+
+.. code-block:: cmake
+
+  set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<$<CONFIG:Debug,RelWithDebInfo>: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
+``$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>``, if supported by the
+compiler, and otherwise ``$<$<CONFIG:Debug,RelWithDebInfo>: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.

+ 30 - 10
Modules/Platform/Windows-Clang.cmake

@@ -89,17 +89,27 @@ macro(__windows_compiler_clang_gnu lang)
     set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -D_DEBUG -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd)
 
     if(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)
-      set(__ADDED_FLAGS "")
-      set(__ADDED_FLAGS_DEBUG "")
+      set(_RTL_FLAGS "")
+      set(_RTL_FLAGS_DEBUG "")
     else()
-      set(__ADDED_FLAGS_DEBUG "-D_DEBUG -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd")
-      set(__ADDED_FLAGS "-D_DLL -D_MT -Xclang --dependent-lib=msvcrt")
+      set(_RTL_FLAGS_DEBUG " -D_DEBUG -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd")
+      set(_RTL_FLAGS " -D_DLL -D_MT -Xclang --dependent-lib=msvcrt")
     endif()
 
-    string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -g -Xclang -gcodeview -O0 ${__ADDED_FLAGS_DEBUG}")
-    string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -Os -DNDEBUG ${__ADDED_FLAGS}")
-    string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O3 -DNDEBUG ${__ADDED_FLAGS}")
-    string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -g -DNDEBUG -Xclang -gcodeview ${__ADDED_FLAGS}")
+    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 -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,8 +119,9 @@ macro(__windows_compiler_clang_gnu lang)
   set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Xclang -include-pch -Xclang <PCH_FILE> -Xclang -include -Xclang <PCH_HEADER>)
   set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH -Xclang -emit-pch -Xclang -include -Xclang <PCH_HEADER> -x ${__pch_header_${lang}})
 
-  unset(__ADDED_FLAGS)
-  unset(__ADDED_FLAGS_DEBUG)
+  unset(_DBG_FLAGS)
+  unset(_RTL_FLAGS)
+  unset(_RTL_FLAGS_DEBUG)
   string(TOLOWER "${CMAKE_BUILD_TYPE}" BUILD_TYPE_LOWER)
   set(CMAKE_${lang}_STANDARD_LIBRARIES_INIT "-lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 -loldnames")
 
@@ -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 "$<$<CONFIG:Debug,RelWithDebInfo>: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")

+ 2 - 0
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.

+ 2 - 0
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.

+ 19 - 2
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 "$<$<CONFIG:Debug,RelWithDebInfo>: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)
 

+ 12 - 2
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}")
 

+ 11 - 0
Source/cmCoreTryCompile.cxx

@@ -95,6 +95,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<std::string> const ghs_platform_vars{
@@ -498,6 +500,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) !=
@@ -861,6 +871,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)) {

+ 35 - 0
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(

+ 5 - 1
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)                                         \

+ 1 - 0
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");

+ 9 - 0
Tests/CMakeLists.txt

@@ -2080,6 +2080,15 @@ if(BUILD_TESTING)
     if(NOT CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_C_COMPILER_ID STREQUAL "IntelLLVM")
       ADD_TEST_MACRO(PrecompiledHeader foo)
     endif()
+
+    set(MSVCDebugInformationFormat_BUILD_OPTIONS -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
+    if(CMAKE_Fortran_COMPILER)
+      list(APPEND MSVCDebugInformationFormat_BUILD_OPTIONS -DCMake_TEST_Fortran=1)
+    endif()
+    ADD_TEST_MACRO(MSVCDebugInformationFormat)
+    set_property(TEST MSVCDebugInformationFormat APPEND
+      PROPERTY LABELS "CUDA")
+
     set(MSVCRuntimeLibrary_BUILD_OPTIONS -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
     ADD_TEST_MACRO(MSVCRuntimeLibrary)
     set_property(TEST MSVCRuntimeLibrary APPEND

+ 81 - 0
Tests/MSVCDebugInformationFormat/CMakeLists.txt

@@ -0,0 +1,81 @@
+cmake_minimum_required(VERSION 3.24)
+cmake_policy(SET CMP0141 NEW)
+
+# The debug information format flags do not change preprocessor definitions,
+# so override our table of flags to artificially add a definition we can check.
+set(CMAKE_USER_MAKE_RULES_OVERRIDE_C ${CMAKE_CURRENT_SOURCE_DIR}/override-C.cmake)
+set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX ${CMAKE_CURRENT_SOURCE_DIR}/override-CXX.cmake)
+set(CMAKE_USER_MAKE_RULES_OVERRIDE_CUDA ${CMAKE_CURRENT_SOURCE_DIR}/override-CUDA.cmake)
+set(CMAKE_USER_MAKE_RULES_OVERRIDE_Fortran ${CMAKE_CURRENT_SOURCE_DIR}/override-Fortran.cmake)
+
+project(MSVCDebugInformationFormat)
+if(CMake_TEST_CUDA)
+  enable_language(CUDA)
+endif()
+if(CMake_TEST_Fortran)
+  enable_language(Fortran)
+endif()
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+
+if("${CMAKE_C_COMPILER_ID};${CMAKE_C_SIMULATE_ID};${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "Clang;MSVC;GNU")
+  set(verify_default VERIFY_Z7)
+  set(NO_COMPILER_PDB 1)
+elseif("${CMAKE_C_COMPILER_ID};${CMAKE_C_SIMULATE_ID};${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "Clang;MSVC;MSVC")
+  set(verify_default VERIFY_Zi)
+  set(NO_EDIT_AND_CONTINUE 1)
+else()
+  set(verify_default VERIFY_Zi)
+endif()
+
+set(verify_def_Embedded        -DVERIFY_Z7)
+set(verify_def_ProgramDatabase -DVERIFY_Zi)
+set(verify_def_EditAndContinue -DVERIFY_ZI)
+
+function(verify_combination format lang src)
+  # Test that try_compile builds with this debug format.
+  set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "${format}")
+  set(CMAKE_TRY_COMPILE_CONFIGURATION "Debug")
+  set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
+  try_compile(${format}_COMPILES
+    ${CMAKE_CURRENT_BINARY_DIR}/try_compile/${format}
+    ${CMAKE_CURRENT_SOURCE_DIR}/${src}
+    COMPILE_DEFINITIONS ${verify_def_${format}}
+    CMAKE_FLAGS -DINCLUDE_DIRECTORIES=${CMAKE_CURRENT_SOURCE_DIR}
+    OUTPUT_VARIABLE ${format}_OUTPUT
+    )
+  if(${format}_COMPILES)
+    message(STATUS "try_compile ${lang} with ${format} worked")
+  else()
+    string(REPLACE "\n" "\n  " ${format}_OUTPUT "  ${${format}_OUTPUT}")
+    message(SEND_ERROR "try_compile ${lang} with ${format} failed:\n${${format}_OUTPUT}")
+  endif()
+
+  # Test that targets build with this debug format.
+  set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<$<BOOL:$<TARGET_PROPERTY:BOOL_TRUE>>:${format}>$<$<BOOL:$<TARGET_PROPERTY:BOOL_FALSE>>:BadContent>")
+  add_library(${format}-${lang} ${src})
+  set_property(TARGET ${format}-${lang} PROPERTY BOOL_TRUE TRUE)
+  target_compile_definitions(${format}-${lang} PRIVATE ${verify_def_${format}})
+endfunction()
+
+function(verify lang src)
+  add_library(default-${lang} ${src})
+  target_compile_definitions(default-${lang} PRIVATE "$<$<CONFIG:Debug,RelWithDebInfo>:${verify_default}>")
+
+  verify_combination(Embedded ${lang} ${src})
+  if(NOT NO_COMPILER_PDB)
+    verify_combination(ProgramDatabase ${lang} ${src})
+    if(NOT NO_EDIT_AND_CONTINUE AND NOT lang MATCHES "^(Fortran)$")
+      verify_combination(EditAndContinue ${lang} ${src})
+    endif()
+  endif()
+endfunction()
+
+verify(C verify.c)
+verify(CXX verify.cxx)
+if(CMake_TEST_CUDA)
+  verify(CUDA verify.cu)
+endif()
+if(CMake_TEST_Fortran)
+  verify(Fortran verify.F90)
+endif()

+ 7 - 0
Tests/MSVCDebugInformationFormat/override-C.cmake

@@ -0,0 +1,7 @@
+set(var "CMAKE_C_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_Embedded")
+string(REPLACE "-Z7" "-Z7;-DTEST_Z7" "${var}" "${${var}}")
+string(REPLACE "-gcodeview" "-gcodeview;-DTEST_Z7" "${var}" "${${var}}")
+set(var "CMAKE_C_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_ProgramDatabase")
+string(REPLACE "-Zi" "-Zi;-DTEST_Zi" "${var}" "${${var}}")
+set(var "CMAKE_C_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_EditAndContinue")
+string(REPLACE "-ZI" "-ZI;-DTEST_ZI" "${var}" "${${var}}")

+ 6 - 0
Tests/MSVCDebugInformationFormat/override-CUDA.cmake

@@ -0,0 +1,6 @@
+set(var "CMAKE_CUDA_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_Embedded")
+string(REPLACE "-Z7" "-Z7;-DTEST_Z7" "${var}" "${${var}}")
+set(var "CMAKE_CUDA_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_ProgramDatabase")
+string(REPLACE "-Zi" "-Zi;-DTEST_Zi" "${var}" "${${var}}")
+set(var "CMAKE_CUDA_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_EditAndContinue")
+string(REPLACE "-ZI" "-ZI;-DTEST_ZI" "${var}" "${${var}}")

+ 7 - 0
Tests/MSVCDebugInformationFormat/override-CXX.cmake

@@ -0,0 +1,7 @@
+set(var "CMAKE_CXX_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_Embedded")
+string(REPLACE "-Z7" "-Z7;-DTEST_Z7" "${var}" "${${var}}")
+string(REPLACE "-gcodeview" "-gcodeview;-DTEST_Z7" "${var}" "${${var}}")
+set(var "CMAKE_CXX_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_ProgramDatabase")
+string(REPLACE "-Zi" "-Zi;-DTEST_Zi" "${var}" "${${var}}")
+set(var "CMAKE_CXX_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_EditAndContinue")
+string(REPLACE "-ZI" "-ZI;-DTEST_ZI" "${var}" "${${var}}")

+ 4 - 0
Tests/MSVCDebugInformationFormat/override-Fortran.cmake

@@ -0,0 +1,4 @@
+set(var "CMAKE_Fortran_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_Embedded")
+string(REPLACE "-Z7" "-Z7;-DTEST_Z7" "${var}" "${${var}}")
+set(var "CMAKE_Fortran_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_ProgramDatabase")
+string(REPLACE "-Zi" "-Zi;-DTEST_Zi" "${var}" "${${var}}")

+ 1 - 0
Tests/MSVCDebugInformationFormat/verify.F90

@@ -0,0 +1 @@
+#include "verify.h"

+ 1 - 0
Tests/MSVCDebugInformationFormat/verify.c

@@ -0,0 +1 @@
+#include "verify.h"

+ 1 - 0
Tests/MSVCDebugInformationFormat/verify.cu

@@ -0,0 +1 @@
+#include "verify.h"

+ 1 - 0
Tests/MSVCDebugInformationFormat/verify.cxx

@@ -0,0 +1 @@
+#include "verify.h"

+ 29 - 0
Tests/MSVCDebugInformationFormat/verify.h

@@ -0,0 +1,29 @@
+#ifdef VERIFY_Z7
+#  ifndef TEST_Z7
+#    error "TEST_Z7 incorrectly not defined by debug format selection"
+#  endif
+#else
+#  ifdef TEST_Z7
+#    error "TEST_Z7 incorrectly defined by non-debug format selection"
+#  endif
+#endif
+
+#ifdef VERIFY_Zi
+#  ifndef TEST_Zi
+#    error "TEST_Zi incorrectly not defined by debug format selection"
+#  endif
+#else
+#  ifdef TEST_Zi
+#    error "TEST_Zi incorrectly defined by non-debug format selection"
+#  endif
+#endif
+
+#ifdef VERIFY_ZI
+#  ifndef TEST_ZI
+#    error "TEST_ZI incorrectly not defined by debug format selection"
+#  endif
+#else
+#  ifdef TEST_ZI
+#    error "TEST_ZI incorrectly defined by non-debug format selection"
+#  endif
+#endif

+ 1 - 0
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})

+ 1 - 0
Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-NEW-result.txt

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

+ 5 - 0
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\.$

+ 2 - 0
Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-NEW.cmake

@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0141 NEW)
+include(CMP0141-common.cmake)

+ 4 - 0
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)

+ 2 - 0
Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-OLD.cmake

@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0141 OLD)
+include(CMP0141-common.cmake)

+ 2 - 0
Tests/RunCMake/MSVCDebugInformationFormat/CMP0141-WARN.cmake

@@ -0,0 +1,2 @@
+
+include(CMP0141-common.cmake)

+ 31 - 0
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)

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

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

+ 6 - 0
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)

+ 0 - 0
Tests/RunCMake/MSVCDebugInformationFormat/empty.cxx


+ 46 - 0
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 "^ *<ItemDefinitionGroup Condition=\"'\\$\\(Configuration\\)\\|\\$\\(Platform\\)'=='([^<>]+)\\|[A-Za-z0-9_]+'\">")
+      set(Configuration "${CMAKE_MATCH_1}")
+    endif()
+    if(line MATCHES "^ *<DebugInformationFormat>([^<>]+)</DebugInformationFormat>")
+      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)

+ 24 - 0
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")

+ 1 - 0
Tests/RunCMake/VS10Project/RunCMakeTest.cmake

@@ -88,3 +88,4 @@ run_cmake(VsDotnetStartupObject)
 run_cmake(VsDotnetTargetFramework)
 run_cmake(VsDotnetTargetFrameworkVersion)
 run_cmake(VsNoCompileBatching)
+run_cmake(DebugInformationFormat)