Visual studio 在CoreBuild之前运行目标?

Visual studio 在CoreBuild之前运行目标?,visual-studio,msbuild,Visual Studio,Msbuild,我正在将自定义的.tt模板生成目标添加到我的项目中,以便在CoreBuild之前运行,似乎有两种方法: <Project...> <Target Name="TransformOnBuild" AfterTargets="BeforeBuild"> </Project> 及 如果我的目标应该在我的项目构建之前运行,因为项目依赖于它,那么使用后者会更好吗?我见过前者用于生成文本模板,但这似乎是一种不可靠的方法,因为它可能在CoreBuild之后

我正在将自定义的
.tt
模板生成目标添加到我的项目中,以便在
CoreBuild
之前运行,似乎有两种方法:

<Project...>
    <Target Name="TransformOnBuild" AfterTargets="BeforeBuild">
</Project>


如果我的目标应该在我的项目构建之前运行,因为项目依赖于它,那么使用后者会更好吗?我见过前者用于生成文本模板,但这似乎是一种不可靠的方法,因为它可能在
CoreBuild
之后运行,这太晚了。或者是有什么原因使得
postertargets=“BeforeBuild”
仍然保证在核心构建之前运行


我还看到了将更早构建的
BeforeTargets=“BeforeBuild”
。这是放置“.tt文本生成目标”的更好位置吗?

从Microsoft.Common.CurrentVersion.targets,构建目标基本上是:

<BuildDependsOn>
  BeforeBuild;
  CoreBuild;
  AfterBuild
</BuildDependsOn>
<Target Name="Build" DependsOnTargets="$(BuildDependsOn)"/>

<PropertyGroup>
  <CoreBuildDependsOn>
    PrepareForBuild;
    PreBuildEvent;
    ...
    Compile;
    ...
    PostBuildEvent
  </CoreBuildDependsOn>
</PropertyGroup>
<Target Name="CoreBuild" DependsOnTargets="$(CoreBuildDependsOn)">

建造前;
核心构建;
后建
准备建造;
预构建事件;
...
编撰;
...
构建后事件

所以使用
BeforeTargets=“CoreBuild”
确实会在CoreBuild之前运行,但这毕竟是它的依赖目标运行之后,所以在所有实际的构建步骤之后。这通常不是你想要的,相反,如果你想在编译之前运行一些东西,可以使用
BeforeTargets=“PrepareForBuild”
或者确实是
postertargets=“BeforeBuild”
或者甚至
BeforeTargets=“BeforeBuild”
基于@stjin的答案,一个好的解决方案似乎是使用

BeforeTargets="CoreCompile" DependsOnTargets="PrepareForBuild"
这就是.net sdk(针对.net核心/标准项目的新型csproj)的功能

它使用以下注释来解释原因:

注意,这必须在每次调用CoreCompile之前运行 确保所有编译器运行都能看到生成的程序集信息。那里 至少有一个场景涉及调用CoreCompile的Xaml 没有其他潜在的钩子,比如编译或CoreBuild等,所以 我们直接连接到CoreCompile。此外,我们必须紧跟其后 PrepareForBuild以确保已创建中间目录 创造


请注意,“中间目录”(
obj/[TargetFramework]
在本例中)是输出
.cs
文件所在的位置,这可能也是您想要执行的操作。

更新2

根据:

