如何将工具可执行程序作为常规构建的一部分发布?
解决入口项目嵌入工具项目发布产物的问题
我需要将EntryPoint.Diagnostics.Utility项目构建为独立可执行程序,并嵌入到入口项目EntryPoint的输出目录中,最终输出结构要求如下:
EntryPoint/bin/Debug/net10.0-windows/ Diagnostics.Utility/ Diagnostics.Utility.exe Diagnostics.Utility.dll ...
当前实现的问题
之前用Exec调用dotnet publish的方式存在两个核心问题:
- 竞争条件导致构建失败:构建整个解决方案时,部分机器会出现文件找不到的错误,示例报错如下:
[...] Restored C:\buildagent\work\9eb378ffe858f165\src\1-0 Spectroscopy\5-BootStrapper\EntryPoint\EntryPoint.csproj (in 12.46 sec). Publishing into 'obj\Release\net10.0-windows\win-x64\DiagnosticsUtility-publish' Determining projects to restore... Restored C:\buildagent\work\9eb378ffe858f165\src\1-0 Spectroscopy\3-ApplicationService\Diagnostics\Spectroscopy.ApplicationService.Diagnostics.Contract\Spectroscopy.ApplicationService.Diagnostics.Contract.csproj (in 333 ms). Restored C:\buildagent\work\9eb378ffe858f165\src\1-0 Spectroscopy\5-BootStrapper\EntryPoint.Diagnostics.Utility\EntryPoint.Diagnostics.Utility.csproj (in 801 ms). C:\Program Files\dotnet\sdk\10.0.101\Microsoft.Common.CurrentVersion.targets(4903,5): error MSB3030: Could not copy the file "C:\buildagent\work\9eb378ffe858f165\src\1-0 Spectroscopy\5-BootStrapper\EntryPoint\obj\Release\net10.0-windows\win-x64\DiagnosticsUtility-artifacts\obj\Spectroscopy.ApplicationService.Diagnostics.Contract\release\AntonPaar.Orca.Spec.ApplicationService.Diagnostics.Contract.dll" because it was not found. [C:\buildagent\work\9eb378ffe858f165\src\1-0 Spectroscopy\3-ApplicationService\Diagnostics\Spectroscopy.ApplicationService.Diagnostics.Contract\Spectroscopy.ApplicationService.Diagnostics.Contract.csproj] [C:\buildagent\work\9eb378ffe858f165\src\1-0 Spectroscopy\5-BootStrapper\EntryPoint\EntryPoint.csproj] C:\buildagent\work\9eb378ffe858f165\src\1-0 Spectroscopy\5-BootStrapper\EntryPoint\EntryPoint.csproj(31,9): error MSB3073: The command "dotnet publish ^ C:\buildagent\work\9eb378ffe858f165\src\1-0 Spectroscopy\5-BootStrapper\EntryPoint\EntryPoint.csproj(31,9): error MSB3073: "..\EntryPoint.Diagnostics.Utility\EntryPoint.Diagnostics.Utility.csproj" ^ C:\buildagent\work\9eb378ffe858f165\src\1-0 Spectroscopy\5-BootStrapper\EntryPoint\EntryPoint.csproj(31,9): error MSB3073: --artifacts-path "obj\Release\net10.0-windows\win-x64\DiagnosticsUtility-artifacts" ^ C:\buildagent\work\9eb378ffe858f165\src\1-0 Spectroscopy\5-BootStrapper\EntryPoint\EntryPoint.csproj(31,9): error MSB3073: --output "obj\Release\net10.0-windows\win-x64\DiagnosticsUtility-publish" ^ C:\buildagent\work\9eb378ffe858f165\src\1-0 Spectroscopy\5-BootStrapper\EntryPoint\EntryPoint.csproj(31,9): error MSB3073: --self-contained false ^ C:\buildagent\work\9eb378ffe858f165\src\1-0 Spectroscopy\5-BootStrapper\EntryPoint\EntryPoint.csproj(31,9): error MSB3073: --configuration Release ^ C:\buildagent\work\9eb378ffe858f165\src\1-0 Spectroscopy\5-BootStrapper\EntryPoint\EntryPoint.csproj(31,9): error MSB3073: --runtime win-x64" exited with code 1.
- 无增量构建支持:工具项目的源文件变更后,不会自动触发重建,必须手动清理后重新构建。
正确的MSBuild实现方案
替换原有的Exec任务,使用MSBuild内置任务处理项目发布,同时配置增量构建和路径隔离:
<Target Name="PublishDiagnosticsUtility" BeforeTargets="BeforeBuild" Inputs="..\EntryPoint.Diagnostics.Utility\**\*.cs;..\EntryPoint.Diagnostics.Utility\EntryPoint.Diagnostics.Utility.csproj" Outputs="$(IntermediateOutputPath)DiagnosticsUtility-publish\Diagnostics.Utility.exe"> <MSBuild Projects="..\EntryPoint.Diagnostics.Utility\EntryPoint.Diagnostics.Utility.csproj" Targets="Publish" Properties="Configuration=$(Configuration); RuntimeIdentifier=win-x64; SelfContained=false; PublishDir=$(IntermediateOutputPath)DiagnosticsUtility-publish; UseArtifactsOutput=true; ArtifactsPath=$(IntermediateOutputPath)DiagnosticsUtility-artifacts; BuildProjectReferences=true" BuildInParallel="false" /> <ItemGroup> <_DiagnosticsUtilityPublishFiles Include="$(IntermediateOutputPath)DiagnosticsUtility-publish\**" /> <Content Include="@(_DiagnosticsUtilityPublishFiles)" Link="Diagnostics.Utility\%(RecursiveDir)%(Filename)%(Extension)" PackagePath="content\Diagnostics.Utility\%(RecursiveDir)%(Filename)%(Extension)" CopyToOutputDirectory="PreserveNewest" /> </ItemGroup> </Target>
方案说明
- 增量构建支持:通过
Inputs和Outputs定义目标的输入输出,MSBuild会自动检测工具项目的源文件或项目文件变更,触发重新发布,无需手动清理。 - 解决竞争条件:
- 设置
BuildInParallel="false",确保工具项目发布任务与解决方案其他构建任务串行执行,避免文件访问冲突。 - 使用独立的
ArtifactsPath和PublishDir,完全隔离工具项目的中间输出和发布产物,不与解决方案内其他构建共享路径。
- 设置
- 属性传递与环境一致性:将配置、运行时标识符等属性直接传递给MSBuild任务,确保发布产物与入口项目构建环境一致。
- 优化复制逻辑:将
CopyToOutputDirectory改为PreserveNewest,仅复制更新过的文件,提升构建效率。
内容的提问来源于stack exchange,提问作者user272507
相关产品推荐
相关产品推荐

