意外的AfterTargets =依赖项目的“构建”执行顺序

时间:2018-04-28 20:02:07

标签: msbuild msbuild-target

我在Visual Studio 2017中有两个多目标项目。

项目依赖

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFrameworks>netcoreapp2.0;net45</TargetFrameworks>
  </PropertyGroup>

  <Target Name="DependencyAfterBuild" AfterTargets="Build">
    <Message Text="DependencyAfterBuild  IsCrossTargetingBuild=$(IsCrossTargetingBuild)" />
  </Target>

</Project>

项目主要

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFrameworks>netcoreapp2.0;net45</TargetFrameworks>
  </PropertyGroup>

    <PropertyGroup>
        <TestProperty>Exe</TestProperty>
    </PropertyGroup>

  <Target Name="MainAfterBuild" AfterTargets="Build">
    <Message Text="MainAfterBuild IsCrossTargetingBuild=$(IsCrossTargetingBuild)" />
  </Target> 

  <ItemGroup>
    <ProjectReference Include="..\ClassLibrary1\Dependency.csproj" />
  </ItemGroup>

</Project>

项目主要取决于依赖性。 我希望构建输出是

DependencyAfterBuild  IsCrossTargetingBuild=
DependencyAfterBuild  IsCrossTargetingBuild=
DependencyAfterBuild  IsCrossTargetingBuild=true
MainAfterBuild IsCrossTargetingBuild=
MainAfterBuild IsCrossTargetingBuild=
MainAfterBuild IsCrossTargetingBuild=true

当我使用visual studio 2017构建解决方案时,我得到了输出

但是当我从cmd运行msbuild时,我得到下一个输出

DependencyAfterBuild  IsCrossTargetingBuild=
MainAfterBuild IsCrossTargetingBuild=
DependencyAfterBuild  IsCrossTargetingBuild=
MainAfterBuild IsCrossTargetingBuild=
MainAfterBuild IsCrossTargetingBuild=true
DependencyAfterBuild  IsCrossTargetingBuild=true

这个顺序有些意外(并在实际项目中打破了我的自定义逻辑)。

为什么“DependencyAfterBuild IsCrossTargetingBuild = true”的运行时间晚于“MainAfterBuild IsCrossTargetingBuild = true”?

我需要修改我的项目以便msbuild在“MainAfterBuild IsCrossTargetingBuild = true”之前运行“DependencyAfterBuild IsCrossTargetingBuild = true”。

2 个答案:

答案 0 :(得分:1)

这里有一些事情可以发挥作用:

首先,Visual Studio构建有点不同 - 它计算出项目依赖性,但是在VS内部组件解析的顺序中,单个项目的构建可能会也可能不会发生。项目系统可以决定项目是“最新的”并完全跳过为该项目调用MSBuild。

因此,在解决方案上调用命令行MSBuild可能会有所不同,因为所有项目都是按需构建的,而不一定是特定的顺序。如果您更改了订单,则在.sln文件(Project… EndProject部分)中定义了项目,订单将是不同的。

要强制执行特殊操作,您可以在解决方案中使用项目依赖项,这将回答您可以对其执行的操作的问题(警告:使用此功能时存在NuGet错误)。

在您的情况下,首先构建msbuild选择Main项目。

由于它是一个多目标项目,它将为每个目标框架分离“内部构建”。

这些内部构建引用了“DependencyAfterBuild”项目,该项目也是一个多目标项目。当引用多目标项目时,只有一个目标框架被构建为引用 - 因此msbuild为依赖项选择“最近的目标框架”。这就是您首先看到DependencyAfterBuild IsCrossTargetingBuild=行(以及主项目的类似行之前)的原因。

内部构建完成后,主项目的后构建目标将运行。

由于您正在构建解决方案而不仅仅是主项目,因此也会调用依赖项目的“构建”目标,因为它也在您正在构建的解决方案中。由于内部构建已经执行,因此将跳过它们,并且不会显示其他后构建消息。

如果您手动添加项目依赖项或只是编辑.sln文件来更改项目的定义顺序,您将看到所有“DependencyAfterBuild”目标在所有主项目的目标之前运行。

答案 1 :(得分:0)

完整性。 我有sln文件

Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Main", "ConsoleApp16\Main.csproj", "{52892173-D25E-43B7-9E14-248C37CF422B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dependency", "ClassLibrary1\Dependency.csproj", "{14E1692E-FDB4-46F7-85DF-7B6EFF7B46A6}"
EndProject

并且在msbuild中以意外顺序调用了afterbuild目标。

仅当我手动更改sln文件时如下

Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Main", "ConsoleApp16\Main.csproj", "{52892173-D25E-43B7-9E14-248C37CF422B}"
    ProjectSection(ProjectDependencies) = postProject
        {14E1692E-FDB4-46F7-85DF-7B6EFF7B46A6} = {14E1692E-FDB4-46F7-85DF-7B6EFF7B46A6}
    EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dependency", "ClassLibrary1\Dependency.csproj", "{14E1692E-FDB4-46F7-85DF-7B6EFF7B46A6}"
EndProject

我设法得到“所需”的执行顺序如下

DependencyAfterBuild  IsCrossTargetingBuild=
DependencyAfterBuild  IsCrossTargetingBuild=
DependencyAfterBuild  IsCrossTargetingBuild=true
MainAfterBuild IsCrossTargetingBuild=
MainAfterBuild IsCrossTargetingBuild=
MainAfterBuild IsCrossTargetingBuild=true