这是目标构建顺序

  • 运行初始目标
  • 运行/target开关在命令行上指定的目标。如果在命令行上未指定任何目标,则将运行DefaultTargets目标。如果两者都不存在,则运行遇到的第一个目标
  • 将计算目标的条件属性。如果Condition属性存在并且计算结果为false,则不会执行目标,并且对构建没有进一步的影响
  • 在执行目标之前,将运行其DependsOnTargets目标。
  • 在执行目标之前,将运行在BeforeTargets属性中列出该目标的任何目标。
  • 在执行目标之前,将比较其输入属性和输出属性。如果MSBuild确定任何输出文件相对于相应的一个或多个输入文件已过期,则MSBuild将执行目标。否则,MSBuild将跳过目标
  • 执行或跳过目标后,将运行在“后目标”属性中列出该目标的任何目标
  • 以下是您问题的答案:

    如果我的目标应该在我的项目构建之前运行,因为项目依赖于它,那么使用后者会更好吗?

    • 不,因为CoreBuild的所有依赖项都将在模板生成目标之前执行,这太晚了
    或者有什么原因可以保证PostTargets=“BeforeBuild”在核心构建之前运行?

    > there appear to be 2 ways of doing it.
    
        There are more options to achieve this. Please review below.
    
    • AfterTargets=“BeforeBuild”保证您的目标将按时执行,因为它将在所有CoreBuild依赖项之前执行
    我还看到了BeforeTargets=“BeforeBuild”,它将更早地构建。这是放置“.tt文本生成目标”的更好地方吗?

    > there appear to be 2 ways of doing it.
    
        There are more options to achieve this. Please review below.
    
    • 在这两种情况下,AfterTargets=“BeforeBuild”或BeforeTargets=“BeforeBuild”您的目标将在所有CoreBuild依赖项之前执行,但是在这两种情况下,您仍然有影响模板生成目标结果的风险,这取决于您必须在BeforeBuild中执行的内容。如果您控制住了这一点,您可以安全地使用这些选项中的任何一个
    在核心构建之前运行目标?

    > there appear to be 2 ways of doing it.
    
        There are more options to achieve this. Please review below.
    

    为此,您应该使用特定的内置目标(预构建或后构建)。这是Microsoft在使用依赖于Microsoft.Common.targets的项目时提供的机制

    如果在CoreBuild之前只有一个目标要运行,则可以执行以下操作:

    <Target Name="BeforeBuild">
        <!-- add your tasks here -->
    </Target>
    
    
    
    如果在CoreBuild之前要运行多个目标,则可以定义一个属性,其中包含需要按所需执行顺序调用的所有目标:

    <PropertyGroup>
        <BeforeBuildDependsOn>
          CustomTarget1;
          CustomTarget2;
          CustomTarget3
        </BeforeBuildDependsOn>
    </PropertyGroup>
    
    <Target Name="BeforeBuild" DependsOnTargets="$(BeforeBuildDependsOn)"/>
    
    
    客户目标1;
    客户目标2;
    客户目标3
    
    更新:

    根据@stijn提供的片段:

    AfterTargets=“BeforeBuild”将插入/执行如下自定义目标:(取决于BeforeBuild

    
    建造前;
    |->自定义目标
    核心构建;
    后建
    
    BeforeTargets=“CoreBuild”将插入/执行如下自定义命令(取决于CoreBuild):

    
    建造前;
    |->自定义目标
    核心构建;
    后建
    
    因此,“模板生成目标”将在同一个位置执行(在BeforeBuild和CoreBuild之间,但取决于不同的目标,这就是为什么要使用合适的目标
    <BuildDependsOn>
      BeforeBuild;
    
    
           |-> Custom Target
      CoreBuild;
      AfterBuild
    </BuildDependsOn>
    
    <PropertyGroup>
        <BuildDependsOn>
          BeforeBuild;
          CoreBuild;
          AfterBuild
        </BuildDependsOn>
    </PropertyGroup>
    
    <Target Name="Build" DependsOnTargets="$(BuildDependsOn)"/>
    
    <PropertyGroup>
        <BuildDependsOn>
          MyCustomThirdParty;
          $(BuildDependsOn);
        </BuildDependsOn>
    </PropertyGroup>
    
    <PropertyGroup>
        <MyCustomThirdPartyDependsOn>
          BeforeMyCustomThirdParty;
          CustomStep1;
          CustomStep2;
          CustomStep1;
          AfterMyCustomThirdParty
        </MyCustomThirdPartyDependsOn>
    </PropertyGroup>
    
    <Target Name="MyCustomThirdParty" DependsOnTargets="$(MyCustomThirdPartyDependsOn)"/>
    
    <PropertyGroup>
        <BuildDependsOn>
          BeforeBuild;
          MyCustomThirdParty;
          CoreBuild;
          AfterBuild
        </BuildDependsOn>
    </PropertyGroup>