意外的 AfterTargets="Build" 依赖项目的执行顺序
Unexpected AfterTargets="Build" execution order for dependent projects
我在 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" 晚?
我需要如何在 "MainAfterBuild IsCrossTargetingBuild=true".
之前将我的 msbuild 项目修改为 运行 "DependencyAfterBuild IsCrossTargetingBuild=true"
这里有几件事在起作用:
首先,Visual Studio 构建有点不同 - 它计算出项目依赖关系,但个别项目的构建可能会或可能不会发生,顺序由 VS 内部的组件解决。项目系统可能会决定某个项目是 "up-to-date" 并完全跳过为该项目调用 MSBuild。
因此,在解决方案上调用命令行 MSBuild 的行为可能会有所不同,因为所有项目都是根据需要按特定顺序构建的。如果您更改了项目在 .sln 文件(Project… EndProject
部分)中定义的顺序,则顺序会有所不同。
要强制执行特殊顺序,您可以在解决方案中使用项目依赖项,这将回答您可以采取哪些措施的问题(注意:使用此功能时存在 NuGet 错误)。
在您的情况下,主项目由 msbuild 选择首先构建。
由于它是一个多目标项目,它将针对每个目标框架分拆 "inner builds"。
这些内部构建引用了 "DependencyAfterBuild" 项目,该项目也是一个多目标项目。当引用一个多目标项目时,只有一个目标框架被构建为引用 - 因此 msbuild 选择 "nearest target framework" 作为依赖项。这就是为什么您首先看到 DependencyAfterBuild IsCrossTargetingBuild=
行(并且在主项目的类似行之前)。
内部构建完成后,主项目的构建目标 运行s.
由于您正在构建一个解决方案而不是单独的主项目,因此也会调用依赖项项目的 "Build" 目标,因为它也在您正在构建的解决方案中。由于已经执行了内部构建,因此将跳过它们并且不会显示额外的构建后消息。
如果您手动添加项目依赖项或只是编辑 .sln 文件以更改项目定义的顺序,您会看到所有 "DependencyAfterBuild" 目标都是 运行主要项目的目标。
为了完整性。
我有 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
我设法得到 "desired" 执行顺序如下
DependencyAfterBuild IsCrossTargetingBuild=
DependencyAfterBuild IsCrossTargetingBuild=
DependencyAfterBuild IsCrossTargetingBuild=true
MainAfterBuild IsCrossTargetingBuild=
MainAfterBuild IsCrossTargetingBuild=
MainAfterBuild IsCrossTargetingBuild=true
我在 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" 晚?
我需要如何在 "MainAfterBuild IsCrossTargetingBuild=true".
之前将我的 msbuild 项目修改为 运行 "DependencyAfterBuild IsCrossTargetingBuild=true"这里有几件事在起作用:
首先,Visual Studio 构建有点不同 - 它计算出项目依赖关系,但个别项目的构建可能会或可能不会发生,顺序由 VS 内部的组件解决。项目系统可能会决定某个项目是 "up-to-date" 并完全跳过为该项目调用 MSBuild。
因此,在解决方案上调用命令行 MSBuild 的行为可能会有所不同,因为所有项目都是根据需要按特定顺序构建的。如果您更改了项目在 .sln 文件(Project… EndProject
部分)中定义的顺序,则顺序会有所不同。
要强制执行特殊顺序,您可以在解决方案中使用项目依赖项,这将回答您可以采取哪些措施的问题(注意:使用此功能时存在 NuGet 错误)。
在您的情况下,主项目由 msbuild 选择首先构建。
由于它是一个多目标项目,它将针对每个目标框架分拆 "inner builds"。
这些内部构建引用了 "DependencyAfterBuild" 项目,该项目也是一个多目标项目。当引用一个多目标项目时,只有一个目标框架被构建为引用 - 因此 msbuild 选择 "nearest target framework" 作为依赖项。这就是为什么您首先看到 DependencyAfterBuild IsCrossTargetingBuild=
行(并且在主项目的类似行之前)。
内部构建完成后,主项目的构建目标 运行s.
由于您正在构建一个解决方案而不是单独的主项目,因此也会调用依赖项项目的 "Build" 目标,因为它也在您正在构建的解决方案中。由于已经执行了内部构建,因此将跳过它们并且不会显示额外的构建后消息。
如果您手动添加项目依赖项或只是编辑 .sln 文件以更改项目定义的顺序,您会看到所有 "DependencyAfterBuild" 目标都是 运行主要项目的目标。
为了完整性。 我有 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
我设法得到 "desired" 执行顺序如下
DependencyAfterBuild IsCrossTargetingBuild=
DependencyAfterBuild IsCrossTargetingBuild=
DependencyAfterBuild IsCrossTargetingBuild=true
MainAfterBuild IsCrossTargetingBuild=
MainAfterBuild IsCrossTargetingBuild=
MainAfterBuild IsCrossTargetingBuild=true