-
Notifications
You must be signed in to change notification settings - Fork 257
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
csproj: document how to properly pack platform-specific native assemblies #6645
Comments
Also relevant is #3931 and #4837 (comment). |
@karann-msft can you please take a look at this issue? |
@nkolev92 maybe you can provide more context on how this can be solved |
@PatoBeltran To me the greatest problem was the information that is scattered. I also came quickly around the documentation @yatli refers to, but it didn't spark the lightbulb immediately. Partially because I didn't first understand there's a difference with the new reference method and how it's done before that and that one really needs a |
@PatoBeltran just like @veikkoeeva mentioned, the information is too fragmented and it is very hard to pull the pieces together. You see, even though I have looked directly at the source code and completely understand how to proceed, I tried to reverse engineer a valid search query for the answer that I already know, and I failed. |
Any kind of official information on this would be highly welcome. |
Cross-referencing #5910. Basically the same issue. |
After some testing, it seems that for corefx the RID fallback mechanism works as expected (e.g. win7-x86 -> win-x86 -> win -> any). But for netfx you need to specify the exact same RID in the .csproj that appears in the nuget package under Instead, without RID specified, corefx copies the whole |
Hi, I'm trying to include MRAA to a NetStandard project. <?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard1.1;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<Content CopyToOutputDirectory="PreserveNewest" Include="runtimes/linux-arm/native/libmraa.so" Link="libmraa.so" Pack="true" PackagePath="runtimes/linux-arm/native/libmraa.so" />
<Content CopyToOutputDirectory="PreserveNewest" Include="runtimes/linux-arm/native/libmraa.so.2" Link="libmraa.so.2" Pack="true" PackagePath="runtimes/linux-arm/native/libmraa.so.2" />
<Content CopyToOutputDirectory="PreserveNewest" Include="runtimes/linux-arm/native/libmraa.so.2.0.0" Link="libmraa.so.2.0.0" Pack="true" PackagePath="runtimes/linux-arm/native/libmraa.so.2.0.0"/>
<Content CopyToOutputDirectory="PreserveNewest" Include="runtimes/linux-x64/native/libmraa.so" Link="libmraa.so" Pack="true" PackagePath="runtimes/linux-x64/native/libmraa.so" />
<Content CopyToOutputDirectory="PreserveNewest" Include="runtimes/linux-x64/native/libmraa.so.2" Link="libmraa.so.2" Pack="true" PackagePath="runtimes/linux-x64/native/libmraa.so.2" />
<Content CopyToOutputDirectory="PreserveNewest" Include="runtimes/linux-x64/native/libmraa.so.2.0.0" Link="libmraa.so.2.0.0" Pack="true" PackagePath="runtimes/linux-x64/native/libmraa.so.2.0.0"/>
</ItemGroup>
</Project> And I'm using this: If libmraa is installed, all the code works well, but i want to create a Package that include the precompiled mraa and the SO doesn't have libmraa installed it says: File not found. |
@deinok you don't need to copy the assemblies to the output folder. and, maybe try launching the program with: |
I will try the LD_DEBUG and try to figure what is happening and report back |
Okey, problem was: Using [DllImport("mraa")] |
@deinok maybe too late but I still want to share the info -- the Say you have "foo.dll" -- [DllImport("foo")] -- OK! |
This is sorely needed. I'm trying to figure out how to get C++/CLI projects to work smoothly with How should I be packaging native and C++/CLI assemblies? How am I meant to reference them from other projects? What if there is a chain of package dependencies sitting between the package containing the native assembly and the consuming project? Are we meant to build 'fat' packages, or is this even supported? What happens in situations where your projects are using a mixture of |
Just for reference, a working solution for simple multi-platform support is shown here. With The libraries are then simply invoked via DllImport, with @rossng, I guess once one of the packages containing the native libs is referenced in your project (e.g. via Regarding the actual problem: From your post it is not clear if you are simply building the project or if you are publishing it. If you are building it, no libs are copied but referenced from the central Nuget folder ( |
Do you know how this works with C++/CLI? I suppose this isn't technically a native lib question, though it's similar in the sense that you are bundling some non-C# assemblies into a package - let me know if it's better to ask elsewhere. The reason I'm asking this is that I have some (non-shareable) packages which include both native DLLs and C++/CLI assemblies. I want to be able to use There's some automagic that allows you to use classes defined in a C++/CLI project just by adding a
I'm then publishing this wrapper project to a local repository. Unfortunately the the
But My choice of |
How are you publishing the C# project? Are you using something like Or are you simply generating a nuget package on build (which is not 'publishing')? I am a little confused because I don't know where in a publish step a nuspec file is created. Only if you create a nuget package, a nuspec file is generated within the package itself. Or do you mean the nuspec file in the obj folder which is generated with Referenced projects and their files are put into the publish folder only during a real publish process (e.g. using The alternative would be to not use project references at all and only use package references during development. But this is no fun if you update the depending projects: You need to upload package, wait for it to be published (15 mins or so), then install the new version in the main project. Also this prevents usage of nuget in combination with CI pipelines like AppVeyor because the packages would get different version numbers. But back to your problem: I have no idea how to get your Edit: Like I did in the project referenced in my previous post. I have a SOEM.PInvoke project that simply P/Invokes into a native DLL and I have an EtherCAT.NET project that depends on SOEM.PInvoke. Both packages are uploaded simultaneously to NuGet (see the dependency chain here). |
Apologies, yes - I mean generating a NuGet package on build, and the I'll experiment with packaging the C++/CLI and the C# wrapper separately. |
I thought I have graduated from this issue... |
This question is still plaguing me. Is there any good documentation on the topic? |
@Wes-Kuegler I subscribed to this issue to get updates. I wouldn't consider a doc, but I made some progress shipping platform-specific binaries on PlaywrightSharp. I shared what I learned here https://www.hardkoded.com/blog/playwright-sharp-monthly-dec-2020 |
Folks, do you have any updates on this? There are some solutions here and there, but they mostly focus on later versions of .NET. We are an SDK (Microsoft.Identity.Client) and need support for all .NET Fx 4.6.1+ .NET Core 3.1 + and NetStandard. The NET Fx seems problematic. |
To add what I learned this week: It's possible to target net47/8 and netstandard2.0 with native DLLs in a single project without using a nuspec file. I did have to include a targets file for the net47 portion. The csproj file contains this line to achieve that: <None Include="NLoptNet.targets" Pack="true" PackagePath="build/net47">... in addition to all the native dlls being copied to the runtimes folder. Notice the use of "build/" there, which thing seems to be undocumented. And the targets file includes lines that look like this: <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Condition="$([MSBuild]::IsOSPlatform('Windows'))">
<None Include="$(MSBuildThisFileDirectory)..\..\runtimes\win-x64\native\nlopt.dll" Condition="'$(Platform)'!='x86'">
<Link>nlopt_x64.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
... Hence, there is only a single copy of each DLL embedded in the package. I'm unsure about the use of MSBuildThisFileDirectory and wondering if there is a better way to get the folder where the package is installed. I don't have a good solution for unit testing the package project, but this kind of code in a static constructor can help on the far end: AssemblyLoadContext.Default.ResolvingUnmanagedDll += (assembly, name) =>
{
var rid = RuntimeInformation.RuntimeIdentifier;
rid = Regex.Replace(rid, @"\d+-", @"-"); // drop version specificity
var ext = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "dll" : "so";
NativeLibrary.TryLoad($"runtimes/{rid}/native/{name}.{ext}", out var handle);
return handle;
}; I'm not sure what the equivalent of that is in a pre-net6 world. It looks like .net6 can load DLLs with alternative names, which would be really useful in the ol' NetFramework 4.x. |
For .NET 8 <ItemGroup>
<None Update="A.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup> to: <ItemGroup>
<Content Include="A.dll">
<Pack>true</Pack>
<PackagePath>lib\$(TargetFramework)</PackagePath>
</Content>
</ItemGroup> |
We now have some docs for this: https://learn.microsoft.com/nuget/create-packages/native-files-in-net-packages Given the title of this issue, and the first post, I'm closing this issue as complete. @flier268 your suggestion doesn't work for native libraries. If you put Please see the docs linked for more info. |
Details about Problem
NuGet product used (NuGet.exe | VS UI | Package Manager Console | dotnet.exe): dotnet.exe
dotnet.exe --version (if appropriate): 2.1.4
OS version (i.e. win10 v1607 (14393.321)): win10 v1709 (16299.248)
Description
We've got rid and tfm specific native assemblies in a package but until very recently I haven't find enough documentation about how to pack them and let the runtime pick the appropriate native library automatically.
Relevant links:
runtimes/win-x64
and so on -- , but how am I supposed to know that this convention is carried over to the new csproj?I have to look into the Nuget code repo, and here: https://github.com/NuGet/NuGet.Client/blob/023fe7670796a8986bbfdc520029e4cf0a6bbfda/src/NuGet.Core/NuGet.Packaging/ContentModel/ManagedCodeConventions.cs#L452
That's it, now I know it's
runtimes/{rid}/native/{any?}
. Searching for a concrete example on the internet:I get issues, not documentation.
Searching for "nuget pack native assemblies" did not work either..
It turns out, the correct information is located here: - Bingo!
However, this page is advertised as "Supporting multiple .NET framework versions", which is really orthogonal to what I want. Multi-targeting is about
tfm
, and platform-specific stuff are aboutrid
-- I have never found a single page that connects all these dots together.So I suggest documenting such behavior at the following docs sites:
runtimes/{rid}/native
does not work withnetfx
-- you have to place native dlls in the lib/ folder (risky, could cause msbuild warnings/errors), or embed the dlls and release them at runtime.The text was updated successfully, but these errors were encountered: