如何通过NuGet分发层级结构DLL并在自包含构建中保留结构?
解决NuGet包分发带层级结构DLL并在Self Contained发布中保留结构的问题
1. 规范NuGet包的文件结构与.nuspec配置
首先确保NuGet包内部按运行时+后端类型划分层级,示例结构如下:
runtimes/ ├─ win-x64/ │ └─ native/ │ ├─ cuda/ │ │ └─ llama.dll │ ├─ avx2/ │ │ └─ llama.dll │ ├─ vulkan/ │ │ └─ llama.dll ├─ linux-x64/ │ └─ native/ │ ├─ avx512/ │ │ └─ libllama.so │ └─ opencl/ │ └─ libllama.so
在.nuspec文件中通过<file>节点明确保留层级结构,避免打包时被扁平化:
<files> <!-- Windows x64各后端DLL --> <file src="runtimes/win-x64/native/cuda/**/*" target="runtimes/win-x64/native/cuda/" /> <file src="runtimes/win-x64/native/avx2/**/*" target="runtimes/win-x64/native/avx2/" /> <file src="runtimes/win-x64/native/vulkan/**/*" target="runtimes/win-x64/native/vulkan/" /> <!-- Linux x64各后端SO --> <file src="runtimes/linux-x64/native/avx512/**/*" target="runtimes/linux-x64/native/avx512/" /> <file src="runtimes/linux-x64/native/opencl/**/*" target="runtimes/linux-x64/native/opencl/" /> <!-- 其他平台/后端按此格式添加 --> </files>
2. 调整项目文件(.csproj)阻止发布时扁平化
在LLamaSharp自身项目或引用它的项目文件中添加以下配置,强制MSBuild保留DLL的层级结构:
基础保留配置
<PropertyGroup> <!-- 确保依赖项被复制到输出目录 --> <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> <!-- Self Contained发布时保留编译上下文 --> <PreserveCompilationContext>true</PreserveCompilationContext> </PropertyGroup> <ItemGroup> <!-- 指定要保留的文件模式,确保子文件夹结构不丢失 --> <PublishPreserveMatchingFiles Include="runtimes\**\*.dll" /> <PublishPreserveMatchingFiles Include="runtimes\**\*.so" /> <PublishPreserveMatchingFiles Include="runtimes\**\*.dylib" /> </ItemGroup>
自定义Target拦截复制流程(针对顽固扁平化问题)
如果上述配置无效,添加自定义Target,在发布后将扁平化的DLL移回对应子文件夹,并删除根目录的冲突文件:
<Target Name="RestoreBackendDirectoryStructure" AfterTargets="CopyFilesToPublishDirectory" Condition="'$(SelfContained)' == 'true'"> <!-- 收集所有后端目录下的原生库文件 --> <ItemGroup> <BackendLibraries Include="$(PublishDir)runtimes\$(RuntimeIdentifier)\native\**\*" /> </ItemGroup> <!-- 将文件复制到发布目录的对应层级 --> <Copy SourceFiles="@(BackendLibraries)" DestinationFiles="@(BackendLibraries->'$(PublishDir)%(RecursiveDir)%(Filename)%(Extension)')" /> <!-- 删除被扁平化到根目录的冲突文件 --> <Delete Files="@(BackendLibraries->'$(PublishDir)%(Filename)%(Extension)')" /> </Target>
3. 适配运行时DLL加载逻辑
修改LLamaSharp的后端选择逻辑,根据硬件检测结果拼接对应DLL路径加载,示例代码:
// 检测到CUDA可用时加载对应路径的DLL string runtimeDir = Path.Combine(AppContext.BaseDirectory, "runtimes", RuntimeInformation.RuntimeIdentifier, "native"); string dllPath = Path.Combine(runtimeDir, "cuda", "llama.dll"); NativeLibrary.Load(dllPath);
此方式既避免同名DLL冲突,也能保证运行时正确选择最优后端。
内容的提问来源于stack exchange,提问作者Martin
相关产品推荐
相关产品推荐

