Generating C# .NET6 Projects - Problems with DOTNET_SDK

I have a project with both C/C++ native code, and C# .NET code. We can currently generate C# projects in cmake which use the “old” style of csproj files and it works perfectly fine for .NET 4.8. E.g. set_target_properties(${this_target} PROPERTIES DOTNET_TARGET_FRAMEWORK_VERSION "v4.8")

We get the csproj files like:

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="17.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <PreferredToolArchitecture>x64</PreferredToolArchitecture>
  </PropertyGroup>
  <PropertyGroup Label="Globals">
...

rather than the “SDK” style csproj files:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup Label="Globals">
...

Now, we want to target .NET 6 instead.

If I try to just switch the framework (set_target_properties(${this_target} PROPERTIES DOTNET_TARGET_FRAMEWORK "net6.0"), I run into problems with NuGet restore and get a bunch of warnings in Visual Studio. Likely because I’m using the “old” style of csproj file, rather than the new “SDK” file.

I saw that CMake supports the SDK csproj files which seemed great!

set_target_properties(${this_target} PROPERTIES
    DOTNET_SDK "Microsoft.NET.Sdk"
    DOTNET_TARGET_FRAMEWORK "net6.0")

Unfortunately, this doesn’t support many other features that we also require. For example we currently use this

target_compile_options(${this_target} PUBLIC "/unsafe")
target_compile_options(${this_target} PUBLIC "/nowarn 7035")

With the old .NET, this generates some lines in the csproj like:

    <AdditionalOptions>"/nowarn 7035"</AdditionalOptions> <!-- note that visual studio normally uses code like <NoWarn>7035</NoWarn>, but this also works -->
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>

With the DOTNET_SDK these are completely absent.

Similarly, we use this to target x64 rather than AnyCPU (which we need for calling into native DLL’s)

    set(CMAKE_CSharp_FLAGS "${CMAKE_CSharp_FLAGS} /platform:x64 /langversion:latest")

And previously that would generate:

    <PlatformTarget>x64</PlatformTarget>

That no longer works, which would be a problem for our project.

Finally, we use add_custom_command in our current .NET4.8 projects to copy native DLL’s from the C/C++ projects in order to p/invoke into those DLL’s. I understand that is not yet working according to the documentation, but I could not figure out another way to copy these DLL’s from a native target to the output of a given managed target without the custom command (though perhaps we can solve that with a dummy project, I’m willing to do a work-around like that unless there is a better solution).

So my question is, are there plans to bring the DOTNET_SDK option up to parity with the old csproj generator?

In summary, DOTNET_SDK type projects are missing:

  • A way to set PlatformTarget to x64
  • Support for compiler options (like “unsafe” or other flags like “nowarn”)
  • A way to copy additional files

Are there plans to address these gaps?

Well I looked through the source code and found what I was missing. If I just set the target property VS_GLOBAL_xxx yyy it translates to <xxx>yyy</xxx> in the csproj file!

There are a few things I’ve seen in .csproj files that also have xml attributes, which I wouldn’t be able to set this way, but they are not blockers for me.

As for copying additional files without the custom commands, I’ve resorted to just making a dummy csproj that does the copying and adding it to the solution with include_external_msproject. That feels like a hack but I can live with it.

Would still like for some of the old behavior, like compiler options translating to csproj properties where possible, but this works for now.