2009-02-05 52 views
8

我在MSBuild中有一個後期構建目標來複制一些構建輸出。當csproj尚未構建時抑制AfterBuild目標

這一點與在作爲一個依賴於AfterBuild目標(由Microsoft.CSharp.targets暴露):

<Target Name="AfterBuild" DependsOnTargets="InstallUtil;CopyPostBuildFiles" /> 

有什麼辦法來避開構建實際上並沒有重新建立被複制的文件?

例如,當MSBuild依賴關係分析斷言項目不需要構建,因爲它的任何源文件都沒有更新,它不會生成,但仍然執行我的複製目標。有什麼辦法可以防止這種情況發生?

回答

7

此頁面瞭解更多信息。這是重建或正常構建的情況。如果你想在重建(而不是構建)之後執行一些操作,那麼你應該擴展重建目標的依賴屬性。因此,在你的情況下,重建時,您的項目文件後,應該看起來像注入了目標:

<Project ...> 
    <!-- some content here --> 

    <Import Project="... Microsoft.Csharp.targets" /> 


    <PropertyGroup> 
     <RebuildDependsOn> 
      $(RebuildDependsOn); 
      InstallUtil; 
      CopyPostBuildFiles 
     </RebuildDependsOn> 
    </PropertyGroup> 
</Project> 

此方法擴展其重建目標的屬性使用聲明一下針對這取決於。我已在文章Inside MSBuild中詳細介紹了這一點,請參見部分擴展構建過程

如果您可以指定什麼文件將「觸發」更新發生,那麼您正在嘗試完成的任務可能由AfterBuild目標實現。換句話說,您可以將一組「輸入」指定到目標中,並將一組「輸出」指定爲這兩個文件。如果所有輸出都是在所有輸入之後創建的,那麼目標會被視爲最新並跳過。這個概念被稱爲Incremental Building,我在文章MSBuild Best Practices Part 2中已經介紹過它。另外我在我的書Inside the Microsoft Build Engine: Using MSBuild and Team Foundation Build中詳細說明了這一點。

編輯:添加BuildDependsOn例如

如果你想在目標只有當文件實際上是建立執行和不執行重建目標只是當。那麼你應該創建你的項目是這樣的:從Microsoft.CSharp.targets內的CoreCompile目標(我假設你在這裏使用C#

<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目標的目標將被跳過。此外,由於我擴展了BuildDependsOn,我們知道MSBuild將在項目構建時嘗試執行它。

+0

似乎更新「RebuildDependsOn」目標只會導致額外的步驟觸發,如果您明確調用「重建」目標。如果你調用「Build」,他們不會觸發。 – 2009-12-23 15:09:07

0

構建目標的定義是:

<Target Name = "Build" DependsOnTargets="BeforeBuild;CoreBuild;AfterBuild"/> 

我覺得不執行CoreBuild如果你的文件並沒有改變,所以你可以嘗試使用AfterCompile代替AfterBuild。

<Target Name="AfterCompile" DependsOnTargets="InstallUtil;CopyPostBuildFiles" /> 
+0

好主意,但它似乎沒有太大的區別。即使在將AfterBuild更改爲AfterCompile之後,該副本仍然每次都執行。 – 2009-02-05 17:29:18

+0

對不起,我的測試用例一定是蹩腳的^^。 – 2009-02-05 18:29:26

0

這是怎麼回事。

  • BuildBreak。如果發生編譯錯誤 ,則設置爲true,否則爲 。可以在構建中斷 目標中使用,以確定它們是 在編譯錯誤後執行還是 正常執行。

http://blogs.msdn.com/aaronhallberg/archive/2008/02/12/team-build-2008-property-reference.aspx

我還沒有嘗試過,但它聽起來非常有前途的。

+0

嗨馬克,這個屬性是一個很好的發現,但是我追求的東西會讓我在「nop構建」之後壓制複製任務,因爲所有的輸出都被認爲是最新的,所以沒有任何東西會被建立。 – 2009-02-06 06:05:57

6

怎麼樣使用輸入和輸出目標的屬性,如它在編譯目標中完成。

<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> 

你可以使用上CopyPostBuildFilesInstallUtil或直接在AfterBuild

既然要覆蓋AfterBuild目標構建後的情況會一直執行查看Targets Inputs Outputs

8

我只是用Google搜索,發現這個本歲答案。我找到了一種方法,通過從核心目標中竊取一個想法來簡化操作。同時覆蓋BeforeBuild和AfterBuild和做類似:

<Target Name="BeforeBuild"> 
    <PropertyGroup> 
     <MyBeforeCompileTimestamp>%(IntermediateAssembly.ModifiedTime) 
       </MyBeforeCompileTimestamp> 
    </PropertyGroup> 
    </Target> 

    <Target Name="AfterBuild"> 
    <CallTarget Condition="$(MyBeforeCompileTimestamp) != 
      %(IntermediateAssembly.ModifiedTime)" Targets="MyTarget" /> 
    </Target> 
-1

我不知道很多關於MSBuild的,但在C#中使用Visual Studio中的MSBuild項目的情況下,有一個頭腦簡單的替代方案:使用構建後生成事件而不是AfterBuild目標。

您可以通過Visual Studio項目屬性對話框中設置了一個生成後生成事件,第三個選項卡「生成事件」上。對於某些情況,在此對話框中輸入一些命令可能是一種想法,然後在確定它如何工作後,直接編輯.csproj文件。

記住選擇「運行這個生成後事件:當構建更新項目輸出」對話框上 - 這是敲門磚由OP請求的功能。

就像我說的,我不知道很多關於MSBuild的,它可能是生成後生成事件並不適用於某些事情的AfterBuild目標可以做。但我用它來複制文件和運行BAT腳本,並且它工作正常。

編輯:

我將添加有關如何我通常使用後建在我的C#項目事件的幾個注意事項。

爲了分離不同的功能區域,我通常創建一個名爲PostBuildEvent.bat一個BAT腳本,並將其放置在同一文件夾中的.csproj文件。然後我生成後事件只包含兩行:

cd $(ProjectDir) 
PostBuildEvent.bat 

然後我把我想在PostBuildEvent.bat文件中的命令。下面是一個例子:請記住,要從BAT腳本中調用BAT腳本,請明確指定「call」。還要注意使用「暫停」 - 這可以通過雙擊BAT文件來測試腳本,然後您可以在cmd窗口中看到任何錯誤消息。當腳本通過MSBuild運行時,「暫停」將被忽略。

0

這將調用AfterBuild目標當且僅當該項目目標文件已經重建:

<Target Name="AfterBuild" 
    DependsOnTargets="InstallUtil;CopyPostBuildFiles" 
    Inputs="$(TargetPath)" 
    Outputs="$(DeployPath)\$(TargetFileName)" /> 

這假定您已經定義了標識爲複製目標輸出文件的文件夾的屬性$(DeployPath)

相關問題