如何将C++ DLL复制到引用它们的任意C#项目构建输出目录?
解决C++/CLI依赖的原生DLL自动复制与NuGet打包问题
我之前也碰到过一模一样的场景——C#类库套着C++/CLI层,底下还有一堆原生C++ DLL,默认构建时根本不会把这些原生DLL带到最终应用的输出目录,做NuGet包的时候更是头疼。给你几个靠谱的解决方案:
方案1:修改C++/CLI项目配置,强制同步原生DLL
这是最直接的办法,不用碰上层C#项目或者NuGet配置:
- 打开你的C++/CLI项目属性,找到链接器 -> 常规,确认“附加库目录”已经包含原生C++ DLL的输出路径
- 切换到生成事件 -> 后期生成事件,添加命令行复制原生DLL到CLI项目的输出目录:
这样每次CLI项目编译完成,都会把依赖的原生DLL同步到自己的输出目录,之后C#类库引用CLI项目时,就会自动把CLI DLL和附带的原生DLL一起复制到上层应用的输出目录。xcopy /Y "$(SolutionDir)Path\To\Your\NativeDlls\$(PlatformTarget)\*.dll" "$(TargetDir)"
方案2:通过NuGet的.targets文件自动处理依赖
如果要把C#类库做成NuGet包,这个是最佳实践,能让任何安装包的项目自动获取所有依赖:
- 在C#类库项目中新建
build文件夹(名字必须是build,NuGet会自动识别) - 在
build里创建一个和NuGet包同名的.targets文件,比如YourLibrary.targets,内容如下:<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <NativeDlls Include="$(MSBuildThisFileDirectory)..\runtimes\win-$(Platform)\native\*.dll" /> </ItemGroup> <Target Name="CopyNativeDlls" AfterTargets="Build"> <Copy SourceFiles="@(NativeDlls)" DestinationFolder="$(OutputPath)" SkipUnchangedFiles="true" /> </Target> </Project> - 按平台整理原生DLL,放到
runtimes\win-x64\native和runtimes\win-x86\native这类符合NuGet runtime约定的目录下 - 修改
.nuspec文件(或者通过项目文件的PackageReference配置),把build和runtimes文件夹都包含进NuGet包:
用户安装你的NuGet包后,MSBuild会自动执行.targets里的复制命令,把对应平台的原生DLL放到应用输出目录,完全不用用户手动配置。<files> <file src="bin\$(Configuration)\net6.0\YourLibrary.dll" target="lib\net6.0" /> <file src="build\**" target="build" /> <file src="runtimes\**" target="runtimes" /> </files>
方案3:让原生C++项目直接输出到CLI目录
如果原生C++项目和CLI项目在同一个解决方案里,可以直接修改原生项目的输出路径:
- 打开原生C++项目属性,找到常规 -> 输出目录,设置为
$(SolutionDir)YourCLIProject\$(Configuration)\$(PlatformTarget)\ - 这样原生项目编译后,DLL直接输出到CLI项目的目录里,CLI项目会把这些DLL当成自己的输出文件,上层C#项目引用CLI时就会自动复制过去。
这个方案适合团队内部项目,减少复制步骤,但如果原生DLL是第三方的就不太适用。
内容的提问来源于stack exchange,提问作者Mugen




