Merge topic 'ninja-multi-cross-configs'
b7a2baf38c Ninja Multi-Config: Add variable to control configs used in cross-config build
Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !4269
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index 393735e..3a62371 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -185,6 +185,7 @@
/prop_tgt/DEPLOYMENT_ADDITIONAL_FILES
/prop_tgt/DEPRECATION
/prop_tgt/DISABLE_PRECOMPILE_HEADERS
+ /prop_tgt/DOTNET_TARGET_FRAMEWORK
/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION
/prop_tgt/EchoString
/prop_tgt/ENABLE_EXPORTS
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 10d7f2c..1f5b39c 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -48,6 +48,7 @@
/variable/CMAKE_DEBUG_TARGET_PROPERTIES
/variable/CMAKE_DIRECTORY_LABELS
/variable/CMAKE_DL_LIBS
+ /variable/CMAKE_DOTNET_TARGET_FRAMEWORK
/variable/CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION
/variable/CMAKE_EDIT_COMMAND
/variable/CMAKE_EXECUTABLE_SUFFIX
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst
index 4315f0a..44b1f2f 100644
--- a/Help/manual/cmake.1.rst
+++ b/Help/manual/cmake.1.rst
@@ -279,7 +279,9 @@
"file": "/full/path/to/the/CMake/file.txt",
"line": 0,
"cmd": "add_executable",
- "args": ["foo", "bar"]
+ "args": ["foo", "bar"],
+ "time": 1579512535.9687231,
+ "frame": 2
}
The members are:
@@ -288,8 +290,8 @@
The full path to the CMake source file where the function
was called.
- ``line``
- The line in `file` of the function call.
+ ``line``
+ The line in ``file`` of the function call.
``cmd``
The name of the function that was called.
@@ -297,6 +299,12 @@
``args``
A string list of all function parameters.
+ ``time``
+ Timestamp (seconds since epoch) of the function call.
+
+ ``frame``
+ Stack frame depth of the function that was called.
+
Additionally, the first JSON document outputted contains the
``version`` key for the current major and minor version of the
diff --git a/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK.rst b/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK.rst
new file mode 100644
index 0000000..8698eb6
--- /dev/null
+++ b/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK.rst
@@ -0,0 +1,13 @@
+DOTNET_TARGET_FRAMEWORK
+-----------------------
+
+Specify the .NET target framework.
+
+Used to specify the .NET target framework for C++/CLI and C#. For
+example: ``netcoreapp2.1``.
+
+This property is only evaluated for :ref:`Visual Studio Generators`
+VS 2010 and above.
+
+Can be initialized for all targets using the variable
+:variable:`CMAKE_DOTNET_TARGET_FRAMEWORK`.
diff --git a/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION.rst b/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION.rst
index c100326..b33f4fb 100644
--- a/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION.rst
+++ b/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION.rst
@@ -3,11 +3,13 @@
Specify the .NET target framework version.
-Used to specify the .NET target framework version for C++/CLI. For
-example: ``v4.5``.
+Used to specify the .NET target framework version for C++/CLI and C#.
+For example: ``v4.5``.
This property is only evaluated for :ref:`Visual Studio Generators`
VS 2010 and above.
-Can be initialized for all targets using the variable
-:variable:`CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION`.
+To initialize this variable for all targets set
+:variable:`CMAKE_DOTNET_TARGET_FRAMEWORK` or
+:variable:`CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION`. If both are set,
+the latter is ignored.
diff --git a/Help/prop_tgt/VS_DOTNET_TARGET_FRAMEWORK_VERSION.rst b/Help/prop_tgt/VS_DOTNET_TARGET_FRAMEWORK_VERSION.rst
index 9f5a313..6cb8f86 100644
--- a/Help/prop_tgt/VS_DOTNET_TARGET_FRAMEWORK_VERSION.rst
+++ b/Help/prop_tgt/VS_DOTNET_TARGET_FRAMEWORK_VERSION.rst
@@ -3,8 +3,9 @@
Specify the .NET target framework version.
-Used to specify the .NET target framework version for C++/CLI. For
+Used to specify the .NET target framework version for C++/CLI. For
example, "v4.5".
This property is deprecated and should not be used anymore. Use
+:prop_tgt:`DOTNET_TARGET_FRAMEWORK` or
:prop_tgt:`DOTNET_TARGET_FRAMEWORK_VERSION` instead.
diff --git a/Help/release/dev/vs-dotnet-standard-core.rst b/Help/release/dev/vs-dotnet-standard-core.rst
new file mode 100644
index 0000000..9bb292e
--- /dev/null
+++ b/Help/release/dev/vs-dotnet-standard-core.rst
@@ -0,0 +1,7 @@
+vs-dotnet-standard-core
+-----------------------
+
+* :ref:`Visual Studio Generators` for VS 2010 and above learned to
+ support .NET Standard and .NET Core. See the
+ :prop_tgt:`DOTNET_TARGET_FRAMEWORK` target property and
+ associated :variable:`CMAKE_DOTNET_TARGET_FRAMEWORK` variable.
diff --git a/Help/variable/CMAKE_DOTNET_TARGET_FRAMEWORK.rst b/Help/variable/CMAKE_DOTNET_TARGET_FRAMEWORK.rst
new file mode 100644
index 0000000..8edcd1e
--- /dev/null
+++ b/Help/variable/CMAKE_DOTNET_TARGET_FRAMEWORK.rst
@@ -0,0 +1,16 @@
+CMAKE_DOTNET_TARGET_FRAMEWORK
+-----------------------------
+
+Default value for :prop_tgt:`DOTNET_TARGET_FRAMEWORK` property of
+targets.
+
+This variable is used to initialize the
+:prop_tgt:`DOTNET_TARGET_FRAMEWORK` property on all targets. See that
+target property for additional information.
+
+Setting ``CMAKE_DOTNET_TARGET_FRAMEWORK`` may be necessary
+when working with ``C#`` and newer .NET framework versions to
+avoid referencing errors with the ``ALL_BUILD`` CMake target.
+
+This variable is only evaluated for :ref:`Visual Studio Generators`
+VS 2010 and above.
diff --git a/Help/variable/CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION.rst b/Help/variable/CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION.rst
index 124fefe..c2eef9e 100644
--- a/Help/variable/CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION.rst
+++ b/Help/variable/CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION.rst
@@ -6,7 +6,11 @@
This variable is used to initialize the
:prop_tgt:`DOTNET_TARGET_FRAMEWORK_VERSION` property on all
-targets. See that target property for additional information.
+targets. See that target property for additional information. When set,
+:variable:`CMAKE_DOTNET_TARGET_FRAMEWORK` takes precednece over this
+variable. See that variable or the associated target property
+:prop_tgt:`DOTNET_TARGET_FRAMEWORK` for additional information.
+
Setting ``CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION`` may be necessary
when working with ``C#`` and newer .NET framework versions to
diff --git a/Modules/FindCUDAToolkit.cmake b/Modules/FindCUDAToolkit.cmake
index f7f68ca..6a40ace 100644
--- a/Modules/FindCUDAToolkit.cmake
+++ b/Modules/FindCUDAToolkit.cmake
@@ -408,6 +408,11 @@
The path to the CUDA Toolkit library directory that contains the CUDA
Runtime library ``cudart``.
+``CUDAToolkit_TARGET_DIR``
+ The path to the CUDA Toolkit directory including the target architecture
+ when cross-compiling. When not cross-compiling this will be equivalant to
+ ``CUDAToolkit_ROOT_DIR``.
+
``CUDAToolkit_NVCC_EXECUTABLE``
The path to the NVIDIA CUDA compiler ``nvcc``. Note that this path may
**not** be the same as
@@ -641,8 +646,37 @@
get_filename_component(CUDAToolkit_ROOT_DIR ${CUDAToolkit_BIN_DIR} DIRECTORY ABSOLUTE)
-# Now that we have the real ROOT_DIR, find components inside it.
-list(APPEND CMAKE_PREFIX_PATH ${CUDAToolkit_ROOT_DIR})
+# Handle cross compilation
+if(CMAKE_CROSSCOMPILING)
+ if(CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7-a")
+ # Support for NVPACK
+ set (CUDAToolkit_TARGET_NAME "armv7-linux-androideabi")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm")
+ # Support for arm cross compilation
+ set(CUDAToolkit_TARGET_NAME "armv7-linux-gnueabihf")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
+ # Support for aarch64 cross compilation
+ if (ANDROID_ARCH_NAME STREQUAL "arm64")
+ set(CUDAToolkit_TARGET_NAME "aarch64-linux-androideabi")
+ else()
+ set(CUDAToolkit_TARGET_NAME "aarch64-linux")
+ endif (ANDROID_ARCH_NAME STREQUAL "arm64")
+ elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
+ set(CUDAToolkit_TARGET_NAME "x86_64-linux")
+ endif()
+
+ if (EXISTS "${CUDAToolkit_ROOT_DIR}/targets/${CUDAToolkit_TARGET_NAME}")
+ set(CUDAToolkit_TARGET_DIR "${CUDAToolkit_ROOT_DIR}/targets/${CUDAToolkit_TARGET_NAME}")
+ # add known CUDA target root path to the set of directories we search for programs, libraries and headers
+ list(APPEND CMAKE_FIND_ROOT_PATH "${CUDAToolkit_TARGET_DIR}")
+ endif()
+else()
+ # Not cross compiling
+ set(CUDAToolkit_TARGET_DIR "${CUDAToolkit_ROOT_DIR}")
+ # Now that we have the real ROOT_DIR, find components inside it.
+ list(APPEND CMAKE_PREFIX_PATH ${CUDAToolkit_ROOT_DIR})
+endif()
+
# Find the include/ directory
find_path(CUDAToolkit_INCLUDE_DIR
@@ -652,14 +686,20 @@
# And find the CUDA Runtime Library libcudart
find_library(CUDA_CUDART
NAMES cudart
- PATH_SUFFIXES lib64 lib/x64
+ PATH_SUFFIXES lib64 lib64/stubs lib/x64
)
if (NOT CUDA_CUDART AND NOT CUDAToolkit_FIND_QUIETLY)
message(STATUS "Unable to find cudart library.")
endif()
unset(CUDAToolkit_ROOT_DIR)
-list(REMOVE_AT CMAKE_PREFIX_PATH -1)
+if(CMAKE_CROSSCOMPILING)
+ if(CUDAToolkit_TARGET_DIR)
+ list(REMOVE_AT CMAKE_FIND_ROOT_PATH -1)
+ endif()
+else()
+ list(REMOVE_AT CMAKE_PREFIX_PATH -1)
+endif()
#-----------------------------------------------------------------------------
# Perform version comparison and validate all required variables are set.
@@ -696,7 +736,7 @@
NAMES ${search_names}
PATHS ${CUDAToolkit_LIBRARY_DIR}
ENV CUDA_PATH
- PATH_SUFFIXES nvidia/current lib64 lib/x64 lib
+ PATH_SUFFIXES nvidia/current lib64 lib64/stubs lib/x64 lib lib/stubs
)
if (NOT CUDA::${lib_name} AND CUDA_${lib_name}_LIBRARY)
diff --git a/Modules/FindPackageHandleStandardArgs.cmake b/Modules/FindPackageHandleStandardArgs.cmake
index a7c3eae..a078049 100644
--- a/Modules/FindPackageHandleStandardArgs.cmake
+++ b/Modules/FindPackageHandleStandardArgs.cmake
@@ -289,10 +289,12 @@
string(TOLOWER ${_NAME} _NAME_LOWER)
if(FPHSA_FOUND_VAR)
- if(FPHSA_FOUND_VAR MATCHES "^${_NAME}_FOUND$" OR FPHSA_FOUND_VAR MATCHES "^${_NAME_UPPER}_FOUND$")
+ set(_FOUND_VAR_UPPER ${_NAME_UPPER}_FOUND)
+ set(_FOUND_VAR_MIXED ${_NAME}_FOUND)
+ if(FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_MIXED OR FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_UPPER)
set(_FOUND_VAR ${FPHSA_FOUND_VAR})
else()
- message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_NAME}_FOUND\" and \"${_NAME_UPPER}_FOUND\" are valid names.")
+ message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_FOUND_VAR_MIXED}\" and \"${_FOUND_VAR_UPPER}\" are valid names.")
endif()
else()
set(_FOUND_VAR ${_NAME_UPPER}_FOUND)
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 47b13af..103129a 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,7 +1,7 @@
# CMake version number components.
set(CMake_VERSION_MAJOR 3)
set(CMake_VERSION_MINOR 16)
-set(CMake_VERSION_PATCH 20200123)
+set(CMake_VERSION_PATCH 20200124)
#set(CMake_VERSION_RC 0)
set(CMake_VERSION_IS_DIRTY 0)
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 020d2af..2dd89e3 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -549,10 +549,19 @@
}
};
- if (this->NinjaSupportsCleanDeadTool) {
+ // The `cleandead` tool needs to know about all outputs in the build we just
+ // wrote out. Ninja-Multi doesn't have a single `build.ninja` we can use that
+ // is the union of all generated configurations, so we can't run it reliably
+ // in that case.
+ if (this->NinjaSupportsCleanDeadTool && !this->IsMultiConfig()) {
run_ninja_tool({ "cleandead" });
}
- if (this->NinjaSupportsUnconditionalRecompactTool) {
+ // The `recompact` tool loads the manifest. As above, we don't have a single
+ // `build.ninja` to load for this in Ninja-Multi. This may be relaxed in the
+ // future pending further investigation into how Ninja works upstream
+ // (ninja#1721).
+ if (this->NinjaSupportsUnconditionalRecompactTool &&
+ !this->IsMultiConfig()) {
run_ninja_tool({ "recompact" });
}
if (this->NinjaSupportsRestatTool) {
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 668a27d..59995be 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -340,6 +340,9 @@
for (std::string const& arg : args) {
val["args"].append(arg);
}
+ val["time"] = cmSystemTools::GetTime();
+ val["frame"] =
+ static_cast<std::uint64_t>(this->ExecutionStatusStack.size());
msg << Json::writeString(builder, val);
#endif
break;
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index a0b3138..d46bf56 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -517,6 +517,7 @@
}
if (impl->TargetType <= cmStateEnums::UTILITY) {
+ initProp("DOTNET_TARGET_FRAMEWORK");
initProp("DOTNET_TARGET_FRAMEWORK_VERSION");
}
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index f707bb4..fd94bc9 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -483,23 +483,33 @@
}
e1.Element("ProjectName", projLabel);
{
- // TODO: add deprecation warning for VS_* property?
- const char* targetFrameworkVersion =
- this->GeneratorTarget->GetProperty(
- "VS_DOTNET_TARGET_FRAMEWORK_VERSION");
- if (!targetFrameworkVersion) {
- targetFrameworkVersion = this->GeneratorTarget->GetProperty(
- "DOTNET_TARGET_FRAMEWORK_VERSION");
- }
- if (!targetFrameworkVersion && this->ProjectType == csproj &&
- this->GlobalGenerator->TargetsWindowsCE() &&
- this->GlobalGenerator->GetVersion() ==
- cmGlobalVisualStudioGenerator::VS12) {
- // VS12 .NETCF default to .NET framework 3.9
- targetFrameworkVersion = "v3.9";
- }
- if (targetFrameworkVersion) {
- e1.Element("TargetFrameworkVersion", targetFrameworkVersion);
+ const char* targetFramework =
+ this->GeneratorTarget->GetProperty("DOTNET_TARGET_FRAMEWORK");
+ if (targetFramework) {
+ if (std::strchr(targetFramework, ';') != nullptr) {
+ e1.Element("TargetFrameworks", targetFramework);
+ } else {
+ e1.Element("TargetFramework", targetFramework);
+ }
+ } else {
+ // TODO: add deprecation warning for VS_* property?
+ const char* targetFrameworkVersion =
+ this->GeneratorTarget->GetProperty(
+ "VS_DOTNET_TARGET_FRAMEWORK_VERSION");
+ if (!targetFrameworkVersion) {
+ targetFrameworkVersion = this->GeneratorTarget->GetProperty(
+ "DOTNET_TARGET_FRAMEWORK_VERSION");
+ }
+ if (!targetFrameworkVersion && this->ProjectType == csproj &&
+ this->GlobalGenerator->TargetsWindowsCE() &&
+ this->GlobalGenerator->GetVersion() ==
+ cmGlobalVisualStudioGenerator::VS12) {
+ // VS12 .NETCF default to .NET framework 3.9
+ targetFrameworkVersion = "v3.9";
+ }
+ if (targetFrameworkVersion) {
+ e1.Element("TargetFrameworkVersion", targetFrameworkVersion);
+ }
}
if (this->ProjectType == vcxproj &&
this->GlobalGenerator->TargetsWindowsCE()) {
@@ -4110,6 +4120,9 @@
e2.Element("Project", "{" + this->GlobalGenerator->GetGUID(name) + "}");
e2.Element("Name", name);
this->WriteDotNetReferenceCustomTags(e2, name);
+ if (dt->IsCSharpOnly() || cmHasLiteralSuffix(path, "csproj")) {
+ e2.Element("SkipGetTargetFrameworkProperties", "true");
+ }
// Don't reference targets that don't produce any output.
if (dt->GetManagedType("") == cmGeneratorTarget::ManagedType::Undefined) {
diff --git a/Tests/RunCMake/CommandLine/trace-json-v1-check.py b/Tests/RunCMake/CommandLine/trace-json-v1-check.py
index 14febaf..e617b76 100755
--- a/Tests/RunCMake/CommandLine/trace-json-v1-check.py
+++ b/Tests/RunCMake/CommandLine/trace-json-v1-check.py
@@ -46,6 +46,7 @@
{
'args': msg_args,
'cmd': 'message',
+ 'frame': 3 if expand else 2
},
]
@@ -59,14 +60,17 @@
for i in fp.readlines():
line = json.loads(i)
- assert sorted(line.keys()) == ['args', 'cmd', 'file', 'line']
+ assert sorted(line.keys()) == ['args', 'cmd', 'file', 'frame', 'line', 'time']
assert isinstance(line['args'], list)
assert isinstance(line['cmd'], unicode)
assert isinstance(line['file'], unicode)
+ assert isinstance(line['frame'], int)
assert isinstance(line['line'], int)
+ assert isinstance(line['time'], float)
for j in required_traces:
- if j['cmd'] == line['cmd'] and j['args'] == line['args']:
- j['found'] = True
+ # Compare the subset of required keys with line
+ if {k: line[k] for k in j} == j:
+ required_traces.remove(j)
-assert all([x.get('found', False) == True for x in required_traces])
+assert not required_traces
diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
index 5cbe333..8a04f78 100644
--- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
+++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
@@ -53,3 +53,6 @@
else()
run_cmake(UnityBuildNative)
endif()
+
+run_cmake(VsDotnetTargetFramework)
+run_cmake(VsDotnetTargetFrameworkVersion)
diff --git a/Tests/RunCMake/VS10Project/VSDotnetTargetFrameworkVersion.cmake b/Tests/RunCMake/VS10Project/VSDotnetTargetFrameworkVersion.cmake
new file mode 100644
index 0000000..8e0e0b4
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VSDotnetTargetFrameworkVersion.cmake
@@ -0,0 +1,10 @@
+enable_language(CSharp)
+if(NOT CMAKE_CSharp_COMPILER)
+ return()
+endif()
+
+set(CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION "v4.6.1")
+add_library(foo SHARED foo.cs)
+
+set(CMAKE_DOTNET_TARGET_FRAMEWORK "netcoreapp3.1")
+add_library(bar SHARED foo.cs)
diff --git a/Tests/RunCMake/VS10Project/VsDotnetTargetFramework-check.cmake b/Tests/RunCMake/VS10Project/VsDotnetTargetFramework-check.cmake
new file mode 100644
index 0000000..e656639
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsDotnetTargetFramework-check.cmake
@@ -0,0 +1,40 @@
+set(files foo.csproj bar.csproj)
+
+set(inLib1 FALSE)
+set(targetFrameworkInLib1 FALSE)
+
+set(inLib2 FALSE)
+set(targetFrameworksInLib2 FALSE)
+
+foreach(file ${files})
+ set(csProjectFile ${RunCMake_TEST_BINARY_DIR}/${file})
+
+ if(NOT EXISTS "${csProjectFile}")
+ set(RunCMake_TEST_FAILED "Project file ${csProjectFile} does not exist.")
+ return()
+ endif()
+
+ file(STRINGS "${csProjectFile}" lines)
+
+ foreach(line IN LISTS lines)
+ if(NOT inLib1)
+ if(line MATCHES " *<TargetFramework>netcoreapp3.1</TargetFramework> *$")
+ set(targetFrameworkInLib1 TRUE)
+ set(inLib1 TRUE)
+ endif()
+ elseif(NOT inLib2)
+ if(line MATCHES " *<TargetFrameworks>netcoreapp3.1;net461</TargetFrameworks> *$")
+ set(targetFrameworksInLib2 TRUE)
+ set(inLib2 TRUE)
+ endif()
+ endif()
+ endforeach()
+endforeach()
+
+if(NOT targetFrameworkInLib1)
+ set(RunCMake_TEST_FAILED "TargetFramework not set correctly.")
+endif()
+
+if(NOT targetFrameworksInLib2)
+ set(RunCMake_TEST_FAILED "TargetFrameworks not set correctly.")
+endif()
diff --git a/Tests/RunCMake/VS10Project/VsDotnetTargetFramework.cmake b/Tests/RunCMake/VS10Project/VsDotnetTargetFramework.cmake
new file mode 100644
index 0000000..f553679
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsDotnetTargetFramework.cmake
@@ -0,0 +1,11 @@
+enable_language(CSharp)
+if(NOT CMAKE_CSharp_COMPILER)
+ return()
+endif()
+
+set(CMAKE_DOTNET_TARGET_FRAMEWORK "netcoreapp3.1")
+set(CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION "net461")
+add_library(foo SHARED foo.cs)
+
+set(CMAKE_DOTNET_TARGET_FRAMEWORK "netcoreapp3.1;net461")
+add_library(bar SHARED foo.cs)
diff --git a/Tests/RunCMake/VS10Project/VsDotnetTargetFrameworkVersion-check.cmake b/Tests/RunCMake/VS10Project/VsDotnetTargetFrameworkVersion-check.cmake
new file mode 100644
index 0000000..d2c3c3b
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsDotnetTargetFrameworkVersion-check.cmake
@@ -0,0 +1,40 @@
+set(files foo.csproj bar.csproj)
+
+set(inLib1 FALSE)
+set(targetFrameworkInLib1 FALSE)
+
+set(inLib2 FALSE)
+set(targetFrameworksInLib2 FALSE)
+
+foreach(file ${files})
+ set(csProjectFile ${RunCMake_TEST_BINARY_DIR}/${file})
+
+ if(NOT EXISTS "${csProjectFile}")
+ set(RunCMake_TEST_FAILED "Project file ${csProjectFile} does not exist.")
+ return()
+ endif()
+
+ file(STRINGS "${csProjectFile}" lines)
+
+ foreach(line IN LISTS lines)
+ if(NOT inLib1)
+ if(line MATCHES " *<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> *$")
+ set(targetFrameworkInLib1 TRUE)
+ set(inLib1 TRUE)
+ endif()
+ elseif(NOT inLib2)
+ if(line MATCHES " *<TargetFramework>netcoreapp3.1</TargetFramework> *$")
+ set(targetFrameworksInLib2 TRUE)
+ set(inLib2 TRUE)
+ endif()
+ endif()
+ endforeach()
+endforeach()
+
+if(NOT targetFrameworkInLib1)
+ set(RunCMake_TEST_FAILED "TargetFrameworkVersion not set correctly.")
+endif()
+
+if(NOT targetFrameworksInLib2)
+ set(RunCMake_TEST_FAILED "TargetFramework not set correctly.")
+endif()
diff --git a/Tests/RunCMake/include_external_msproject/RunCMakeTest.cmake b/Tests/RunCMake/include_external_msproject/RunCMakeTest.cmake
index 47dac34..7ed0773 100644
--- a/Tests/RunCMake/include_external_msproject/RunCMakeTest.cmake
+++ b/Tests/RunCMake/include_external_msproject/RunCMakeTest.cmake
@@ -5,3 +5,7 @@
run_cmake(CustomTypePlatform)
run_cmake(CustomGuidTypePlatform)
run_cmake(CustomConfig)
+
+if(RunCMake_GENERATOR MATCHES "Visual Studio ([^9]|9[0-9])")
+ run_cmake(SkipGetTargetFrameworkProperties)
+endif()
diff --git a/Tests/RunCMake/include_external_msproject/SkipGetTargetFrameworkProperties-check.cmake b/Tests/RunCMake/include_external_msproject/SkipGetTargetFrameworkProperties-check.cmake
new file mode 100644
index 0000000..375b231
--- /dev/null
+++ b/Tests/RunCMake/include_external_msproject/SkipGetTargetFrameworkProperties-check.cmake
@@ -0,0 +1,21 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/ALL_BUILD.vcxproj" all_build)
+
+macro(project_reference EXTERNAL_PROJECT)
+ string(REGEX MATCH
+ "<ProjectReference.Include=.${${EXTERNAL_PROJECT}}.>.*</SkipGetTargetFrameworkProperties>"
+ EndOfProjectReference
+ ${all_build}
+ )
+endmacro()
+
+set(external_project "external.project")
+project_reference(external_project)
+if(NOT ${EndOfProjectReference} MATCHES ".*</ProjectReference>")
+ set(RunCMake_TEST_FAILED "${test} is being set unexpectedly.")
+endif()
+
+set(external_project "external.csproj")
+project_reference(external_project)
+if(${EndOfProjectReference} MATCHES ".*</ProjectReference>")
+ set(RunCMake_TEST_FAILED "${test} is not set.")
+endif()
diff --git a/Tests/RunCMake/include_external_msproject/SkipGetTargetFrameworkProperties.cmake b/Tests/RunCMake/include_external_msproject/SkipGetTargetFrameworkProperties.cmake
new file mode 100644
index 0000000..f660bd0
--- /dev/null
+++ b/Tests/RunCMake/include_external_msproject/SkipGetTargetFrameworkProperties.cmake
@@ -0,0 +1,5 @@
+include_external_msproject(external1 external.project
+ GUID aaa-bbb-ccc-000)
+
+include_external_msproject(external2 external.csproj
+ GUID aaa-bbb-ccc-001)