From 2a9ff9703e20172ca14b6c872b300d0dbb75f5da Mon Sep 17 00:00:00 2001
From: Luca Cappa <lucappa@microsoft.com>
Date: Tue, 19 Mar 2019 13:52:53 -0700
Subject: MSVC: Add support for /JMC (Just My Code)

---
 Help/manual/cmake-properties.7.rst                 |  1 +
 Help/manual/cmake-variables.7.rst                  |  1 +
 Help/prop_tgt/VS_JUST_MY_CODE_DEBUGGING.rst        | 10 ++++++
 Help/release/dev/vs-just-my-code-debugging.rst     |  9 +++++
 Help/variable/CMAKE_VS_JUST_MY_CODE_DEBUGGING.rst  |  8 +++++
 Modules/Compiler/MSVC-C.cmake                      |  5 +++
 Modules/Compiler/MSVC-CXX.cmake                    |  5 +++
 Source/cmLocalGenerator.cxx                        | 26 +++++++++++++++
 Source/cmTarget.cxx                                |  1 +
 Tests/RunCMake/CMakeLists.txt                      |  5 ++-
 Tests/RunCMake/VS10Project/RunCMakeTest.cmake      |  5 +++
 .../RunCMake/VS10Project/VsJustMyCode-check.cmake  | 38 ++++++++++++++++++++++
 Tests/RunCMake/VS10Project/VsJustMyCode.cmake      | 24 ++++++++++++++
 13 files changed, 137 insertions(+), 1 deletion(-)
 create mode 100644 Help/prop_tgt/VS_JUST_MY_CODE_DEBUGGING.rst
 create mode 100644 Help/release/dev/vs-just-my-code-debugging.rst
 create mode 100644 Help/variable/CMAKE_VS_JUST_MY_CODE_DEBUGGING.rst
 create mode 100644 Tests/RunCMake/VS10Project/VsJustMyCode-check.cmake
 create mode 100644 Tests/RunCMake/VS10Project/VsJustMyCode.cmake

diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index c11496c..be30e96 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -333,6 +333,7 @@ Properties on Targets
    /prop_tgt/VS_GLOBAL_variable
    /prop_tgt/VS_IOT_EXTENSIONS_VERSION
    /prop_tgt/VS_IOT_STARTUP_TASK
+   /prop_tgt/VS_JUST_MY_CODE_DEBUGGING
    /prop_tgt/VS_KEYWORD
    /prop_tgt/VS_MOBILE_EXTENSIONS_VERSION
    /prop_tgt/VS_NO_SOLUTION_DEPLOY
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 6d93ae9..d445bc1 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -418,6 +418,7 @@ Variables that Control the Build
    /variable/CMAKE_VS_GLOBALS
    /variable/CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD
    /variable/CMAKE_VS_INCLUDE_PACKAGE_TO_DEFAULT_BUILD
+   /variable/CMAKE_VS_JUST_MY_CODE_DEBUGGING
    /variable/CMAKE_VS_SDK_EXCLUDE_DIRECTORIES
    /variable/CMAKE_VS_SDK_EXECUTABLE_DIRECTORIES
    /variable/CMAKE_VS_SDK_INCLUDE_DIRECTORIES
