Merge topic 'msvc-compilers-default-to-ZI'

5fcadc481e MSVC: Default to -ZI instead of /Zi for x86 and x64

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !7295
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index 788d086..a7741f7 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -58,6 +58,7 @@
 .. toctree::
    :maxdepth: 1
 
+   CMP0138: MSVC compilers use -ZI instead of /Zi for x86 and x64 by default. </policy/CMP0138>
    CMP0137: try_compile() passes platform variables in project mode. </policy/CMP0137>
    CMP0136: Watcom runtime library flags are selected by an abstraction. </policy/CMP0136>
    CMP0135: ExternalProject ignores timestamps in archives by default for the URL download method. </policy/CMP0135>
diff --git a/Help/policy/CMP0138.rst b/Help/policy/CMP0138.rst
new file mode 100644
index 0000000..5cf3948
--- /dev/null
+++ b/Help/policy/CMP0138.rst
@@ -0,0 +1,43 @@
+CMP0138
+-------
+
+.. versionadded:: 3.24
+
+MSVC compilers use ``-ZI`` instead of ``/Zi`` for x86 and x64 by default.
+
+When using MSVC C/C++ compilers in CMake 3.23 and below, debug information
+format flag ``/Zi`` is added to :variable:`CMAKE_<LANG>_FLAGS_DEBUG` and
+:variable:`CMAKE_<LANG>_FLAGS_RELWITHDEBINFO` by default. The ``/Zi`` flag
+produces a separate PDB file that contains all the symbolic debugging
+information for use with the debugger, however, it does not support Edit
+and Continue feature in a debugging session.
+
+CMake 3.24 and above adds ``-ZI`` to :variable:`CMAKE_<LANG>_FLAGS_DEBUG`
+and :variable:`CMAKE_<LANG>_FLAGS_RELWITHDEBINFO` instead to enable Edit
+and Continue by default.
+
+This policy provides compatibility with projects that have not been updated
+to expect the lack of warning flags. The policy setting takes effect as of
+the first :command:`project` or :command:`enable_language` command that
+initializes :variable:`CMAKE_<LANG>_FLAGS_DEBUG` and
+:variable:`CMAKE_<LANG>_FLAGS_RELWITHDEBINFO` for a given language
+``<LANG>`` using MSVC compilers.
+
+.. note::
+
+  Once the policy has taken effect at the top of a project for a given
+  language, that choice must be used throughout the tree for that language.
+  In projects that have nested projects in subdirectories, be sure to
+  convert everything together.
+
+The ``OLD`` behavior for this policy is to place ``/Zi`` in the default
+:variable:`CMAKE_<LANG>_FLAGS_DEBUG` and
+:variable:`CMAKE_<LANG>_FLAGS_RELWITHDEBINFO` cache entries. The ``NEW``
+behavior for this policy is to place ``-ZI`` in the default cache entries.
+
+This policy was introduced in CMake version 3.24. 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/release/dev/msvc-compilers-default-to-ZI.rst b/Help/release/dev/msvc-compilers-default-to-ZI.rst
new file mode 100644
index 0000000..61ea877
--- /dev/null
+++ b/Help/release/dev/msvc-compilers-default-to-ZI.rst
@@ -0,0 +1,5 @@
+msvc-compilers-default-to-ZI
+----------------------------
+
+* With MSVC compilers, debug configurations now use ``-ZI`` by default
+  instead of ``/Zi``.  See policy :policy:`CMP0138`.
diff --git a/Modules/Platform/Windows-MSVC-C.cmake b/Modules/Platform/Windows-MSVC-C.cmake
index 67b6827..7dfc033 100644
--- a/Modules/Platform/Windows-MSVC-C.cmake
+++ b/Modules/Platform/Windows-MSVC-C.cmake
@@ -2,6 +2,15 @@
 if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 18.0)
   set(_FS_C " /FS")
 endif()
+
+cmake_policy(GET CMP0138 _cmp0138)
+if(_cmp0138 STREQUAL "NEW")
+  if(NOT _MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM" AND NOT _MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM64")
+    set(_ZiOrZI "-ZI")
+  endif()
+endif()
+unset(_cmp0138)
+
 __windows_compiler_msvc(C)
 
 if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
diff --git a/Modules/Platform/Windows-MSVC-CXX.cmake b/Modules/Platform/Windows-MSVC-CXX.cmake
index 6fea617..ba9a260 100644
--- a/Modules/Platform/Windows-MSVC-CXX.cmake
+++ b/Modules/Platform/Windows-MSVC-CXX.cmake
@@ -3,6 +3,15 @@
 if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18.0)
   set(_FS_CXX " /FS")
 endif()
+
+cmake_policy(GET CMP0138 _cmp0138)
+if(_cmp0138 STREQUAL "NEW")
+  if(NOT _MSVC_CXX_ARCHITECTURE_FAMILY STREQUAL "ARM" AND NOT _MSVC_CXX_ARCHITECTURE_FAMILY STREQUAL "ARM64")
+    set(_ZiOrZI "-ZI")
+  endif()
+endif()
+unset(_cmp0138)
+
 __windows_compiler_msvc(CXX)
 
 if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
diff --git a/Modules/Platform/Windows-MSVC.cmake b/Modules/Platform/Windows-MSVC.cmake
index e74ec9e..acfd0d8 100644
--- a/Modules/Platform/Windows-MSVC.cmake
+++ b/Modules/Platform/Windows-MSVC.cmake
@@ -441,6 +441,10 @@
     endif()
     unset(_cmp0092)
 
