summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSumit Bhardwaj <bhardwajs@outlook.com>2021-12-15 08:21:34 -0800
committerSumit Bhardwaj <bhardwajs@outlook.com>2021-12-21 09:35:49 -0800
commit0eea32a376fc54b198fa4690ca57b829a2d14baa (patch)
treec786935ed240c0857c0e82d87ffc27149fdade33
parenta450cc9533ac8a54d14ec5e0cbf6b379a2014e7a (diff)
downloadcmake-0eea32a376fc54b198fa4690ca57b829a2d14baa.tar.gz
VS: Add DOTNET_SDK property to generate SDK-style C# projects
Changes in cmVisualStudio10TargetGenerator::Generate to write .Net SDK-style project for VS generators VS 19 and above. Also adds documentation and tests. Issue: #20227
-rw-r--r--Auxiliary/vim/syntax/cmake.vim2
-rw-r--r--Help/manual/cmake-properties.7.rst1
-rw-r--r--Help/manual/cmake-variables.7.rst1
-rw-r--r--Help/prop_tgt/DOTNET_SDK.rst25
-rw-r--r--Help/release/dev/vs-csharp-dotnet-sdk.rst9
-rw-r--r--Help/variable/CMAKE_DOTNET_SDK.rst9
-rw-r--r--Source/cmGeneratorTarget.cxx5
-rw-r--r--Source/cmGeneratorTarget.h2
-rw-r--r--Source/cmGlobalVisualStudio7Generator.cxx10
-rw-r--r--Source/cmTarget.cxx4
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx119
-rw-r--r--Source/cmVisualStudio10TargetGenerator.h3
-rw-r--r--Tests/RunCMake/CMakeLists.txt4
-rw-r--r--Tests/RunCMake/VsDotnetSdk/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/VsDotnetSdk/DotnetSdkVariables-check.cmake52
-rw-r--r--Tests/RunCMake/VsDotnetSdk/DotnetSdkVariables.cmake14
-rw-r--r--Tests/RunCMake/VsDotnetSdk/RunCMakeTest.cmake17
-rw-r--r--Tests/RunCMake/VsDotnetSdk/VsDotnetSdk.cmake18
-rw-r--r--Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsSource-result.txt0
-rw-r--r--Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsSource-stderr.txt7
-rw-r--r--Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsSource.cmake15
-rw-r--r--Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsTarget-result.txt0
-rw-r--r--Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsTarget-stderr.txt7
-rw-r--r--Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsTarget.cmake12
-rw-r--r--Tests/RunCMake/VsDotnetSdk/csharponly.cs11
-rw-r--r--Tests/RunCMake/VsDotnetSdk/lib1.cs10
26 files changed, 357 insertions, 3 deletions
diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim
index 52330f7c51..c6c5d23adb 100644
--- a/Auxiliary/vim/syntax/cmake.vim
+++ b/Auxiliary/vim/syntax/cmake.vim
@@ -152,6 +152,7 @@ syn keyword cmakeProperty contained
\ DISABLED
\ DISABLED_FEATURES
\ DISABLE_PRECOMPILE_HEADERS
+ \ DOTNET_SDK
\ DOTNET_TARGET_FRAMEWORK
\ DOTNET_TARGET_FRAMEWORK_VERSION
\ ECLIPSE_EXTRA_CPROJECT_CONTENTS
@@ -1001,6 +1002,7 @@ syn keyword cmakeVariable contained
\ CMAKE_DIRECTORY_LABELS
\ CMAKE_DISABLE_PRECOMPILE_HEADERS
\ CMAKE_DL_LIBS
+ \ CMAKE_DOTNET_SDK
\ CMAKE_DOTNET_TARGET_FRAMEWORK
\ CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION
\ CMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index 5e18e10748..73e57d1985 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -191,6 +191,7 @@ Properties on Targets
/prop_tgt/DEPLOYMENT_REMOTE_DIRECTORY
/prop_tgt/DEPRECATION
/prop_tgt/DISABLE_PRECOMPILE_HEADERS
+ /prop_tgt/DOTNET_SDK
/prop_tgt/DOTNET_TARGET_FRAMEWORK
/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION
/prop_tgt/EchoString
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 3c50117d32..13704c5029 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -49,6 +49,7 @@ Variables that Provide Information
/variable/CMAKE_DEBUG_TARGET_PROPERTIES
/variable/CMAKE_DIRECTORY_LABELS
/variable/CMAKE_DL_LIBS
+ /variable/CMAKE_DOTNET_SDK
/variable/CMAKE_DOTNET_TARGET_FRAMEWORK
/variable/CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION
/variable/CMAKE_EDIT_COMMAND
diff --git a/Help/prop_tgt/DOTNET_SDK.rst b/Help/prop_tgt/DOTNET_SDK.rst
new file mode 100644
index 0000000000..ca1dcaca9a
--- /dev/null
+++ b/Help/prop_tgt/DOTNET_SDK.rst
@@ -0,0 +1,25 @@
+DOTNET_SDK
+----------
+
+.. versionadded:: 3.23
+
+Specify the .NET SDK for C# projects. For example: ``Microsoft.NET.Sdk``.
+
+This property tells :ref:`Visual Studio Generators` for VS 2019 and
+above to generate a .NET SDK-style project using the specified SDK.
+The property is meaningful only to these generators, and only in C#
+targets. It is ignored for C++ projects, even if they are managed
+(e.g. using :prop_tgt:`COMMON_LANGUAGE_RUNTIME`).
+
+This property must be a non-empty string to generate .NET SDK-style projects.
+CMake does not perform any validations for the value of the property.
+
+This property may be initialized for all targets using the
+:variable:`CMAKE_DOTNET_SDK` variable.
+
+.. note::
+
+ The :ref:`Visual Studio Generators` in this version of CMake have not
+ yet learned to support :command:`add_custom_command` in .NET SDK-style
+ projects. It is currently an error to attach a custom command to a
+ target with the ``DOTNET_SDK`` property set.
diff --git a/Help/release/dev/vs-csharp-dotnet-sdk.rst b/Help/release/dev/vs-csharp-dotnet-sdk.rst
new file mode 100644
index 0000000000..cc0ebe474a
--- /dev/null
+++ b/Help/release/dev/vs-csharp-dotnet-sdk.rst
@@ -0,0 +1,9 @@
+vs-csharp-dotnet-sdk
+--------------------
+
+* The :ref:`Visual Studio Generators` for VS 2019 and above learned to
+ support .NET SDK-style project files (``.csproj``) for C# projects.
+ See the :prop_tgt:`DOTNET_SDK` target property and corresponding
+ :variable:`CMAKE_DOTNET_SDK` variable.
+ However, this version of CMake does not yet support using
+ :command:`add_custom_command` in .NET SDK-style projects.
diff --git a/Help/variable/CMAKE_DOTNET_SDK.rst b/Help/variable/CMAKE_DOTNET_SDK.rst
new file mode 100644
index 0000000000..dc8806af96
--- /dev/null
+++ b/Help/variable/CMAKE_DOTNET_SDK.rst
@@ -0,0 +1,9 @@
+CMAKE_DOTNET_SDK
+----------------
+
+.. versionadded:: 3.23
+
+Default value for :prop_tgt:`DOTNET_SDK` property of targets.
+
+This variable is used to initialize the :prop_tgt:`DOTNET_SDK`
+property on all targets. See that target property for additional information.
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index e539e1de6e..c54bd15dd2 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -7719,6 +7719,11 @@ bool cmGeneratorTarget::IsCSharpOnly() const
return languages.size() == 1 && languages.count("CSharp") > 0;
}
+bool cmGeneratorTarget::IsDotNetSdkTarget() const
+{
+ return !this->GetProperty("DOTNET_SDK").IsEmpty();
+}
+
void cmGeneratorTarget::ComputeLinkImplementationLanguages(
const std::string& config, cmOptionalLinkImplementation& impl) const
{
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index eff5253248..76458bd9d9 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -431,6 +431,8 @@ public:
bool IsCSharpOnly() const;
+ bool IsDotNetSdkTarget() const;
+
void GetObjectLibrariesCMP0026(
std::vector<cmGeneratorTarget*>& objlibs) const;
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index b3f8d9057b..c72b10957d 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -373,8 +373,16 @@ void cmGlobalVisualStudio7Generator::WriteTargetConfigurations(
this->IsPartOfDefaultBuild(configs, projectTargets, target);
cmValue vcprojName = target->GetProperty("GENERATOR_FILE_NAME");
if (vcprojName) {
+ std::string mapping;
+
+ // On VS 19 and above, always map .NET SDK projects to "Any CPU".
+ if (target->IsDotNetSdkTarget() &&
+ this->GetVersion() >= VSVersion::VS16 &&
+ !this->IsReservedTarget(target->GetName())) {
+ mapping = "Any CPU";
+ }
this->WriteProjectConfigurations(fout, *vcprojName, *target, configs,
- configsPartOfDefaultBuild);
+ configsPartOfDefaultBuild, mapping);
}
}
}
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index ebf5bd0aa3..f384463651 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -525,6 +525,10 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
this->impl->PolicyMap.Set(cmPolicies::CMP0022, cmPolicies::NEW);
}
+ if (!this->IsImported()) {
+ initProp("DOTNET_SDK");
+ }
+
if (this->impl->TargetType <= cmStateEnums::GLOBAL_TARGET) {
initProp("DOTNET_TARGET_FRAMEWORK");
initProp("DOTNET_TARGET_FRAMEWORK_VERSION");
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 6f6b0a6791..ddfe24dc85 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -406,7 +406,14 @@ void cmVisualStudio10TargetGenerator::Generate()
char magic[] = { char(0xEF), char(0xBB), char(0xBF) };
BuildFileStream.write(magic, 3);
- this->WriteClassicMsBuildProjectFile(BuildFileStream);
+ if (this->Managed && this->ProjectType == VsProjectType::csproj &&
+ this->GeneratorTarget->IsDotNetSdkTarget() &&
+ this->GlobalGenerator->GetVersion() >=
+ cmGlobalVisualStudioGenerator::VS16) {
+ this->WriteSdkStyleProjectFile(BuildFileStream);
+ } else {
+ this->WriteClassicMsBuildProjectFile(BuildFileStream);
+ }
if (BuildFileStream.Close()) {
this->GlobalGenerator->FileReplacedDuringGenerate(PathToProjectFile);
@@ -468,7 +475,7 @@ void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile(
// build fails.
// Setting ResolveNugetPackages to false skips this target and the build
// succeeds.
- std::string_view targetName{ this->GeneratorTarget->Target->GetName() };
+ cm::string_view targetName{ this->GeneratorTarget->GetName() };
if (targetName == "ALL_BUILD" ||
targetName == CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
Elem e1(e0, "PropertyGroup");
@@ -822,6 +829,96 @@ void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile(
}
}
+void cmVisualStudio10TargetGenerator::WriteSdkStyleProjectFile(
+ cmGeneratedFileStream& BuildFileStream)
+{
+ if (!this->Managed || this->ProjectType != VsProjectType::csproj ||
+ !this->GeneratorTarget->IsDotNetSdkTarget()) {
+ std::string message = "The target \"" + this->GeneratorTarget->GetName() +
+ "\" is not eligible for .Net SDK style project.";
+ this->Makefile->IssueMessage(MessageType::INTERNAL_ERROR, message);
+ return;
+ }
+
+ if (this->HasCustomCommands()) {
+ std::string message = "The target \"" + this->GeneratorTarget->GetName() +
+ "\" does not currently support add_custom_command as the Visual Studio "
+ "generators have not yet learned how to generate custom commands in "
+ ".Net SDK-style projects.";
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, message);
+ return;
+ }
+
+ Elem e0(BuildFileStream, "Project");
+ e0.Attribute("Sdk", *this->GeneratorTarget->GetProperty("DOTNET_SDK"));
+
+ {
+ Elem e1(e0, "PropertyGroup");
+ this->WriteCommonPropertyGroupGlobals(e1);
+
+ e1.Element("EnableDefaultItems", "false");
+ // Disable the project upgrade prompt that is displayed the first time a
+ // project using an older toolset version is opened in a newer version
+ // of the IDE.
+ e1.Element("VCProjectUpgraderObjectName", "NoUpgrade");
+ e1.Element("ManagedAssembly", "true");
+
+ cmValue targetFramework =
+ this->GeneratorTarget->GetProperty("DOTNET_TARGET_FRAMEWORK");
+ if (targetFramework) {
+ if (targetFramework->find(';') != std::string::npos) {
+ e1.Element("TargetFrameworks", *targetFramework);
+ } else {
+ e1.Element("TargetFramework", *targetFramework);
+ }
+ } else {
+ e1.Element("TargetFramework", "net5.0");
+ }
+
+ std::string outputType;
+ switch (this->GeneratorTarget->GetType()) {
+ case cmStateEnums::OBJECT_LIBRARY:
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Target \"", this->GeneratorTarget->GetName(),
+ "\" is of a type not supported for managed binaries."));
+ return;
+ case cmStateEnums::SHARED_LIBRARY:
+ outputType = "Library";
+ break;
+ case cmStateEnums::EXECUTABLE: {
+ auto const win32 =
+ this->GeneratorTarget->GetSafeProperty("WIN32_EXECUTABLE");
+ if (win32.find("$<") != std::string::npos) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Target \"", this->GeneratorTarget->GetName(),
+ "\" has a generator expression in its WIN32_EXECUTABLE "
+ "property. This is not supported on managed "
+ "executables."));
+ return;
+ }
+ outputType = "Exe";
+ } break;
+ case cmStateEnums::UTILITY:
+ case cmStateEnums::INTERFACE_LIBRARY:
+ case cmStateEnums::GLOBAL_TARGET:
+ outputType = "Utility";
+ break;
+ case cmStateEnums::UNKNOWN_LIBRARY:
+ break;
+ }
+ e1.Element("OutputType", outputType);
+ }
+
+ this->WriteDotNetDocumentationFile(e0);
+ this->WriteAllSources(e0);
+ this->WritePackageReferences(e0);
+ this->WriteProjectReferences(e0);
+}
+
void cmVisualStudio10TargetGenerator::WriteCommonPropertyGroupGlobals(Elem& e1)
{
e1.Attribute("Label", "Globals");
@@ -873,6 +970,24 @@ void cmVisualStudio10TargetGenerator::WriteCommonPropertyGroupGlobals(Elem& e1)
}
}
+bool cmVisualStudio10TargetGenerator::HasCustomCommands() const
+{
+ if (!this->GeneratorTarget->GetPreBuildCommands().empty() ||
+ !this->GeneratorTarget->GetPreLinkCommands().empty() ||
+ !this->GeneratorTarget->GetPostBuildCommands().empty()) {
+ return true;
+ }
+
+ for (cmGeneratorTarget::AllConfigSource const& si :
+ this->GeneratorTarget->GetAllConfigSources()) {
+ if (si.Source->GetCustomCommand()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void cmVisualStudio10TargetGenerator::WritePackageReferences(Elem& e0)
{
std::vector<std::string> packageReferences;
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index 83e8ee1558..37b8dfd125 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -263,10 +263,13 @@ private:
// .Net SDK-stype project variable and helper functions
void WriteClassicMsBuildProjectFile(cmGeneratedFileStream& BuildFileStream);
+ void WriteSdkStyleProjectFile(cmGeneratedFileStream& BuildFileStream);
void WriteCommonPropertyGroupGlobals(
cmVisualStudio10TargetGenerator::Elem& e1);
+ bool HasCustomCommands() const;
+
std::unordered_map<std::string, ConfigToSettings> ParsedToolTargetSettings;
bool PropertyIsSameInAllConfigs(const ConfigToSettings& toolSettings,
const std::string& propName);
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 5dc7031b97..dec147b9a1 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -616,6 +616,10 @@ if("${CMAKE_GENERATOR}" MATCHES "Visual Studio ([^9]|9[0-9])")
endif()
endif()
+if(CMAKE_GENERATOR MATCHES "^Visual Studio (1[6-9]|[2-9][0-9])")
+ add_RunCMake_test(VsDotnetSdk)
+endif()
+
if(XCODE_VERSION)
add_RunCMake_test(XcodeProject -DXCODE_VERSION=${XCODE_VERSION})
add_RunCMake_test(XcodeProject-Embed -DXCODE_VERSION=${XCODE_VERSION})
diff --git a/Tests/RunCMake/VsDotnetSdk/CMakeLists.txt b/Tests/RunCMake/VsDotnetSdk/CMakeLists.txt
new file mode 100644
index 0000000000..e597708ff8
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.22.0)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/VsDotnetSdk/DotnetSdkVariables-check.cmake b/Tests/RunCMake/VsDotnetSdk/DotnetSdkVariables-check.cmake
new file mode 100644
index 0000000000..7a5cd1d789
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/DotnetSdkVariables-check.cmake
@@ -0,0 +1,52 @@
+set(files foo.csproj bar.csproj baz.csproj)
+
+set(inLib1 FALSE)
+set(dotnetSdkInLib1 FALSE)
+
+set(inLib2 FALSE)
+set(dotnetSdkWebInLib2 FALSE)
+
+set(inLib3 FALSE)
+set(classicProjInLib3 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 "<Project Sdk=\"Microsoft\.NET\.Sdk\">")
+ set(dotnetSdkInLib1 TRUE)
+ set(inLib1 TRUE)
+ endif()
+ elseif(NOT inLib2)
+ if(line MATCHES "<Project Sdk=\"Microsoft\.NET\.Sdk\.Web\">")
+ set(dotnetSdkWebInLib2 TRUE)
+ set(inLib2 TRUE)
+ endif()
+ elseif(NOT inLib3)
+ if(line MATCHES "<Project DefaultTargets=\"Build\" ToolsVersion=\"")
+ set(classicProjInLib3 TRUE)
+ set(inLib3 TRUE)
+ endif()
+ endif()
+ endforeach()
+endforeach()
+
+if(NOT dotnetSdkInLib1)
+ set(RunCMake_TEST_FAILED ".Net SDK not set correctly.")
+endif()
+
+if(NOT dotnetSdkWebInLib2)
+ set(RunCMake_TEST_FAILED ".Net Web SDK not set correctly.")
+endif()
+
+if(NOT classicProjInLib3)
+ set(RunCMake_TEST_FAILED "Empty DOTNET_SDK doesn't build Classic project.")
+endif()
diff --git a/Tests/RunCMake/VsDotnetSdk/DotnetSdkVariables.cmake b/Tests/RunCMake/VsDotnetSdk/DotnetSdkVariables.cmake
new file mode 100644
index 0000000000..f080edd3d2
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/DotnetSdkVariables.cmake
@@ -0,0 +1,14 @@
+enable_language(CSharp)
+
+if(NOT CMAKE_CSharp_COMPILER)
+ return()
+endif()
+
+set(CMAKE_DOTNET_SDK "Microsoft.NET.Sdk")
+add_library(foo SHARED lib1.cs)
+
+set(CMAKE_DOTNET_SDK "Microsoft.NET.Sdk.Web")
+add_library(bar SHARED lib1.cs)
+
+set(CMAKE_DOTNET_SDK "")
+add_library(baz SHARED lib1.cs)
diff --git a/Tests/RunCMake/VsDotnetSdk/RunCMakeTest.cmake b/Tests/RunCMake/VsDotnetSdk/RunCMakeTest.cmake
new file mode 100644
index 0000000000..b174c25a35
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/RunCMakeTest.cmake
@@ -0,0 +1,17 @@
+cmake_policy(SET CMP0053 NEW)
+include(RunCMake)
+
+run_cmake(VsDotnetSdkCustomCommandsTarget)
+run_cmake(VsDotnetSdkCustomCommandsSource)
+run_cmake(DotnetSdkVariables)
+
+function(run_VsDotnetSdk)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/VsDotnetSdk-build)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+ file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+ run_cmake(VsDotnetSdk)
+ set(build_flags /restore)
+ run_cmake_command(VsDotnetSdk-build ${CMAKE_COMMAND} --build . -- ${build_flags})
+endfunction()
+run_VsDotnetSdk()
diff --git a/Tests/RunCMake/VsDotnetSdk/VsDotnetSdk.cmake b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdk.cmake
new file mode 100644
index 0000000000..60066ab401
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdk.cmake
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.22)
+
+# a simple CSharp only test case
+project (DotNetSdk CSharp)
+
+set(CMAKE_DOTNET_TARGET_FRAMEWORK net472)
+set(CMAKE_DOTNET_SDK "Microsoft.NET.Sdk")
+
+add_library(dotNetSdkLib1 SHARED lib1.cs)
+set_target_properties(dotNetSdkLib1
+ PROPERTIES
+ VS_GLOBAL_RuntimeIdentifier win10-x64)
+
+add_executable(DotNetSdk csharponly.cs)
+target_link_libraries(DotNetSdk dotNetSdkLib1)
+set_target_properties(DotNetSdk
+ PROPERTIES
+ VS_GLOBAL_RuntimeIdentifier win10-x64)
diff --git a/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsSource-result.txt b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsSource-result.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsSource-result.txt
diff --git a/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsSource-stderr.txt b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsSource-stderr.txt
new file mode 100644
index 0000000000..90af627f3d
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsSource-stderr.txt
@@ -0,0 +1,7 @@
+CMake Error in CMakeLists.txt:
+ The target "foo" does not currently support add_custom_command as the
+ Visual Studio generators have not yet learned how to generate custom
+ commands in .Net SDK-style projects.
+
+
+CMake Generate step failed. Build files cannot be regenerated correctly.
diff --git a/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsSource.cmake b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsSource.cmake
new file mode 100644
index 0000000000..af18946034
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsSource.cmake
@@ -0,0 +1,15 @@
+enable_language(CSharp)
+
+if(NOT CMAKE_CSharp_COMPILER)
+ return()
+endif()
+
+set(CMAKE_DOTNET_SDK "Microsoft.NET.Sdk")
+add_custom_command(
+ OUTPUT bar.cs
+ COMMAND copy /A ${CMAKE_CURRENT_SOURCE_DIR}/lib1.cs
+ bar.cs
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/lib1.cs
+ VERBATIM)
+
+add_library(foo SHARED bar.cs)
diff --git a/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsTarget-result.txt b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsTarget-result.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsTarget-result.txt
diff --git a/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsTarget-stderr.txt b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsTarget-stderr.txt
new file mode 100644
index 0000000000..90af627f3d
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsTarget-stderr.txt
@@ -0,0 +1,7 @@
+CMake Error in CMakeLists.txt:
+ The target "foo" does not currently support add_custom_command as the
+ Visual Studio generators have not yet learned how to generate custom
+ commands in .Net SDK-style projects.
+
+
+CMake Generate step failed. Build files cannot be regenerated correctly.
diff --git a/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsTarget.cmake b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsTarget.cmake
new file mode 100644
index 0000000000..f5cd3174eb
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsTarget.cmake
@@ -0,0 +1,12 @@
+enable_language(CSharp)
+
+if(NOT CMAKE_CSharp_COMPILER)
+ return()
+endif()
+
+set(CMAKE_DOTNET_SDK "Microsoft.NET.Sdk")
+add_library(foo SHARED lib1.cs)
+add_custom_command(TARGET foo
+ PRE_BUILD
+ COMMAND echo "This shouldn't happen!"
+ VERBATIM)
diff --git a/Tests/RunCMake/VsDotnetSdk/csharponly.cs b/Tests/RunCMake/VsDotnetSdk/csharponly.cs
new file mode 100644
index 0000000000..f02e8a31f0
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/csharponly.cs
@@ -0,0 +1,11 @@
+namespace CSharpOnly
+{
+ class CSharpOnly
+ {
+ public static void Main(string[] args)
+ {
+ int val = Lib1.getResult();
+ return;
+ }
+ }
+}
diff --git a/Tests/RunCMake/VsDotnetSdk/lib1.cs b/Tests/RunCMake/VsDotnetSdk/lib1.cs
new file mode 100644
index 0000000000..7a7ae1036a
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/lib1.cs
@@ -0,0 +1,10 @@
+namespace CSharpOnly
+{
+ public class Lib1
+ {
+ public static int getResult()
+ {
+ return 23;
+ }
+ }
+}