如何使 MSBuild 不因 .NET 解决方案出错而停止 [英] How to make MSBuild to NOT stop on error on .NET solution
问题描述
我正在研究根据团队需求量身定制的构建服务器设置.它应该自动构建我们的 .net 解决方案.我尽量不更改 .sln 或项目文件中的任何内容.
I'm working on a custom build server setup tailored to the team needs. It should automatically build our .net solutions. I'm doing my best to not change anything in the .sln or project files.
该作业的明显构建工具是 msbuild
.我已经成功地从 .sln 文件中成功编译了我们的解决方案.
The obvious build tool for the job is the msbuild
. I've got it as far as to actually successfully compile our solutions from .sln files.
下一步是测试某些解决方案项目损坏时的场景.在以下情况下,我在 devenv
和 msbuild
之间遇到了奇怪的行为差异.有 3 个项目,其中 2nd 依赖于 1st,而 3rd 是独立和破碎的.devenv
按预期编译第 1 次和第 2 次,第 3 次失败;msbuild
编译第 1 次,第 3 次失败,并且 - 出乎意料地 - 没有尝试第 2 次.
Next step is testing the scenario when some of solution's projects are broken. And here I encountered a strange difference in behavior between devenv
and msbuild
in following situation. There are 3 projects, where 2nd depends on 1st, and 3rd is independent and broken. devenv
compiles 1st and 2nd and fails the 3rd, as expected; msbuild
compiles 1st, fails 3rd and - unexpectedly - doesn't try the 2nd.
示例解决方案(4 个文件:Complete.sln、1.csproj、2.csproj、3.csproj)
Example solution (4 files: Complete.sln, 1.csproj, 2.csproj, 3.csproj)
--- 1.csproj
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<OldToolsVersion>2.0</OldToolsVersion>
</PropertyGroup>
<Target Name="Build">
<Message Importance="High" Text="Project 1" />
</Target>
</Project>
--- 2.csproj
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<OldToolsVersion>2.0</OldToolsVersion>
</PropertyGroup>
<Target Name="Build">
<Message Importance="High" Text="Project 2" />
</Target>
</Project>
--- 3.csproj
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<OldToolsVersion>2.0</OldToolsVersion>
</PropertyGroup>
<Target Name="Build">
<Message Importance="High" Text="Project 3" />
<Error Text="Build failed" />
</Target>
</Project>
--- Complete.sln
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29709.97
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "1", "1.csproj", "{AA88BE9A-5006-4CCE-8871-A67F413DBADF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "2", "2.csproj", "{BAF51480-4B90-454A-96F5-E63A05A486EF}"
ProjectSection(ProjectDependencies) = postProject
{AA88BE9A-5006-4CCE-8871-A67F413DBADF} = {AA88BE9A-5006-4CCE-8871-A67F413DBADF}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "3", "3.csproj", "{12C30CFB-7387-4CD2-81D4-87E14209C408}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{AA88BE9A-5006-4CCE-8871-A67F413DBADF}.Debug|x86.ActiveCfg = Debug|x86
{AA88BE9A-5006-4CCE-8871-A67F413DBADF}.Debug|x86.Build.0 = Debug|x86
{BAF51480-4B90-454A-96F5-E63A05A486EF}.Debug|x86.ActiveCfg = Debug|x86
{BAF51480-4B90-454A-96F5-E63A05A486EF}.Debug|x86.Build.0 = Debug|x86
{12C30CFB-7387-4CD2-81D4-87E14209C408}.Debug|x86.ActiveCfg = Debug|x86
{12C30CFB-7387-4CD2-81D4-87E14209C408}.Debug|x86.Build.0 = Debug|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {75E95C15-489D-4D3F-82CA-735FB7B88910}
EndGlobalSection
EndGlobal
VS 2019 开发人员命令提示符"的控制台输出如下所示:
Console output from "Developer Command Prompt for VS 2019" is like following:
e>devenv /Build Debug Complete.sln
Microsoft Visual Studio 2019 Version 16.4.3.
Copyright (C) Microsoft Corp. All rights reserved.
1>------ Build started: Project: 1, Configuration: Debug x86 ------
2>------ Build started: Project: 3, Configuration: Debug x86 ------
1> Project 1
2> Project 3
2>C:\temp\msbuild\TestSolution\Complete\3.csproj(11,2): error : Build failed
3>------ Build started: Project: 2, Configuration: Debug x86 ------
3> Project 2
========== Build: 2 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
>msbuild Complete.sln /p:Configuration=Debug /p:Platform=x86 /m
Microsoft (R) Build Engine version 16.4.0+e901037fe for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.
Build started 23.01.2020 11:10:38.
1>Project "c:\temp\msbuild\TestSolution\Complete\Complete.sln" on node 1 (default targets).
1>ValidateSolutionConfiguration:
Building solution configuration "Debug|x86".
1>Project "c:\temp\msbuild\TestSolution\Complete\Complete.sln" (1) is building "c:\temp\msbuild\TestSolution\Complete\1.cs
proj" (2) on node 1 (default targets).
2>Build:
Project 1
2>Done Building Project "c:\temp\msbuild\TestSolution\Complete\1.csproj" (default targets).
1>Project "c:\temp\msbuild\TestSolution\Complete\Complete.sln" (1) is building "c:\temp\msbuild\TestSolution\Complete\3.cs
proj" (3) on node 2 (default targets).
3>Build:
Project 3
3>c:\temp\msbuild\TestSolution\Complete\3.csproj(11,5): error : Build failed
3>Done Building Project "c:\temp\msbuild\TestSolution\Complete\3.csproj" (default targets) -- FAILED.
1>Done Building Project "c:\temp\msbuild\TestSolution\Complete\Complete.sln" (default targets) -- FAILED.
Build FAILED.
"c:\temp\msbuild\TestSolution\Complete\Complete.sln" (default target) (1) ->
"c:\temp\msbuild\TestSolution\Complete\3.csproj" (default target) (3) ->
(Build target) ->
c:\temp\msbuild\TestSolution\Complete\3.csproj(11,5): error : Build failed
0 Warning(s)
1 Error(s)
Time Elapsed 00:00:00.65
请注意 msbuild
输出中缺少 Project 2
消息.
Please notice in msbuild
output the Project 2
message is missing.
有没有(非侵入式)方法让 msbuild
继续编译其他项目?
Is there a (non-intrusive) way to make msbuild
continue compiling other projects?
到目前为止,我想到的最好的方法是在 Complete.sln
上方的某个文件夹中创建一个 Directory.Solution.targets
(参见 msdn) 包含以下内容.>
The best I came up till now is creating a Directory.Solution.targets
in some folder upwards from Complete.sln
(see msdn) with following content.
<Project>
<Target Name="SetSkip">
<ItemGroup>
<ProjectReference Update="*">
<SkipNonexistentProjects>Build</SkipNonexistentProjects>
</ProjectReference>
</ItemGroup>
</Target>
<Target Name="BuildAll" DependsOnTargets="SetSkip">
<CallTarget Targets="Build"/>
</Target>
</Project>
注意 SkipNonexistentProjects
设置为 Build
,而不是 True
.当设置为 True
时,第二个项目被跳过,Skipping project "2.csproj.metaproj" 因为它没有找到.
.
Note SkipNonexistentProjects
is set to Build
, not True
. When set to True
the 2nd project is skipped with Skipping project "2.csproj.metaproj" because it was not found.
.
然后使用 /t:BuildAll
而不是 /t:Build
调用 msbuild
.但是我需要为所有可能的解决方案和每个可能的目标执行此操作,而且我真的想要一些更好的方法,也许是我还找不到的命令行开关(/p:ContinueOnError=true;StopOnFirstFailure=false;SkipNonexistentProjects=true
没有帮助.
And then calling msbuild
with /t:BuildAll
instead of /t:Build
. But I'd need to do this for every possible solution and every possible target, and I'd really like some better way, maybe a command line switch I wasn't able to find yet (/p:ContinueOnError=true;StopOnFirstFailure=false;SkipNonexistentProjects=true
doesn't help).
UPDATE 改进了我的解决方法:现在只需要根文件夹中的一个附加文件.
UPDATE improved my workaround: now only a single additional file in a root folder is needed.
推荐答案
这个答案在问题本身中引用了我的解决方法,以提高其可见性(如 评论另一个答案).
This answer quotes my workaround in the question itself, to improve its visibility (as suggested in a comment to another answer).
到目前为止,我想到的最好的方法是在 Complete.sln
上方的某个文件夹中创建一个 Directory.Solution.targets
(参见 msdn) 包含以下内容.>
The best I came up till now is creating a Directory.Solution.targets
in some folder upwards from Complete.sln
(see msdn) with following content.
<Project>
<Target Name="SetSkip">
<ItemGroup>
<ProjectReference Update="*">
<SkipNonexistentProjects>Build</SkipNonexistentProjects>
</ProjectReference>
</ItemGroup>
</Target>
<Target Name="BuildAll" DependsOnTargets="SetSkip">
<CallTarget Targets="Build"/>
</Target>
<Target Name="RebuildAll" DependsOnTargets="SetSkip">
<CallTarget Targets="Rebuild"/>
</Target>
<Target Name="CleanAll" DependsOnTargets="SetSkip">
<CallTarget Targets="Clean"/>
</Target>
</Project>
注意 SkipNonexistentProjects
设置为 Build
,而不是 True
.当设置为 True
时,第二个项目被跳过,Skipping project "2.csproj.metaproj" 因为它没有找到.
.
Note SkipNonexistentProjects
is set to Build
, not True
. When set to True
the 2nd project is skipped with Skipping project "2.csproj.metaproj" because it was not found.
.
然后使用 /t:BuildAll
而不是 /t:Build
调用 msbuild
会按预期构建它可以构建的所有内容.
And then calling msbuild
with /t:BuildAll
instead of /t:Build
builds everything it can, as expected.
这对我来说是一个足够好的解决方案,尽管我仍然更喜欢不定义替代构建/重建目标的某种方式.
This is a good enough solution for me, although I would still prefer some way without defining alternate Build/Rebuild targets.
这篇关于如何使 MSBuild 不因 .NET 解决方案出错而停止的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!