【问题标题】:How does ResolveProjectReferences work?ResolveProjectReferences 是如何工作的?
【发布时间】:2011-09-01 08:58:13
【问题描述】:

我想分析和调整我们的构建,希望能在这里和那里节省几秒钟。我能够创建一个派生自 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,但它没有多大用处。

【问题讨论】:

    标签: msbuild build resolveassemblyreference


    【解决方案1】:

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

    考虑以下目标:

    <Target
      Name="Build"
      Returns="@(BuildOutput)">
    
      <ItemGroup>
        <BuildOutput Include="bin\Debug\Foo.exe" />
      </ItemGroup>
    </Target>
    

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

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

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

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

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

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

    【讨论】:

    • 那么,如果发现 ResolveProjectReferences 阶段在构建期间花费了大量时间,那实际上是因为项目被阻止、等待或构建依赖项?我还没有找到任何明确的文档。目前尚不清楚这是花费在识别和定位依赖项上的时间(实际工作),还是花费在等待依赖项可用的时间(实际上是空闲时间)
    • 您最好的选择是在诊断详细级别构建。这将准确地向您展示每个目标正在做什么(包括嵌套构建)以及许多操作的时间安排。
    猜你喜欢
    • 1970-01-01
    • 2017-07-24
    • 2016-11-13
    • 2017-10-11
    • 2021-10-13
    • 2011-02-24
    • 2013-11-16
    • 2011-10-16
    • 2012-11-03
    相关资源
    最近更新 更多