An insane hack to inject runtime assets into deps.json by injecting RuntimeTargetsCopyLocalItems
items into the GenerateDepsFile
task.
This library can be obtained via NuGet.
By default (without DllImportSearchPath.AssemblyDirectory
), the .NET runtime only loads native DLLs listed in the deps.json of an application. There is a long-standing issue: deps.json does not list native DLLs from reference projects (only native DLLs from NuGet packages), which means that such native DLLs cannot be loaded:
- dotnet/sdk#765 Copy runtime libraries from references project
- dotnet/sdk#1088 Allow runtime-specific assets in the project
- dotnet/sdk#24708 Architecture-specific folders like runtimes//native/ outside of NuGet packages [nativeinterop]
So, if you develop a library containing native DLLs, you get stuck. The test projects and sample projects will project-reference the library project, which does not work!
Again, this is an insane hack that plays with the implementation details deep inside the .NET SDK. It is likely that this will break even by a minor version update of the .NET SDK.
Tested on the following versions of the .NET SDK:
- 6.0.301
List the native files as InjectNativeFileDepsHack
items in your application project (not your library project).
Notes:
- Normally you list the native DLLs as
Content
items in the library project, so the native DLLs should be copied into$(OutputPath)
. - You cannot use wildcards in
Include
to list files within output directories because these wildcards are evaluated before the build starts and thus output files are not yet built (such a wildcard will break clean builds).
<ItemGroup>
<PackageReference Include="Asmichi.InjectNativeFileDepsHack" Version="0.2.0" PrivateAssets="all" IncludeAssets="runtime;build;native;contentfiles;analyzers" />
</ItemGroup>
<ItemGroup>
<InjectNativeFileDepsHack Include="$(OutputPath)runtimes\linux-x64\native\libMyAwesomeLibrary.so">
<!-- The relative path of the deployed directory from the application directory. -->
<DestinationSubDirectory>runtimes\linux-x64\native</DestinationSubDirectory>
<!-- RID -->
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
</InjectNativeFileDepsHack>
</ItemGroup>
See sample for a minimal example. To run the sample, on an x64 Linux system, run:
(cd sample; ./build_and_run.sh)
See https://github.com/asmichi/ChildProcess/blob/master/build/msbuild/InjectChildProcessNativeFileDeps.targets and its usage.
Basically, it tricks the deps.json generation process into treating the specified native DLLs as the runtime assets of the Asmichi.InjectNativeFileDepsHack
NuGet library.
The runtimeTargets
items (assetType
== native
) of a library comes from RuntimeLibray.NativeLibraryGroups
. Looking into the target, GenerateDepsFile
and DependencyContextBuilder
for clues of how NativeLibraryGroups
are collected, you will notice that a project
type library always have empty NativeLibraryGroups
. So, there is no way to add runtimeTargets
items into a project
type library. Absolutely no way! Only NuGet libraries!
NuGet runtime files are collected by ResolvePackageAssets
as RuntimeTargetsCopyLocalItems
. Asmichi.InjectNativeFileDepsHack
adds the specified native DLLs as RuntimeTargetsCopyLocalItems
items just before GenerateDepsFile
runs, hence they appear as runtimeTargets
items of the Asmichi.InjectNativeFileDepsHack
NuGet library.