如何用.NET Core CLI打包包含非托管DLL的NuPkg包?
嘿,这个问题我熟——把带非托管DLL依赖的.NET Core类库打包成能正常工作的NuGet包,核心就是得让NuGet把那些非托管文件送到引用项目的正确位置,确保运行时能找得到。下面是一步步的实操方案:
非托管DLL没法像托管程序集那样直接被项目引用,所以咱们得借助NuGet的打包规则,把这些平台特定的文件打包进NuPkg,并且让引用项目在构建/运行时能自动找到它们。最稳妥的方式是遵循NuGet的运行时特定文件结构,或者用MSBuild目标文件自定义复制逻辑。
首先,先给你的非托管DLL建个标准的目录结构,放在类库项目根目录下:
你的类库项目/ ├── runtimes/ │ ├── win-x86/ │ │ └── native/ │ │ └── YourNativeLib.dll │ ├── win-x64/ │ │ └── native/ │ │ └── YourNativeLib.dll │ └── linux-x64/ │ └── native/ │ └── libYourNativeLib.so └── YourLibrary.csproj
这个结构是NuGet官方认可的,会自动根据目标项目的运行时标识(RID)匹配对应的非托管文件。
接下来修改YourLibrary.csproj,添加以下配置:
配置1:包含非托管文件到NuGet包
<ItemGroup> <!-- 递归包含runtimes目录下的所有非托管文件,打包时保留原目录结构 --> <None Include="runtimes/**/*" Pack="true" PackagePath="%(RecursiveDir)" /> </ItemGroup>
配置2:指定支持的运行时标识
<PropertyGroup> <!-- 列出你要支持的所有平台RID,按需调整 --> <RuntimeIdentifiers>win-x86;win-x64;linux-x64</RuntimeIdentifiers> <!-- 让.NET自动处理非托管库的提取(针对.NET Core 3.0+) --> <IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract> </PropertyGroup>
配置3:DllImport的正确写法
确保你的DllImport只写文件名,不用带路径——.NET会自动在匹配的runtimes/{RID}/native目录下查找:
// Windows下的写法 [DllImport("YourNativeLib.dll")] private static extern void YourNativeMethod(); // Linux下的写法(注意lib前缀) [DllImport("libYourNativeLib.so")] private static extern void YourNativeMethod();
如果要跨平台兼容,可以用条件编译区分。
如果官方的runtimes结构满足不了你的需求(比如你想把非托管DLL直接复制到输出目录根目录),可以添加一个MSBuild目标文件来控制复制行为:
- 在类库项目根目录创建
YourLibrary.targets文件,内容如下:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <!-- 匹配当前运行时对应的非托管DLL --> <NativeLibs Include="$(MSBuildThisFileDirectory)..\runtimes\$(RuntimeIdentifier)\native\*" /> </ItemGroup> <Target Name="CopyNativeDependencies" BeforeTargets="Build"> <!-- 把非托管DLL复制到项目输出目录 --> <Copy SourceFiles="@(NativeLibs)" DestinationFolder="$(OutputPath)" /> </Target> </Project>
- 在
YourLibrary.csproj里把这个.targets文件打包到NuGet的build目录:
<ItemGroup> <None Include="YourLibrary.targets" Pack="true" PackagePath="build\$(TargetFramework)" /> </ItemGroup>
这样引用这个NuGet包的项目在构建时,会自动执行这个目标,把对应平台的非托管DLL复制到输出目录。
用.NET CLI执行打包命令:
dotnet pack -c Release
生成的NuPkg会在bin/Release目录下。你可以把它添加到本地NuGet源,然后新建一个测试项目引用这个包,运行后检查输出目录是否有对应的非托管DLL,同时验证原生方法是否能正常调用。
- 平台一致性:不同架构的非托管DLL不能混用,一定要按RID分开存放,否则会出现
DllNotFoundException。 - 文件名匹配:DllImport的文件名必须和非托管文件完全一致,Linux下的SO文件通常带
lib前缀,别漏了。 - .NET Framework兼容:如果要支持.NET Framework项目,可能需要额外配置
PackagePath为build/net4xx,但.NET Core/.NET 5+的标准结构基本能兼容大部分场景。
内容的提问来源于stack exchange,提问作者UlfW

