我有一种有点复杂但有效的解决方案:
当使用解决方案文件调用 MSBuild 时,它会在内部从该解决方案生成一个项目文件并构建该项目文件。当将环境变量 msbuildemitsolution 设置为 1 时,它会将该项目文件输出到命名为解决方案文件但后跟 .proj 的硬盘上。此外,它总是会生成一个 .cache 文件,以防止它一直重新生成项目文件。所以我首先要做的是:
IF EXIST xyz.sln.proj DEL xyz.sln.proj
IF EXIST xyz.sln.cache DEL xyz.sln.cache
SET msbuildemitsolution=1
MSBuild.exe xyz-sln /t:_xxxxx_ /noconsolelogger
目标xxxx不应该存在的地方。MSBuild 然后生成一个 xyz.sln.proj 并由于缺少目标而输出许多错误。我忽略了这些错误,因为我想要的是项目文件。实际上,我在 C# 程序中执行上述操作,但为了更容易理解,我在这里选择了 BAT 语法。
xyz.sln.proj 包含许多目标:“Build”、“Clean”、“Rebuild”和“Publish”以及“”、“:Clean”、“:Rebuild”、“:Publish”、“”...我感兴趣的只是目标“构建”、“重建”和“清洁”。这些目标由几个构建 csproj 文件集的 MSBuild 任务组成。这些集合称为 BuildLevelX(其中 X 是一个数字)。对于 C++ 项目,Build/Rebuild/Clean 目标包含直接调用任务的 CallTarget 任务。我的文件中的一个片段:
<Target Name="Build" Condition="'$(CurrentSolutionConfigurationContents)' != ''" Outputs="@(CollectedBuildOutput)">
<MSBuild Condition="@(BuildLevel0) != ''" Projects="@(BuildLevel0)" Properties="Configuration=%(Configuration); Platform=%(Platform); BuildingSolutionFile=true; CurrentSolutionConfigurationContents=$(CurrentSolutionConfigurationContents); SolutionDir=$(SolutionDir); SolutionExt=$(SolutionExt); SolutionFileName=$(SolutionFileName); SolutionName=$(SolutionName); SolutionPath=$(SolutionPath)" ToolsVersion="$(ProjectToolsVersion)" BuildInParallel="true" UnloadProjectsOnCompletion="$(UnloadProjectsOnCompletion)" UseResultsCache="$(UseResultsCache)" ContinueOnError="true">
<Output TaskParameter="TargetOutputs" ItemName="CollectedBuildOutput" />
</MSBuild>
<Message Text="The project "%(SkipLevel0.Identity)" is not selected for building in solution configuration "$(Configuration)|$(Platform)"." Condition="@(SkipLevel0) != ''" />
<Warning Text="The project configuration for project "%(MissingConfigLevel0.Identity)" was not specified in the solution file for the solution configuration "$(Configuration)|$(Platform)"." Code="MSB4121" HelpKeyword="MSBuild.SolutionProjectConfigurationMissing" Condition="@(MissingConfigLevel0) != ''" />
<MSBuild Condition="@(BuildLevel1) != ''" Projects="@(BuildLevel1)" Properties="Configuration=%(Configuration); Platform=%(Platform); BuildingSolutionFile=true; CurrentSolutionConfigurationContents=$(CurrentSolutionConfigurationContents); SolutionDir=$(SolutionDir); SolutionExt=$(SolutionExt); SolutionFileName=$(SolutionFileName); SolutionName=$(SolutionName); SolutionPath=$(SolutionPath)" ToolsVersion="$(ProjectToolsVersion)" BuildInParallel="true" UnloadProjectsOnCompletion="$(UnloadProjectsOnCompletion)" UseResultsCache="$(UseResultsCache)" ContinueOnError="true">
<Output TaskParameter="TargetOutputs" ItemName="CollectedBuildOutput" />
</MSBuild>
<Message Text="The project "%(SkipLevel1.Identity)" is not selected for building in solution configuration "$(Configuration)|$(Platform)"." Condition="@(SkipLevel1) != ''" />
<Warning Text="The project configuration for project "%(MissingConfigLevel1.Identity)" was not specified in the solution file for the solution configuration "$(Configuration)|$(Platform)"." Code="MSB4121" HelpKeyword="MSBuild.SolutionProjectConfigurationMissing" Condition="@(MissingConfigLevel1) != ''" />
<CallTarget Targets="SomeLib" RunEachTargetSeparately="true" ContinueOnError="true" />
<MSBuild Condition="@(BuildLevel2) != ''" Projects="@(BuildLevel2)" Properties="Configuration=%(Configuration); Platform=%(Platform); BuildingSolutionFile=true; CurrentSolutionConfigurationContents=$(CurrentSolutionConfigurationContents); SolutionDir=$(SolutionDir); SolutionExt=$(SolutionExt); SolutionFileName=$(SolutionFileName); SolutionName=$(SolutionName); SolutionPath=$(SolutionPath)" ToolsVersion="$(ProjectToolsVersion)" BuildInParallel="true" UnloadProjectsOnCompletion="$(UnloadProjectsOnCompletion)" UseResultsCache="$(UseResultsCache)" ContinueOnError="true">
<Output TaskParameter="TargetOutputs" ItemName="CollectedBuildOutput" />
</MSBuild>
<Message Text="The project "%(SkipLevel2.Identity)" is not selected for building in solution configuration "$(Configuration)|$(Platform)"." Condition="@(SkipLevel2) != ''" />
<Warning Text="The project configuration for project "%(MissingConfigLevel2.Identity)" was not specified in the solution file for the solution configuration "$(Configuration)|$(Platform)"." Code="MSB4121" HelpKeyword="MSBuild.SolutionProjectConfigurationMissing" Condition="@(MissingConfigLevel2) != ''" />
<CallTarget Targets="SomeProgram" RunEachTargetSeparately="true" ContinueOnError="true" />
<MSBuild Condition="@(BuildLevel3) != ''" Projects="@(BuildLevel3)" Properties="Configuration=%(Configuration); Platform=%(Platform); BuildingSolutionFile=true; CurrentSolutionConfigurationContents=$(CurrentSolutionConfigurationContents); SolutionDir=$(SolutionDir); SolutionExt=$(SolutionExt); SolutionFileName=$(SolutionFileName); SolutionName=$(SolutionName); SolutionPath=$(SolutionPath)" ToolsVersion="$(ProjectToolsVersion)" BuildInParallel="true" UnloadProjectsOnCompletion="$(UnloadProjectsOnCompletion)" UseResultsCache="$(UseResultsCache)" ContinueOnError="true">
<Output TaskParameter="TargetOutputs" ItemName="CollectedBuildOutput" />
</MSBuild>
<Message Text="The project "%(SkipLevel3.Identity)" is not selected for building in solution configuration "$(Configuration)|$(Platform)"." Condition="@(SkipLevel3) != ''" />
<Warning Text="The project configuration for project "%(MissingConfigLevel3.Identity)" was not specified in the solution file for the solution configuration "$(Configuration)|$(Platform)"." Code="MSB4121" HelpKeyword="MSBuild.SolutionProjectConfigurationMissing" Condition="@(MissingConfigLevel3) != ''" />
<MSBuild Condition="@(BuildLevel4) != ''" Projects="@(BuildLevel4)" Properties="Configuration=%(Configuration); Platform=%(Platform); BuildingSolutionFile=true; CurrentSolutionConfigurationContents=$(CurrentSolutionConfigurationContents); SolutionDir=$(SolutionDir); SolutionExt=$(SolutionExt); SolutionFileName=$(SolutionFileName); SolutionName=$(SolutionName); SolutionPath=$(SolutionPath)" ToolsVersion="$(ProjectToolsVersion)" BuildInParallel="true" UnloadProjectsOnCompletion="$(UnloadProjectsOnCompletion)" UseResultsCache="$(UseResultsCache)" ContinueOnError="true">
<Output TaskParameter="TargetOutputs" ItemName="CollectedBuildOutput" />
</MSBuild>
<Message Text="The project "%(SkipLevel4.Identity)" is not selected for building in solution configuration "$(Configuration)|$(Platform)"." Condition="@(SkipLevel4) != ''" />
<Warning Text="The project configuration for project "%(MissingConfigLevel4.Identity)" was not specified in the solution file for the solution configuration "$(Configuration)|$(Platform)"." Code="MSB4121" HelpKeyword="MSBuild.SolutionProjectConfigurationMissing" Condition="@(MissingConfigLevel4) != ''" />
</Target>
我加载 proj 文件并将 ContinueOnError="true" 添加到 Build/Rebuild/Clean 目标中的所有 MSBuild 和 CallTarget 任务中:
XmlDocument msBuildProject = new XmlDocument();
msBuildProject.Load(Tools.getFullPath(m_strBaseDir, strSolutionProjFile));
foreach (XmlNode nodeL0 in msBuildProject.ChildNodes)
{
XmlElement elementL0 = nodeL0 as XmlElement;
if ((elementL0 != null) && (String.CompareOrdinal(nodeL0.Name, "Project") == 0))
{
foreach (XmlNode nodeL1 in elementL0.ChildNodes)
{
XmlElement elementL1 = nodeL1 as XmlElement;
if ((elementL1 != null) && (String.CompareOrdinal(nodeL1.Name, "Target") == 0))
{
if ((String.CompareOrdinal(elementL1.Attributes["Name"].Value, "Build") == 0) ||
(String.CompareOrdinal(elementL1.Attributes["Name"].Value, "Rebuild") == 0) ||
(String.CompareOrdinal(elementL1.Attributes["Name"].Value, "Clean") == 0) ||
(String.CompareOrdinal(elementL1.Attributes["Name"].Value, "Publish") == 0))
{
foreach (XmlNode nodeL2 in elementL1.ChildNodes)
{
XmlElement elementL2 = nodeL2 as XmlElement;
if ((elementL2 != null) &&
((String.CompareOrdinal(nodeL2.Name, "MSBuild") == 0) ||
(String.CompareOrdinal(nodeL2.Name, "CallTarget") == 0)))
{
elementL2.SetAttribute("ContinueOnError", "true");
}
}
}
}
}
}
}
msBuildProject.Save(Tools.getFullPath(m_strBaseDir, strSolutionProjFile));
之后,我使用配置调用 MSBuild。
这很好用,但因为它不是很容易我永远不会将此标记为我的问题的答案:-)