Visual studio 如何在编译之前但仅在编译发生时运行MSBuild目标

Visual studio 如何在编译之前但仅在编译发生时运行MSBuild目标,visual-studio,msbuild,msbuild-task,incremental-build,Visual Studio,Msbuild,Msbuild Task,Incremental Build,我有一个C#library项目,其中包含一些在“BeforeBuild”中使用PowerShell创建的依赖项 MSBuild似乎每次都执行目标“BeforeBuild”,如果库项目本身不需要生成,也是如此 我希望将生成过程配置为仅在库需要(重新)生成时运行PowerShell脚本 有办法做到这一点吗 我尝试使用目标“BeforeBuild”和“beforecomile”。但它似乎每次都会执行 MSBuild似乎每次都执行“BeforeBuild”目标,就好像库项目本身不需要生成一样 如果库项目

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

MSBuild似乎每次都执行目标“BeforeBuild”,如果库项目本身不需要生成,也是如此

我希望将生成过程配置为仅在库需要(重新)生成时运行PowerShell脚本

有办法做到这一点吗

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

MSBuild似乎每次都执行“BeforeBuild”目标,就好像库项目本身不需要生成一样

如果库项目本身不需要生成,那么msbuild每次执行目标是什么意思?正如我所知,
BeforeBuild
是构建过程中的一个必要目标,因此如果构建一个项目,它将始终调用此目标。如果库项目不需要生成,那么调用msbuild来生成它的原因是什么?更多细节可能更好:)

我想将生成过程配置为仅运行PowerShell 如果库需要(重新)构建,请编写脚本

有办法做到这一点吗

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

BeforeBuild
BeforeCompile
是msbuild系统中预定义的目标。您可以覆盖它们以自定义构建步骤,但无法避免在构建过程中运行它们。因此,如果构建每次启动,它们都会执行,这是设计所期望的行为

根据您的描述,您可以覆盖这些目标并在其中运行powershell脚本。这就是为什么在您的机器中它总是调用ps脚本

如果使用msbuild.exe而不是VS IDE生成项目,这里有一个解决方法:

假设您在项目文件中覆盖了BeforeTarget。您可以添加一个,以确定是在目标之前运行自定义的(调用ps脚本),还是在目标之前运行原始的

定义名为
RunPS
的属性,并将条件添加到您使用的BeforeTarget中,方法如下:

  <PropertyGroup>
    <RunPS>false</RunPS>
  </PropertyGroup>

  <Target Name="BeforeBuild" Condition="$(RunPS)=='true'">
   <!--Run the ps script here-->  
  </Target>
然后在VS IDE中,如果您使用正常配置进行编译
调试或发布
,它将在编译之前使用默认的
目标。仅当您使用自定义
PSDebug或PSRelease
进行生成时,它才会在生成之前调用自定义
目标。在VS中,您可以通过以下框轻松地在这些配置之间切换:


对于命令行,它也可以工作。如果使用类似于
msbuild xx.csproj/p:Configuration=Debug
的命令,它将使用预定义的BeforeBuild目标来执行此操作,如果使用类似于
msbuild xx.csproj/p:Configuration=PSDebug
的命令,它将调用自定义目标并运行PS脚本

您无法真正预测编译是否会发生,因为您无法知道目标运行后可能会做什么或不做什么。但是,您可以根据构建目录的当前状态预测任务是否需要运行。这就是如何在MsBuild中实现增量构建,这听起来像是您真正想要的

所有目标都有一个可选的输入和输出参数。这两个用于计算自上次生成以来是否有任何输入发生了更改,并根据该MsBuild决定是否运行目标或是否可以跳过目标

这需要一些基于构建中项目组和属性的当前状态的知识来预测目标的结果

当未指定输入和输出时,MsBuild无法确定您的目标是否会影响任何内容,因此它将运行它以确保安全

要预测输出,您需要编写某种转换。或者,您可以编写某种标记文件(如
codeanalysis.lastSuccessed
),并使用该文件进行比较。增量构建将只查看所有输入的最后更改日期,并将其与所有输出进行比较。因此,您需要将是否需要运行表示为对该数据的操作

基本结构:

<target name="RunMyPowerShell" 
    beforetargets="Compile" Inputs="@(Content)" 
    Outputs"@(Content->'%(Filename).translated.content')">
    ...
    <exec Command="powershell .\mypsfile.ps1" />
    ...
</targets>
如果您以前没有深入研究过这一领域,那么MsBuild的所有复杂之处都会让人难以承受,要使这项工作顺利进行,您需要掌握很多东西。它可能需要更改PowerShell脚本的操作,以使其输出具有足够的可预测性,从而使MsBuild发挥其作用

或者,您可以基于某个表达式在目标上添加一个条件,但是考虑到构建文件的解析、计算和执行方式,很难找到正确的方法

如果你把这些事情做对了,你会有巨大的性能提升

另见:


谢谢您的建议!我理解这种行为是“故意的”!但我不能使用你的解决方案,因为它也需要在VS中工作。@IngoKarstein请查看我的更新,因为它是按设计行为进行的,我们没有VS选项来直接控制它。但是vs允许我们从调试和发布中创建新的配置,因此我们可以通过定制项目文件来实现该行为。希望有帮助:)嗨,朋友,这个问题有什么更新吗?
<target name="RunMyPowerShell" 
    beforetargets="Compile" Inputs="@(Content)" 
    Outputs"@(Content->'%(Filename).translated.content')">
    ...
    <exec Command="powershell .\mypsfile.ps1" />
    ...
</targets>
<PropertyGroup>
    <CompileDependsOn>
        RunMyPowerShell;
        $(CompileDependsOn)
    </CompileDependsOn>
</PropertyGroup>