+    if(NOT DEFINED _ZiOrZI)
+      set(_ZiOrZI "/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,15 +455,16 @@
       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} ${_ZiOrZI} /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} ${_ZiOrZI} /O2 /Ob1 /DNDEBUG")
       string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT "${_MD} /O1 /Ob1 /DNDEBUG")
     endif()
     unset(_Wall)
     unset(_W3)
     unset(_MDd)
     unset(_MD)
+    unset(_ZiOrZI)
 
     set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         -MT)
     set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      -MD)
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index c8b037e..f13432b 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -414,7 +414,10 @@
          24, 0, cmPolicies::WARN)                                             \
   SELECT(POLICY, CMP0137,                                                     \
          "try_compile() passes platform variables in project mode", 3, 24, 0, \
-         cmPolicies::WARN)
+         cmPolicies::WARN)                                                    \
+  SELECT(POLICY, CMP0138,                                                     \
+         "MSVC compilers use -ZI instead of /Zi for x86 and x64 by default.", \
+         3, 24, 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/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index da91e64..6f90bf7 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -352,6 +352,9 @@
   add_RunCMake_test(MSVCRuntimeLibrary)
   add_RunCMake_test(MSVCRuntimeTypeInfo)
   add_RunCMake_test(MSVCWarningFlags)
+  if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
+    add_RunCMake_test(MSVCDebugInformationFormat)
+  endif()
 endif()
 if(XCODE_VERSION)
   set(ObjectLibrary_ARGS -DXCODE_VERSION=${XCODE_VERSION})
diff --git a/Tests/RunCMake/MSVCDebugInformationFormat/CMP0138-NEW.cmake b/Tests/RunCMake/MSVCDebugInformationFormat/CMP0138-NEW.cmake
new file mode 100644
index 0000000..7dda266
--- /dev/null
+++ b/Tests/RunCMake/MSVCDebugInformationFormat/CMP0138-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0138 NEW)
+include(CMP0138-common.cmake)
diff --git a/Tests/RunCMake/MSVCDebugInformationFormat/CMP0138-OLD.cmake b/Tests/RunCMake/MSVCDebugInformationFormat/CMP0138-OLD.cmake
new file mode 100644
index 0000000..43e4668
--- /dev/null
+++ b/Tests/RunCMake/MSVCDebugInformationFormat/CMP0138-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0138 OLD)
+include(CMP0138-common.cmake)
diff --git a/Tests/RunCMake/MSVCDebugInformationFormat/CMP0138-WARN.cmake b/Tests/RunCMake/MSVCDebugInformationFormat/CMP0138-WARN.cmake
new file mode 100644
index 0000000..2a0dd0e
--- /dev/null
+++ b/Tests/RunCMake/MSVCDebugInformationFormat/CMP0138-WARN.cmake
@@ -0,0 +1,2 @@
+
+include(CMP0138-common.cmake)
diff --git a/Tests/RunCMake/MSVCDebugInformationFormat/CMP0138-common.cmake b/Tests/RunCMake/MSVCDebugInformationFormat/CMP0138-common.cmake
new file mode 100644
index 0000000..89a5ca1
--- /dev/null
+++ b/Tests/RunCMake/MSVCDebugInformationFormat/CMP0138-common.cmake
@@ -0,0 +1,20 @@
+foreach(lang C CXX)
+  enable_language(${lang})
+
+  cmake_policy(GET CMP0138 cmp0138)
+  if(cmp0138 STREQUAL "NEW")
+    if(NOT " ${CMAKE_${lang}_FLAGS_DEBUG} " MATCHES " -ZI ")
+      message(SEND_ERROR "CMAKE_${lang}_FLAGS_DEBUG does not have '-ZI' under NEW behavior")
+    endif()
+    if(NOT " ${CMAKE_${lang}_FLAGS_RELWITHDEBINFO} " MATCHES " -ZI ")
+      message(SEND_ERROR "CMAKE_${lang}_FLAGS_RELWITHDEBINFO does not have '-ZI' under NEW behavior")
+    endif()
+  else()
+    if(NOT " ${CMAKE_${lang}_FLAGS_DEBUG} " MATCHES " /Zi ")
+      message(SEND_ERROR "CMAKE_${lang}_FLAGS_DEBUG does not have '/Zi' under OLD behavior")
+    endif()
+    if(NOT " ${CMAKE_${lang}_FLAGS_RELWITHDEBINFO} " MATCHES " /Zi ")
+      message(SEND_ERROR "CMAKE_${lang}_FLAGS_RELWITHDEBINFO does not have '/Zi' under OLD behavior")
+    endif()
+  endif()
+endforeach()
diff --git a/Tests/RunCMake/MSVCDebugInformationFormat/CMakeLists.txt b/Tests/RunCMake/MSVCDebugInformationFormat/CMakeLists.txt
new file mode 100644
index 0000000..5ff8d3e
--- /dev/null
+++ b/Tests/RunCMake/MSVCDebugInformationFormat/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.23)
+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..7210fcd
--- /dev/null
+++ b/Tests/RunCMake/MSVCDebugInformationFormat/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0138-WARN)
+run_cmake(CMP0138-OLD)
+run_cmake(CMP0138-NEW)