8

我想分析和调整我们的构建,希望在这里和那里节省几秒钟。我能够创建一个派生自 ResolveAssemblyReferences 的任务并改用它,但我在理解以下内容时遇到了问题(来自 Microsoft.Common.targets):

<!--
    ============================================================
                                        ResolveProjectReferences

    Build referenced projects:

        [IN]
        @(NonVCProjectReference) - The list of non-VC project references.

        [OUT]
        @(_ResolvedProjectReferencePaths) - Paths to referenced projects.
    ============================================================
    -->
    <Target
        Name="ResolveProjectReferences"
        DependsOnTargets="SplitProjectReferencesByType;_SplitProjectReferencesByFileExistence">

        <!--
        When building this project from the IDE or when building a .SLN from the command-line,
        just gather the referenced build outputs.  The code that builds the .SLN will already have
        built the project, so there's no need to do it again here.

        The ContinueOnError setting is here so that, during project load, as
        much information as possible will be passed to the compilers.
        -->
        <MSBuild
            Projects="@(_MSBuildProjectReferenceExistent)"
            Targets="GetTargetPath"
            BuildInParallel="$(BuildInParallel)"
            UnloadProjectsOnCompletion="$(UnloadProjectsOnCompletion)"
            Properties="%(_MSBuildProjectReferenceExistent.SetConfiguration); %(_MSBuildProjectReferenceExistent.SetPlatform)"
            Condition="'@(NonVCProjectReference)'!='' and ('$(BuildingSolutionFile)' == 'true' or '$(BuildingInsideVisualStudio)' == 'true' or '$(BuildProjectReferences)' != 'true') and '@(_MSBuildProjectReferenceExistent)' != ''"
            ContinueOnError="!$(BuildingProject)">

            <Output TaskParameter="TargetOutputs" ItemName="_ResolvedProjectReferencePaths"/>
        </MSBuild>

        <!--
        Build referenced projects when building from the command line.

        The $(ProjectReferenceBuildTargets) will normally be blank so that the project's default
        target is used during a P2P reference. However if a custom build process requires that
        the referenced project has a different target to build it can be specified.
        -->
        <MSBuild
            Projects="@(_MSBuildProjectReferenceExistent)"
            Targets="$(ProjectReferenceBuildTargets)"
            BuildInParallel="$(BuildInParallel)"
            UnloadProjectsOnCompletion="$(UnloadProjectsOnCompletion)"
            Condition="'@(NonVCProjectReference)'!='' and '$(BuildingInsideVisualStudio)' != 'true' and '$(BuildingSolutionFile)' != 'true' and '$(BuildProjectReferences)' == 'true' and '@(_MSBuildProjectReferenceExistent)' != ''">
            <Output TaskParameter="TargetOutputs" ItemName="_ResolvedProjectReferencePaths"/>

        </MSBuild>

        <!--
        Get manifest items from the (non-exe) built project references (to feed them into ResolveNativeReference).
        -->
        <MSBuild
            Projects="@(_MSBuildProjectReferenceExistent)"
            Targets="GetNativeManifest"
            BuildInParallel="$(BuildInParallel)"
            UnloadProjectsOnCompletion="$(UnloadProjectsOnCompletion)"
            Properties="%(_MSBuildProjectReferenceExistent.SetConfiguration); %(_MSBuildProjectReferenceExistent.SetPlatform)"
            Condition="'@(NonVCProjectReference)'!='' and '$(BuildingProject)'=='true' and '@(_MSBuildProjectReferenceExistent)'!=''">

            <Output TaskParameter="TargetOutputs" ItemName="NativeReference"/>

        </MSBuild>


        <!-- Issue a warning for each non-existent project. -->
        <Warning
            Text="The referenced project '%(_MSBuildProjectReferenceNonexistent.Identity)' does not exist."
            Condition="'@(NonVCProjectReference)'!='' and '@(_MSBuildProjectReferenceNonexistent)'!=''"/>
    </Target>

一些参数被传递,一些参数被返回,但实际工作发生在哪里呢?msdn 上的内容不多——我找到了 Microsoft.Build.Tasks.ResolveProjectBase,但它没有多大用处。

4

1 回答 1

14

ResolveProjectReferences(至少是您指向的那个)是一个目标,用于通过使用<MSBuild>任务构建项目间引用来解析它们。这个任务需要一个项目文件来构建,以及项目中一个或多个目标的名称,这些目标应该作为构建的一部分被调用(它还需要其他参数,但您现在可以忽略这些参数)。

考虑以下目标:

<Target
  Name="Build"
  Returns="@(BuildOutput)">

  <ItemGroup>
    <BuildOutput Include="bin\Debug\Foo.exe" />
  </ItemGroup>
</Target>

如果您引用了一个包含此目标的项目,并且想要解析“Foo”目标的输出,那么您的项目中将有一个 <ProjectReference> 元素,如下所示:

<ItemGroup>
  <ProjectReference Include="..\SomeProject\SomeProject.proj">
    <Targets>Build</Targets>
  </ProjectReference>
</ItemGroup>

请注意,如果“构建”是引用项目的默认目标,您可以完全关闭“目标”元数据。您还可以在 Targets 元数据(以分号分隔的列表)中指定多个目标。

因此,您的 ResolveProjectReferences 目标将出现并调用 <MSBuild> 任务,将其传递给“..\SomeProject\SomeProject.proj”并要求它构建“Build”目标。现在,由于“构建”目标通过其 Returns 属性指定输出(但如果未指定 Returns 属性,将使用 Outputs 属性),这些输出将在构建期间收集,并在 <MSBuild> 任务的 TargetOutputs 参数中返回. 他们添加了几条额外的元数据,使您能够通过原始目标来隔离它们。这些包括:

  • MSBuildSourceProjectFile - 其构建生成输出的引用项目
  • MSBuildSourceTargetName - 生成生成输出的目标的名称

如果您在 C# 项目中工作,则还有许多其他参考解析阶段(包括程序集解析)。如果您想了解这些,请给我留言。

于 2011-09-01T13:28:21.347 回答