以下内容适用于 RAD Studio XE4,但也可能适用于更早或更高版本。此外,在 .groupproj 中定义的依赖项也不会使用此方法。我试图并行化的 .groupproj 没有项目间依赖关系,所以我不知道如何处理。
当您使用 Build、Clean 或 Make 目标通过 MSBuild 构建 .groupproj 文件时,构建不会并行运行,因为这些目标使用 CallTarget 任务来执行其他目标,但是CallTarget 不会并行执行其目标。
为了并行构建单独的项目,MSBuild 项目必须使用单个MSBuild task 来一次构建多个项目。目标必须像这样定义:
<Target Name="Build">
<MSBuild Projects="@(Projects)" BuildInParallel="true"/>
</Target>
<Target Name="Clean">
<MSBuild Targets="Clean" Projects="@(Projects)" BuildInParallel="true"/>
</Target>
<Target Name="Make">
<MSBuild Targets="Make" Projects="@(Projects)" BuildInParallel="true"/>
</Target>
将这些添加到 .groupproj,然后删除其他 <Target> 指令以及 <Import> 指令。 (CodeGear.Group.Targets 定义了一些目标,以便在您要求仅构建项目的子集时以正确的顺序构建项目并构建依赖关系,但它覆盖了在.groupproj。)请注意,这只允许您构建所有项目,而不仅仅是一个子集。
BuildInParallel was added in MSBuild 3.5. 但是,由于 .groupproj 文件未指定 ToolsVersion 属性,MSBuild 将使用不支持 BuildInParallel 的 2.0 版中定义的 MSBuild 任务。有两种方法可以解决此问题:
- 将
ToolsVersion="3.5"(或更高版本)添加到 .groupproj 文件的根 <Project> 元素中。
- 使用
/toolsversion:3.5(或简称/tv:3.5)命令行参数运行MSBuild(/toolsversion 会覆盖所有项目文件中指定的ToolsVersion。)
完成此操作后,使用 /maxcpucount(或 /m)参数运行 MSBuild,您的项目应该并行构建。但是,RAD Studio 不能正确处理这个转换后的项目组,因此您可能需要为文件提供不同的扩展名,以明确它不是标准的 RAD Studio 项目组(任何以 proj 结尾的扩展名都可以) .
以下 XSLT 样式表执行上述转换:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
exclude-result-prefixes="msbuild"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
xmlns:msbuild="http://schemas.microsoft.com/developer/msbuild/2003"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="//msbuild:Project">
<xsl:copy>
<xsl:attribute name="ToolsVersion">3.5</xsl:attribute>
<xsl:apply-templates select="@* | node()"/>
<Target Name="Build">
<MSBuild Projects="@(Projects)" BuildInParallel="true"/>
</Target>
<Target Name="Clean">
<MSBuild Targets="Clean" Projects="@(Projects)" BuildInParallel="true"/>
</Target>
<Target Name="Make">
<MSBuild Targets="Make" Projects="@(Projects)" BuildInParallel="true"/>
</Target>
</xsl:copy>
</xsl:template>
<xsl:template match="//msbuild:Target">
<!-- Do not copy -->
</xsl:template>
<xsl:template match="//msbuild:Import">
<!-- Do not copy -->
</xsl:template>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
您可以使用此项目文件(其中groupproj2parallel.xslt 是上面的 XSLT 文件)在 MSBuild(4.0 或更高版本:XslTransformation 在 MSBuild 4.0 中添加)应用此样式表:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Build" Inputs="$(InputPaths)" Outputs="$(OutputPaths)">
<XslTransformation
XmlInputPaths="$(InputPaths)"
XslInputPath="groupproj2parallel.xslt"
OutputPaths="$(OutputPaths)" />
</Target>
</Project>
您需要在命令行中使用/p:InputPaths="..." /p:OutputPaths="..." 明确指定InputPaths 和OutputPaths,或者在MSBuild 任务的Properties 参数上指定它们。 (或者,您可以在项目文件中硬编码文件名。)
MSBuild 为 C# 和 Visual Basic 项目提供的目标定义通过使用项目文件中定义的 <ProjectReference> 项来处理依赖项,而不是在解决方案文件中定义依赖项。 Delphi .dproj 文件和 C++ Builder .cbproj 文件不支持这一点,因为底层 CodeGear.Common.Targets 不会重用在 Microsoft.Common.Targets 中为 <ProjectReference> 定义的机制。