diff --git a/Help/prop_tgt/VS_JUST_MY_CODE_DEBUGGING.rst b/Help/prop_tgt/VS_JUST_MY_CODE_DEBUGGING.rst
new file mode 100644
index 0000000..42fb8ad
--- /dev/null
+++ b/Help/prop_tgt/VS_JUST_MY_CODE_DEBUGGING.rst
@@ -0,0 +1,10 @@
+VS_JUST_MY_CODE_DEBUGGING
+-------------------------
+
+Enable Just My Code with Visual Studio debugger.
+
+Supported on :ref:`Visual Studio Generators` for VS 2010 and higher,
+:ref:`Makefile Generators` and the :generator:`Ninja` generators.
+
+This property is initialized by the :variable:`CMAKE_VS_JUST_MY_CODE_DEBUGGING`
+variable if it is set when a target is created.
diff --git a/Help/release/dev/vs-just-my-code-debugging.rst b/Help/release/dev/vs-just-my-code-debugging.rst
new file mode 100644
index 0000000..73299d9
--- /dev/null
+++ b/Help/release/dev/vs-just-my-code-debugging.rst
@@ -0,0 +1,9 @@
+vs-just-my-code-debugging
+-------------------------
+
+* For the :ref:`Visual Studio Generators`, for the
+  :ref:`Makefile Generators` and the :generator:`Ninja` generator
+  the Just My Code feature of the Visual Studio Debugger could be
+  leveraged by turning on the :prop_tgt:`VS_JUST_MY_CODE_DEBUGGING` target
+  property. Its default value is provided by the variable
+  :variable:`CMAKE_VS_JUST_MY_CODE_DEBUGGING`.
diff --git a/Help/variable/CMAKE_VS_JUST_MY_CODE_DEBUGGING.rst b/Help/variable/CMAKE_VS_JUST_MY_CODE_DEBUGGING.rst
new file mode 100644
index 0000000..546cdf4
--- /dev/null
+++ b/Help/variable/CMAKE_VS_JUST_MY_CODE_DEBUGGING.rst
@@ -0,0 +1,8 @@
+CMAKE_VS_JUST_MY_CODE_DEBUGGING
+-------------------------------
+
+Enable Just My Code with Visual Studio debugger.
+
+This variable is used to initialize the :prop_tgt:`VS_JUST_MY_CODE_DEBUGGING`
+property on all targets when they are created.  See that target property for
+additional information.
diff --git a/Modules/Compiler/MSVC-C.cmake b/Modules/Compiler/MSVC-C.cmake
index f56227b..20787a3 100644
--- a/Modules/Compiler/MSVC-C.cmake
+++ b/Modules/Compiler/MSVC-C.cmake
@@ -31,3 +31,8 @@ macro(cmake_record_c_compile_features)
   endif()
   set(_result 0) # expected by cmake_determine_compile_features
 endmacro()
+
+# /JMC "Just My Code" is only supported by MSVC 19.05 onward.
+if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.05)
+  set(CMAKE_C_COMPILE_OPTIONS_JMC "-JMC")
+endif()
diff --git a/Modules/Compiler/MSVC-CXX.cmake b/Modules/Compiler/MSVC-CXX.cmake
index 787c17e..378a119 100644
--- a/Modules/Compiler/MSVC-CXX.cmake
+++ b/Modules/Compiler/MSVC-CXX.cmake
@@ -64,3 +64,8 @@ elseif (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0)
     _record_compiler_features(CXX "" CMAKE_CXX_COMPILE_FEATURES)
   endmacro()
 endif()
+
+# /JMC "Just My Code" is only supported by MSVC 19.05 onward.
+if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.05)
+  set(CMAKE_CXX_COMPILE_OPTIONS_JMC "-JMC")
+endif()
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 8b51834..047d405 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -877,6 +877,32 @@ void cmLocalGenerator::AddCompileOptions(std::string& flags,
     }
   }
   this->AddCompilerRequirementFlag(flags, target, lang);
