Add .NET DLL for SDK projection to NuGet package#40182
Add .NET DLL for SDK projection to NuGet package#40182florelis wants to merge 1 commit intomicrosoft:feature/wsl-for-appsfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds support for shipping a C# projection DLL (wslcsdkcs.dll) in the Microsoft.WSL.Containers NuGet package, and updates build/targets logic so consumers get correct native asset layout and copy behavior.
Changes:
- Introduces a CMake helper (
configure_csharp_target) and a new C# CMake target forwslcsdkcs. - Updates NuGet package layout to place native binaries under
runtimes/win-<arch>/native/and adds new MSBuild targets fornet8.0. - Updates CMake package config and NuGet spec to reference the new locations and include the new managed DLL.
Reviewed changes
Copilot reviewed 11 out of 12 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| src/windows/wslsettings/CMakeLists.txt | Switches to shared C# target configuration helper and removes duplicated per-target settings. |
| src/windows/WslcSDK/csharp/Projection.cs | Adds placeholder C# source for the new projection DLL. |
| src/windows/WslcSDK/csharp/CMakeLists.txt | Adds new C# shared library target wslcsdkcs. |
| nuget/Microsoft.WSL.Containers/cmake/Microsoft.WSL.ContainersConfig.cmake | Updates imported DLL path to native/ subfolder. |
| nuget/Microsoft.WSL.Containers/build/net8.0/Microsoft.WSL.Containers.targets | Adds net8-specific copy logic (RID/PlatformTarget fallback) and erroring. |
| nuget/Microsoft.WSL.Containers/build/net/Microsoft.WSL.Containers.targets | Removes old net targets file. |
| nuget/Microsoft.WSL.Containers/build/native/Microsoft.WSL.Containers.targets | Updates native targets and attempts DLL copy via MSBuild items. |
| nuget/Microsoft.WSL.Containers/build/Microsoft.WSL.Containers.common.targets | Removes common targets file previously used for copying/erroring. |
| nuget/Microsoft.WSL.Containers.nuspec.in | Adds wslcsdkcs.dll and moves native DLLs under native/. |
| cmake/findCSharp.cmake | Adds configure_csharp_target() helper (C# flags + Windows SDK MSBuild properties). |
| CMakeLists.txt | Adds find_package(CSharp) and adds the new C# subdirectory build. |
| .gitignore | Normalizes *.etl entry and adds *.lscache. |
| set(TargetApp wslsettings) | ||
|
|
||
| project(${TargetApp} LANGUAGES CSharp) | ||
| configure_csharp_target(${TargetApp}) |
There was a problem hiding this comment.
configure_csharp_target() calls target_compile_options()/set_target_properties() on the passed target. In this file it’s invoked before the wslsettings CMake target is created, which will cause CMake configuration to fail. Move the configure_csharp_target(${TargetApp}) call to after the corresponding add_executable() / add_library() (or alter the helper to only set directory-level config until the target exists).
| @@ -0,0 +1,28 @@ | |||
| function(configure_csharp_target TARGET) | |||
| project(${TARGET} LANGUAGES CSharp) | |||
There was a problem hiding this comment.
Calling project() inside a helper function (and potentially multiple times across subdirectories/targets) has broad global side effects in CMake (e.g., resets project variables, may affect language enablement and toolchain behavior). Prefer enabling C# once at the top-level (e.g., enable_language(CSharp) after find_package(CSharp) or in the top-level project(...) LANGUAGES ... CSharp) and keep configure_csharp_target() limited to setting target properties/options.
| project(${TARGET} LANGUAGES CSharp) | |
| if(NOT CMAKE_CSharp_COMPILER) | |
| message(FATAL_ERROR | |
| "C# language is not enabled before calling configure_csharp_target(${TARGET}). " | |
| "Enable it once at the top level with project(... LANGUAGES CSharp) or enable_language(CSharp)." | |
| ) | |
| endif() |
| # Set the C# language version (defaults to 3.0). | ||
| set(CMAKE_CSharp_FLAGS "/langversion:latest") | ||
|
|
||
| target_compile_options( | ||
| ${TARGET} |
There was a problem hiding this comment.
set(CMAKE_CSharp_FLAGS ...) inside a CMake function only affects that function’s scope, so the language-version flag is unlikely to be applied to targets outside the function body (or to subsequent targets). Apply the language version via target_compile_options(${TARGET} PRIVATE \"/langversion:latest\"), or set the variable with PARENT_SCOPE/directory property if you truly intend it to be global.
| # Set the C# language version (defaults to 3.0). | |
| set(CMAKE_CSharp_FLAGS "/langversion:latest") | |
| target_compile_options( | |
| ${TARGET} | |
| # Set the C# language version (defaults to 3.0) for this target. | |
| target_compile_options( | |
| ${TARGET} | |
| PRIVATE "/langversion:latest" |
| find_package(VERSION REQUIRED) | ||
| find_package(MC REQUIRED) | ||
| find_package(Appx REQUIRED) | ||
| find_package(CSharp REQUIRED) |
There was a problem hiding this comment.
For CMake module-mode package discovery, find_package(CSharp) expects a module named FindCSharp.cmake. The PR adds cmake/findCSharp.cmake (lowercase 'f'), which will fail on case-sensitive filesystems. Rename the module to FindCSharp.cmake (and ensure it’s on CMAKE_MODULE_PATH).
| find_package(CSharp REQUIRED) | |
| if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/cmake/findCSharp.cmake") | |
| include("${CMAKE_CURRENT_LIST_DIR}/cmake/findCSharp.cmake") | |
| else() | |
| find_package(CSharp REQUIRED) | |
| endif() |
| <group targetFramework="net8.0" /> | ||
| </dependencies> | ||
| </metadata> | ||
| <files> | ||
| <file src="${CMAKE_SOURCE_DIR_NATIVE}\src\windows\WslcSDK\wslcsdk.h" target="include"/> | ||
| <file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\x64\Release\wslcsdkcs.dll" target="lib\net8.0"/> |
There was a problem hiding this comment.
The build configuration sets DOTNET_TARGET_FRAMEWORK to a Windows-specific TFM (e.g., net8.0-windows...), but the NuGet asset is being placed under lib\\net8.0 (and targets under build\\net8.0). This can lead to incorrect NuGet TFM selection/compatibility (e.g., allowing restore for non-Windows net8.0 projects) and mismatched asset resolution. Either (a) package under a Windows TFM folder (e.g., lib\\net8.0-windows... / build\\net8.0-windows...) consistent with what you build, or (b) change the build to actually target net8.0 if the assembly is platform-agnostic.
| <group targetFramework="net8.0" /> | |
| </dependencies> | |
| </metadata> | |
| <files> | |
| <file src="${CMAKE_SOURCE_DIR_NATIVE}\src\windows\WslcSDK\wslcsdk.h" target="include"/> | |
| <file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\x64\Release\wslcsdkcs.dll" target="lib\net8.0"/> | |
| <group targetFramework="net8.0-windows" /> | |
| </dependencies> | |
| </metadata> | |
| <files> | |
| <file src="${CMAKE_SOURCE_DIR_NATIVE}\src\windows\WslcSDK\wslcsdk.h" target="include"/> | |
| <file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\x64\Release\wslcsdkcs.dll" target="lib\net8.0-windows"/> |
| <group targetFramework="net8.0" /> | ||
| </dependencies> | ||
| </metadata> | ||
| <files> | ||
| <file src="${CMAKE_SOURCE_DIR_NATIVE}\src\windows\WslcSDK\wslcsdk.h" target="include"/> | ||
| <file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\x64\Release\wslcsdkcs.dll" target="lib\net8.0"/> |
There was a problem hiding this comment.
The build configuration sets DOTNET_TARGET_FRAMEWORK to a Windows-specific TFM (e.g., net8.0-windows...), but the NuGet asset is being placed under lib\\net8.0 (and targets under build\\net8.0). This can lead to incorrect NuGet TFM selection/compatibility (e.g., allowing restore for non-Windows net8.0 projects) and mismatched asset resolution. Either (a) package under a Windows TFM folder (e.g., lib\\net8.0-windows... / build\\net8.0-windows...) consistent with what you build, or (b) change the build to actually target net8.0 if the assembly is platform-agnostic.
| <group targetFramework="net8.0" /> | |
| </dependencies> | |
| </metadata> | |
| <files> | |
| <file src="${CMAKE_SOURCE_DIR_NATIVE}\src\windows\WslcSDK\wslcsdk.h" target="include"/> | |
| <file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\x64\Release\wslcsdkcs.dll" target="lib\net8.0"/> | |
| <group targetFramework="net8.0-windows" /> | |
| </dependencies> | |
| </metadata> | |
| <files> | |
| <file src="${CMAKE_SOURCE_DIR_NATIVE}\src\windows\WslcSDK\wslcsdk.h" target="include"/> | |
| <file src="${CMAKE_SOURCE_DIR_NATIVE}\bin\x64\Release\wslcsdkcs.dll" target="lib\net8.0-windows"/> |
| <ItemGroup> | ||
| <ReferenceCopyLocalPaths Include="$(MSBuildThisFileDirectory)..\..\runtimes\win-$(Platform)\native\wslcsdk.dll" /> | ||
| </ItemGroup> |
There was a problem hiding this comment.
ReferenceCopyLocalPaths is primarily used by managed build pipelines (RAR/CopyLocal) and typically won’t copy anything for native .vcxproj consumers. Also, $(Platform) is often ARM64 (uppercase) in VS, while the package folder is win-arm64 (lowercase), so the path can be wrong. For native projects, add an explicit MSBuild Target that copies the DLL to $(TargetDir) (or uses Content + CopyToOutputDirectory) and normalize/map platforms (e.g., ARM64 -> arm64, Win32 -> x86 if relevant).
| </Choose> | ||
|
|
||
| <Target Name="WSLCSDK_ErrorPlatform" BeforeTargets="PrepareForBuild" Condition="'$(_wslcSdkInvalidPlatform)' != ''"> | ||
| <Error Text="wslcsdk.dll could not be copied because the $(_wslcSdkInvalidPlatformProperty) '$(_wslcSdkInvalidPlatform)' is not supported." /> |
There was a problem hiding this comment.
The new error doesn’t indicate which values are supported. Consider including expected values in the message (e.g., mention supported RIDs *-x64/*-arm64 or PlatformTarget values x64/arm64) to reduce build-triage time.
Summary of the Pull Request
wslcsdkcs.dll, that will include the SDK projection for C#.PR Checklist
Detailed Description of the Pull Request / Additional comments
wslsettingstarget and reused for the newwslcsdkcs..targetsto use a proper TFM (net8.0instead ofnet), to check$(PlatformTarget)as a fallback when$(RuntimeIdentifier)is not set.runtimes\win-<arch>\toruntimes\win-<arch>\native\, where MSBuild knows to automatically reference and copy them for .NET projects using$(RuntimeIdentifier)Validation Steps Performed
Manually created C# projects and confirmed that the right files were being referenced and copied. More proper validation will come later in the form of sample apps.