如何发布包含x86/x64及Linux平台非托管二进制的NuGet包
解决方案
你的配置存在两个核心问题导致消费者无法找到文件:
- 仅将原生库放入runtimes目录,未配置自动复制逻辑,消费者项目编译时不会自动将对应架构的文件输出到运行目录
- PackagePath开头带反斜杠可能导致打包路径异常,且使用win10-x86这类特定版本RID兼容性弱于通用RID
第一步:调整项目属性配置
在你的.csproj文件的<PropertyGroup>节点中添加以下配置:
<PropertyGroup> <!-- 原有配置保持不变 --> <RuntimeIdentifiers>win-x86;win-x64;linux-x86;linux-x64</RuntimeIdentifiers> </PropertyGroup>
第二步:修正原生文件打包配置
替换你原来的Content打包配置为以下内容,使用None节点更适合打包原生资源:
<ItemGroup> <!-- Windows x86 原生库 --> <None Include="Binaries\x86\net.dll" Pack="true" PackagePath="runtimes\win-x86\native" /> <None Include="Binaries\x86\NetModuleWrapper.dll" Pack="true" PackagePath="runtimes\win-x86\native" /> <None Include="Binaries\x86\pthread.dll" Pack="true" PackagePath="runtimes\win-x86\native" /> <!-- Linux x86 原生库 --> <None Include="Binaries\x86\net.so" Pack="true" PackagePath="runtimes\linux-x86\native" /> <None Include="Binaries\x86\NetModuleWrapper.so" Pack="true" PackagePath="runtimes\linux-x86\native" /> <!-- Windows x64 原生库 --> <None Include="Binaries\x64\net.dll" Pack="true" PackagePath="runtimes\win-x64\native" /> <None Include="Binaries\x64\NetModuleWrapper.dll" Pack="true" PackagePath="runtimes\win-x64\native" /> <None Include="Binaries\x64\pthread.dll" Pack="true" PackagePath="runtimes\win-x64\native" /> <!-- Linux x64 原生库 --> <None Include="Binaries\x64\net.so" Pack="true" PackagePath="runtimes\linux-x64\native" /> <None Include="Binaries\x64\NetModuleWrapper.so" Pack="true" PackagePath="runtimes\linux-x64\native" /> <!-- 打包自动复制逻辑的targets文件 --> <None Include="你的包ID.targets" Pack="true" PackagePath="build\" /> </ItemGroup>
注意:将
你的包ID替换为你实际的NuGet包ID,需和<PackageId>节点的值完全一致。
第三步:添加自动复制逻辑文件
在你的项目根目录下新建和包ID同名的.targets文件(例如包ID为MyNativeWrapper则文件名为MyNativeWrapper.targets),内容如下:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <!-- x86 平台复制逻辑 --> <ItemGroup Condition="'$(Platform)' == 'x86' Or '$(PlatformTarget)' == 'x86'"> <Content Include="$(MSBuildThisFileDirectory)..\runtimes\win-x86\native\*.dll"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <TargetPath>%(Filename)%(Extension)</TargetPath> </Content> <Content Include="$(MSBuildThisFileDirectory)..\runtimes\linux-x86\native\*.so"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <TargetPath>%(Filename)%(Extension)</TargetPath> </Content> </ItemGroup> <!-- x64/AnyCPU 平台复制逻辑 --> <ItemGroup Condition="'$(Platform)' == 'x64' Or '$(PlatformTarget)' == 'x64' Or '$(Platform)' == 'AnyCPU' Or '$(PlatformTarget)' == 'AnyCPU'"> <Content Include="$(MSBuildThisFileDirectory)..\runtimes\win-x64\native\*.dll"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <TargetPath>%(Filename)%(Extension)</TargetPath> </Content> <Content Include="$(MSBuildThisFileDirectory)..\runtimes\linux-x64\native\*.so"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <TargetPath>%(Filename)%(Extension)</TargetPath> </Content> </ItemGroup> </Project>
第四步:调整DllImport写法
所有调用原生库的DllImport特性不要加路径,直接写文件名即可,例如:
[DllImport("net.dll")] public static extern int SomeMethod();
.NET运行时会自动根据当前运行环境的架构搜索匹配的原生文件。
注意事项
- 消费者项目如果需要兼容32位系统,需要将平台目标设置为x86,不要使用AnyCPU
- 你原有按平台复制到输出目录的配置可以保留,不影响打包逻辑
- 重新打包后需要清理消费者项目的NuGet缓存,避免旧版本包的影响
内容的提问来源于stack exchange,提问作者NanoBob
相关产品推荐
相关产品推荐