+
+  // Add compile flag for the MSVC compiler only.
+  cmMakefile* mf = this->GetMakefile();
+  if (const char* jmc =
+        mf->GetDefinition("CMAKE_" + lang + "_COMPILE_OPTIONS_JMC")) {
+
+    // Handle Just My Code debugging flags, /JMC.
+    // If the target is a Managed C++ one, /JMC is not compatible.
+    if (target->GetManagedType(config) !=
+        cmGeneratorTarget::ManagedType::Managed) {
+      // add /JMC flags if target property VS_JUST_MY_CODE_DEBUGGING is set
+      // to ON
+      if (char const* jmcExprGen =
+            target->GetProperty("VS_JUST_MY_CODE_DEBUGGING")) {
+        cmGeneratorExpression ge;
+        std::unique_ptr<cmCompiledGeneratorExpression> cge =
+          ge.Parse(jmcExprGen);
+        std::string isJMCEnabled = cge->Evaluate(this, config);
+        if (cmSystemTools::IsOn(isJMCEnabled)) {
+          std::vector<std::string> optVec;
+          cmSystemTools::ExpandListArgument(jmc, optVec);
+          this->AppendCompileOptions(flags, optVec);
+        }
+      }
+    }
+  }
 }
 
 std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectoriesImplicit(
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 9598a3f..d6d463b 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -335,6 +335,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
     InitProperty("LINK_SEARCH_START_STATIC", nullptr);
     InitProperty("LINK_SEARCH_END_STATIC", nullptr);
     InitProperty("FOLDER", nullptr);
+    InitProperty("VS_JUST_MY_CODE_DEBUGGING", nullptr);
 #ifdef __APPLE__
     if (this->GetGlobalGenerator()->IsXcode()) {
       InitProperty("XCODE_GENERATE_SCHEME", nullptr);
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 2b78171..d57138b 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -360,7 +360,10 @@ if("${CMAKE_GENERATOR}" MATCHES "Visual Studio")
 endif()
 
 if("${CMAKE_GENERATOR}" MATCHES "Visual Studio ([^9]|9[0-9])")
-  add_RunCMake_test(VS10Project)
+  add_RunCMake_test(VS10Project
+    -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
+    -DCMAKE_C_COMPILER_VERSION=${CMAKE_C_COMPILER_VERSION}
+    )
   if( vs12 AND wince )
     add_RunCMake_test( VS10ProjectWinCE "-DRunCMake_GENERATOR_PLATFORM=${wince_sdk}")
   endif()
diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
index 0ac589d..9a0b7a9 100644
--- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
+++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
@@ -1,4 +1,5 @@
 include(RunCMake)
+cmake_policy(SET CMP0054 NEW)
 
 run_cmake(VsCSharpCompilerOpts)
 run_cmake(ExplicitCMakeLists)
@@ -20,3 +21,7 @@ run_cmake(VSCSharpDefines)
 run_cmake(VsSdkDirectories)
 run_cmake(VsGlobals)
 run_cmake(VsProjectImport)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.05)
+  run_cmake(VsJustMyCode)
+endif()
diff --git a/Tests/RunCMake/VS10Project/VsJustMyCode-check.cmake b/Tests/RunCMake/VS10Project/VsJustMyCode-check.cmake
new file mode 100644
index 0000000..7119976
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsJustMyCode-check.cmake
@@ -0,0 +1,38 @@
+macro(VsJustMyCode_check tgt jmc_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(HAVE_JMC 0)
+
+  file(STRINGS "${vcProjectFile}" lines)
+  foreach(line IN LISTS lines)
+    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}'.")
+        return()
+      endif()
+      set(HAVE_JMC 1)
+      break()
+    endif()
+  endforeach()
+
+  if(NOT HAVE_JMC AND NOT "${jmc_expect}" STREQUAL "")
+    set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not have a <SupportJustMyCode> property group.")
+    return()
+  endif()
+endmacro()
+
+VsJustMyCode_check(JMC-default-C "")
+VsJustMyCode_check(JMC-default-CXX "")
+VsJustMyCode_check(JMC-ON-C true)
+VsJustMyCode_check(JMC-ON-CXX true)
+VsJustMyCode_check(JMC-OFF-C "")
+VsJustMyCode_check(JMC-OFF-CXX "")
+VsJustMyCode_check(JMC-TGT-ON-C true)
+VsJustMyCode_check(JMC-TGT-ON-CXX true)
+VsJustMyCode_check(JMC-TGT-OFF-C "")
+VsJustMyCode_check(JMC-TGT-OFF-CXX "")
diff --git a/Tests/RunCMake/VS10Project/VsJustMyCode.cmake b/Tests/RunCMake/VS10Project/VsJustMyCode.cmake
new file mode 100644
index 0000000..b39f30f
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsJustMyCode.cmake
@@ -0,0 +1,24 @@
+set(CMAKE_CONFIGURATION_TYPES Debug)
+enable_language(C)
+enable_language(CXX)
+
+add_library(JMC-default-C empty.c)
+add_library(JMC-default-CXX empty.cxx)
+
+set(CMAKE_VS_JUST_MY_CODE_DEBUGGING OFF)
+add_library(JMC-OFF-C empty.c)
+add_library(JMC-OFF-CXX empty.cxx)
+
+set(CMAKE_VS_JUST_MY_CODE_DEBUGGING ON)
+add_library(JMC-ON-C empty.c)
+add_library(JMC-ON-CXX empty.cxx)
+
+set(CMAKE_VS_JUST_MY_CODE_DEBUGGING OFF)
+add_library(JMC-TGT-ON-C empty.c)
+set_property(TARGET JMC-TGT-ON-C PROPERTY VS_JUST_MY_CODE_DEBUGGING ON)
+add_library(JMC-TGT-ON-CXX empty.cxx)
+set_property(TARGET JMC-TGT-ON-CXX PROPERTY VS_JUST_MY_CODE_DEBUGGING ON)
+add_library(JMC-TGT-OFF-C empty.c)
+set_property(TARGET JMC-TGT-OFF-C PROPERTY VS_JUST_MY_CODE_DEBUGGING OFF)
+add_library(JMC-TGT-OFF-CXX empty.cxx)
+set_property(TARGET JMC-TGT-OFF-CXX PROPERTY VS_JUST_MY_CODE_DEBUGGING OFF)
-- 
cgit v0.12