如何在编译前运行 MSBuild 目标,但仅在编译将发生时运行?

8

我有一个C#库项目,其中一些依赖项是在使用PowerShell的“BeforeBuild”中创建的。

似乎每次都会执行目标“BeforeBuild”,即使库项目本身不需要构建。

我想配置构建过程,仅在需要(重新)构建库时才运行PowerShell脚本。

有办法实现吗?

我尝试使用目标“BeforeBuild”和“BeforeCompile”。但似乎每次都会执行。


朋友,这个问题有什么更新吗? - LoLance
2个回答

3
您无法真正预测编译是否会发生,因为您无法知道在目标运行后目标可能执行什么操作。但是,您可以根据构建目录的当前状态来预测任务是否需要运行。这就是您在MsBuild中实现增量构建的方式,这似乎是您真正想要的。
所有目标都有一个可选的Inputs和Outputs参数。这两个参数用于计算自上次构建以来输入是否发生了更改,并基于此来决定是否运行您的目标或是否可以跳过它。
这需要一些知识,基于您的构建中ItemGroups和Properties的当前状态来预测您目标的结果。
当未指定Inputs和Outputs时,MsBuild无法确定您的目标是否会影响任何内容,因此将运行它以确保安全。 文档提供了关于如何启用自定义目标的增量构建的良好解释。 要预测输出,您需要编写某种转换。或者,您可以编写某种标记文件(如 codeanalysis.lastsucceeded ),并使用该文件进行比较。增量构建将仅查看所有输入的最后更改日期,并将其与所有输出进行比较。因此,您需要将运行或不运行的需求表达为该数据的操作。
基本结构:
<target name="RunMyPowerShell" 
    beforetargets="Compile" Inputs="@(Content)" 
    Outputs"@(Content->'%(Filename).translated.content')">
    ...
    <exec Command="powershell .\mypsfile.ps1" />
    ...
</targets>

作为 BeforeTargets="Build" 的替代方案,您可以覆盖 BuildDependsOn 属性:
<PropertyGroup>
    <CompileDependsOn>
        RunMyPowerShell;
        $(CompileDependsOn)
    </CompileDependsOn>
</PropertyGroup>

如果你之前没有涉足过这个领域,MsBuild的所有细节可能会让人感到不知所措。要使其正常工作,你需要掌握很多东西。这也可能需要对PowerShell脚本进行更改,以使其输出足够可预测,以便MsBuild发挥其魔力。

另一种方法是在目标上添加一个基于某些表达式的条件,但是由于建立文件被解析、计算和执行的方式,这样做可能会很难弄明白如何正确执行。

如果你能做到这些,可能会有巨大的性能提升。

另请参见:


0
MSBuild似乎每次都会执行目标“BeforeBuild”,即使库项目本身不需要构建。如果库项目不需要构建,为什么要调用msbuild来构建它?我知道“BeforeBuild”是构建过程中必要的一个目标之一,因此如果你构建一个项目,它总是会调用此目标。更多细节可以更好:)
我想配置构建过程只在需要(重新)构建库时运行PowerShell脚本。有没有办法做到这一点?我试图使用目标“BeforeBuild”和“BeforeCompile”。但它似乎每次都会执行。 "BeforeBuild"和" BeforeCompile"是MSBuild系统中预定义的目标。您可以覆盖它们以自定义构建步骤,但您无法避免在构建过程中运行它们。所以,如果启动构建,它们将每次执行,这是设计上的预期行为。
根据您的描述,您可能会覆盖这些目标并在其中运行PowerShell脚本。这就是为什么在您的机器上它将始终调用ps脚本的原因。
如果您使用msbuild.exe而不是VS IDE构建项目,则可以使用以下解决方法:
假设您已经在项目文件中覆盖了BeforeTarget。您可以添加一个condition来确定是否运行自定义BeforeTarget(调用ps脚本)或原始BeforeTarget。
定义一个名为RunPS的属性,并以以下方式向您使用的BeforeTarget添加条件:
  <PropertyGroup>
    <RunPS>false</RunPS>
  </PropertyGroup>

  <Target Name="BeforeBuild" Condition="$(RunPS)=='true'">
   <!--Run the ps script here-->  
  </Target>

然后,您可以通过设置RunPS的值来控制是否使用默认的BeforeTarget或自定义BeforeTarget。

msbuild xx.csproj /p:RunPS=true在构建过程中运行ps脚本,msbuild xx.csproj运行原始的BeforeTarget

如果您在VS IDE中构建项目,则可以创建从Debug或Release复制的新配置(CustomDebug),并将Condition="$(Configuration)=='CustomDebug'"设置为目标。

更新:

适用于VS和命令行的解决方法:

请参见this document,在VS中,我们可以通过从Debug和Release Configurations复制设置轻松创建新配置。

1.我认为,对于您的库项目,您有普通的Debug和Release Configurations,您可以按照文档中的提示创建相应的自定义配置。从Debug中复制设置并创建一个名为PSDebug的新配置,从Release中复制设置并创建一个名为PSRelease的新配置。

2.然后编辑xx.csproj,在此格式中添加条件:

  <Target Name="BeforeBuild" Condition="'$(Configuration)'=='PSDebug' OR '$(Configuration)'=='PSRelease'">
    <!--Run the ps script here-->
    <Message Text="showsth" Importance="high" />
  </Target>

然后在VS IDE中,如果您使用普通配置Debug或Release进行构建,则会使用默认的BeforeBuild目标。只有当您使用自定义PSDebug或PSRelease进行构建时,它才会调用您的自定义BeforeBuild目标。在VS中,您可以通过此框轻松切换这些配置:

enter image description here

对于命令行,它同样适用。如果您使用像 msbuild xx.csproj /p:Configuration=Debug 这样的命令,它将使用预定义的 BeforeBuild 目标来执行此操作,如果您使用像 msbuild xx.csproj /p:Configuration=PSDebug 这样的命令,则会调用您的自定义目标并运行 PS 脚本。


谢谢您的建议!我明白这种行为是“按设计要求”的!但是我不能使用您的解决方案,因为它需要在VS中工作。 - Ingo Karstein
@IngoKarstein,请看我的更新,由于这是设计行为,我们没有VS选项可以直接控制它。但是VS允许我们从Debug和Release创建新的配置,因此我们可以通过自定义项目文件来实现该行为。希望能有所帮助 :) - LoLance

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接