如何创建仅含一份原生库的多目标.NET NuGet包?
我正在为外部C++库编写.NET绑定项目,希望将平台相关的原生库(已构建x64、arm64等版本)纳入nupkg,用户安装包即可直接使用。项目目标框架包含net6.0和net8.0,但当前配置下NuGet会为每个.NET框架各打包一次library.so,还会在包根目录再放一份,共3份副本;即使只目标netstandard2.0,也会有两份。原生库体积很大,导致包体积至少是单架构库的2倍,无法上传到限制250MB的nuget.org。
当前csproj相关配置:
<ItemGroup> <Content Include="library.so" Pack="true" CopyToOutputDirectory="PreserveNewest" /> </ItemGroup>
生成的Nupkg结构:
... ./contentFiles/any/net6.0/library.so ./contentFiles/any/net8.0/library.so ./content/library.so ...
该原生库对net6.0和net8.0完全相同,请问如何构建仅包含一次该文件的包?或有哪些方案可避免用户手动安装该库?
1. 配置Content项指定共享路径
修改csproj中的Content节点,明确设置PackagePath和ContentTargetFolders为跨框架的共享位置,让文件只打包一次:
<ItemGroup> <Content Include="library.so" Pack="true" CopyToOutputDirectory="PreserveNewest" PackagePath="contentFiles/any/any" ContentTargetFolders="contentFiles/any/any" /> </ItemGroup>
配置后,文件只会出现在contentFiles/any/any/library.so,所有目标框架都会引用这个共享位置的文件,不会生成多份副本。
2. 改用NativeLibrary资产类型
原生库更适合用NuGet专门的NativeLibrary类型处理,它默认支持跨框架共享,不会重复打包:
<ItemGroup> <NativeLibrary Include="library.so" Pack="true" CopyToOutputDirectory="PreserveNewest" /> </ItemGroup>
文件会被打包到标准的原生资产目录,所有兼容的.NET框架都会自动识别并引用该文件。
3. 按运行时标识符(RID)分架构打包
如果原生库是分架构的(x64、arm64),可以按RID组织文件,每个架构只打包一次,NuGet会根据用户环境自动匹配:
<ItemGroup> <NativeLibrary Include="runtimes/linux-x64/native/library.so" Pack="true" CopyToOutputDirectory="PreserveNewest" /> <NativeLibrary Include="runtimes/linux-arm64/native/library.so" Pack="true" CopyToOutputDirectory="PreserveNewest" /> </ItemGroup>
这种方式既避免了跨框架重复,还能让用户只获取对应架构的库,进一步缩减包体积。
4. 移除content目录的冗余副本
如果不需要兼容旧版packages.config项目,可以添加配置避免在包根目录的content下生成副本:
<ItemGroup> <Content Include="library.so" Pack="true" CopyToOutputDirectory="PreserveNewest" PackagePath="contentFiles/any/any" ContentTargetFolders="contentFiles/any/any" PackageCopyToOutput="false" /> <Content Remove="library.so" PackagePath="content/" /> </ItemGroup>
内容的提问来源于stack exchange,提问作者python_kaa

