在Tar​​getFrameworks代码中每个框架运行一次的目标之前,如何制作仅运行一次而不是一次的MSBuild目标?

时间:2017-10-10 20:50:26

标签: c# visual-studio-2017 csproj msbuild-15

我有一个代码生成器工具,我部分拥有,现在csproj文件可以在其中列出多个目标框架并构建所有这些,我试图弄清楚如何使MSBuild目标进行代码生成每次运行构建时,无论列出多少个目标框架,并且每个目标框架的编译都等到代码生成完成。

我目前以TargetFramework的特定值为条件。例如,Condition="'netstandard2.0' == '$(TargetFramework)'"

这避免了代码生成工具同时针对每个Target Framework启动,然后在进程尝试创建/更新相同文件时获取访问被拒绝错误。

然而,其他目标框架正确地尝试编译而不等待代码生成完成,并且在没有代码存在的情况下失败。

我希望每次构建项目时只生成一次代码生成,并且每个Target Framework的编译只在完成一次后才开始。

每次运行构建时都需要运行,以防输入发生变化并生成不同的代码。

注意:目前我忽略了#if FrameworkSpecificDefine用于为代码生成器提供不同输入代码的情况,这样不同的目标框架会导致代码生成器的输出不同。目前,我正在考虑代码生成器的输出在所有目标框架中是相同且有效的。

更新:在MSBuild拆分为TargetFramework特定版本之前找到一个Target后,我可以在之前挂钩构建,我在VS中的详细构建输出中看到了这一点:

1>Target _SetBuildInnerTarget:
1>Target _ComputeTargetFrameworkItems:
1>Target DispatchToInnerBuilds:
1>  Using "MSBuild" task from assembly "Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".
1>  Task "MSBuild"
1>    Additional Properties for project "ProjectA.csproj":
1>      TargetFramework=netstandard2.0
1>    Additional Properties for project "ProjectA.csproj":
1>      TargetFramework=net47

然后我将目标设置为BeforeTargets="DispatchToInnerBuilds",然后在专门设置TargetFramework的个人构建之前运行,并且似乎完全符合我的需求。

(添加到BuildDependsOn属性似乎不再起作用:Add a msbuild task that runs after building a .NET Core project in Visual Studio 2017 RC;我怀疑稍后会以新的csproj格式评估Microsoft.Common.targets,以及任何附加到属性的内容您在项目文件中执行的操作将被Microsoft.Common.targets覆盖。)

3 个答案:

答案 0 :(得分:1)

单个目标框架上,我仅使用BeforeTargets="PreBuildEvent"

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>
  <Target Name="GenerateVersionInfo" BeforeTargets="PreBuildEvent">
    <Exec Command="your custom command" />
  </Target>
</Project>

多目标框架上,我使用BeforeTargets="DispatchToInnerBuilds"

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>netstandard2.0;net461</TargetFrameworks>
  </PropertyGroup>
  <Target Name="GenerateVersionInfo" BeforeTargets="DispatchToInnerBuilds">
    <Exec Command="your custom command" />
  </Target>
</Project>

因此,我的自定义命令在每次构建之前仅执行一次。如果您使用InitialTargets,则该命令的执行次数将不止一次!例如,如果您保存您的项目!

答案 1 :(得分:0)

虽然有些目标仅在内部版本中运行,例如当您使用BeforeTargets="BeforeBuild"时,外部构建还定义了IsCrossTargetingBuild变量,以指示当前正在运行的构建是外部构建,该构建将调度到内部构建,并且是调整目标的首选方式。

因此,您可以像Condition="'$(IsCrossTargetingBuild)' == 'true'"一样调整目标,以确保目标仅针对外部版本运行。

答案 2 :(得分:0)

另一种方法是在要更改nuget文件时使用GenerateNuspec

       

打包后,您将发现Foo输出一次。