我在MSBuild中有一个构建后目标,可以复制一些构建输出。
它作为依赖项链接到AfterBuild目标(由Microsoft.CSharp.targets公开):
<Target Name="AfterBuild" DependsOnTargets="InstallUtil;CopyPostBuildFiles" />如果构建实际上没有重新构建,有什么方法可以避免文件被复制吗?
例如,当MSBuild依赖分析断言由于项目的源文件都没有更新而不需要构建项目时,它不会进行构建,但仍然会执行我的复制目标。有什么方法可以防止这种情况发生吗?
发布于 2009-12-22 03:01:00
由于您覆盖了AfterBuild目标,因此它将始终在构建发生后执行。这是重建或普通构建的情况。如果您想要在重建(而不是构建)之后执行某些操作,那么您应该扩展重建目标的依赖属性。因此,在您的示例中,要在重建发生后注入目标,您的项目文件应如下所示:
<Project ...>
   <!-- some content here -->
   <Import Project="... Microsoft.Csharp.targets" />
    <PropertyGroup>
        <RebuildDependsOn>
            $(RebuildDependsOn);
            InstallUtil;
            CopyPostBuildFiles
        </RebuildDependsOn>
    </PropertyGroup>
</Project>此方法扩展了Rebuild target用来声明它所依赖的目标的属性。我已经在文章Inside MSBuild中详细介绍了这一点,请参阅扩展构建过程一节。
此外,如果您可以指定哪些文件将“触发”更新发生,则AfterBuild目标可能会实现您正在尝试完成的操作。换句话说,您可以在目标中指定一组“输入”和一组“输出”,这两个文件都是文件。如果所有输出都是在所有输入之后创建的,那么目标将被认为是最新的,并被跳过。这个概念被称为增量构建,我已经在文章MSBuild Best Practices Part 2中介绍了它。我还在我的书Inside the Microsoft Build Engine: Using MSBuild and Team Foundation Build中详细介绍了这一点。
编辑:添加BuildDependsOn示例
如果希望目标仅在实际生成文件时执行,而不是仅在执行重新生成目标时执行。然后,您应该创建如下所示的项目:
<Project ...>
   <!-- some content here -->
   <Import Project="... Microsoft.Csharp.targets" />
    <PropertyGroup>
        <BuildDependsOn>
            $(BuildDependsOn);
            CustomAfterBuild;
        </BuildDependsOn>
    </PropertyGroup>
   <Target Name="CustomAfterBuild" Inputs="$(MSBuildAllProjects);
            @(Compile);                               
            @(_CoreCompileResourceInputs);
            $(ApplicationIcon);
            $(AssemblyOriginatorKeyFile);
            @(ReferencePath);
            @(CompiledLicenseFile);
            @(EmbeddedDocumentation); 
            $(Win32Resource);
            $(Win32Manifest);
            @(CustomAdditionalCompileInputs)"
    Outputs="@(DocFileItem);
             @(IntermediateAssembly);
             @(_DebugSymbolsIntermediatePath);                 
             $(NonExistentFile);
             @(CustomAdditionalCompileOutputs)">
   <!-- Content here -->
    </Target>
</Project>我只是将CoreCompile目标的输入和输出复制到Microsoft.CSharp.targets中(我假设您在这里使用的是C# ),并将其粘贴到这里。这意味着只要执行CoreCompile目标,就会跳过该目标。另外,因为我扩展了BuildDependsOn,所以我们知道每当构建项目时,MSBuild都会尝试并执行它。
发布于 2012-12-13 05:31:20
我用谷歌搜索了一下,找到了这个多年前的答案。我找到了一种方法,通过从核心目标中窃取想法来更容易地完成这项工作。覆盖BeforeBuild和AfterBuild,并执行以下操作:
  <Target Name="BeforeBuild">
    <PropertyGroup>
      <MyBeforeCompileTimestamp>%(IntermediateAssembly.ModifiedTime)
                 </MyBeforeCompileTimestamp>
    </PropertyGroup>
  </Target>
  <Target Name="AfterBuild">
    <CallTarget Condition="$(MyBeforeCompileTimestamp) !=   
          %(IntermediateAssembly.ModifiedTime)" Targets="MyTarget" /> 
  </Target>发布于 2009-02-06 07:43:26
如何使用输入和输出目标的属性,就像在编译目标中一样。
<PropertyGroup>
  <PostBuildDir>CopiedFilesDirectory</PostBuildDir>
</PropertyGroup>
<Target Name="AfterBuild" DependsOnTargets="InstallUtil;CopyPostBuildFiles" />
<Target Name="CopyPostBuildFiles"
        Inputs="@(PostBuildFiles)"
        Outputs="@(PostBuildFiles -> '$(PostBuildDir)%(Filename)%(Extension)'">
    <Copy SourceFiles="@(PostBuildFiles)"
          DestinationFolder="PostBuildDir"/>
</Target>你可以在CopyPostBuildFiles和InstallUtil上使用它,也可以直接在AfterBuild上使用。
有关Targets Inputs Outputs的更多信息,请参阅此页面
https://stackoverflow.com/questions/516227
复制相似问题