延伸 Visual Studio 建置流程
Visual Studio 建置處理序是由匯入至專案檔的一系列 MSBuild .targets 檔案所定義。 可以擴充其中一個已匯入的檔案 (Microsoft.Common.targets),以讓您在建置處理序的數個點執行自訂工作。 本文說明您可以使用兩種方法來擴充 Visual Studio 建置處理序:
覆寫通用目標中定義的特定預先定義目標 (Microsoft.Common.targets 或其匯入的檔案)。
覆寫通用目標中定義的 "DependsOn" 屬性。
覆寫預先定義的目標
通用目標包含一組預先定義的空目標,可在建置處理序的部分主要目標之前和之後呼叫。 例如,MSBuild 在主要 CoreBuild
目標之前呼叫 BeforeBuild
目標,而在 CoreBuild
目標之後呼叫 AfterBuild
目標。 根據預設,通用目標中的空目標不會執行任何作業,但是您可以在匯入通用目標的專案檔中定義您想要的目標,以覆寫其預設行為。 覆寫預先定義的目標,即可使用 MSBuild 工作,更充分地控制建置處理序。
注意
SDK 樣式專案在專案檔的最後一行之後,隱含匯入目標。 這表示除非如如何:使用 MSBuild 專案 SDK 所述手動指定匯入,否則您無法覆寫預設目標。
覆寫預先定義的目標
識別通用目標中您要覆寫的預先定義目標。 如需您可安全覆寫之目標的完整清單,請參閱下表。
在專案檔結尾,於
</Project>
標記的正前方定義目標。 例如:<Project> ... <Target Name="BeforeBuild"> <!-- Insert tasks to run before build here --> </Target> <Target Name="AfterBuild"> <!-- Insert tasks to run after build here --> </Target> </Project>
建置專案檔。
下表顯示通用目標中您可安全覆寫的所有目標。
目標名稱 | 描述 |
---|---|
BeforeCompile , AfterCompile |
在核心編譯完成之前或之後,會執行插入至其中一個目標的工作。 大部分的自訂是在這兩個目標的其中一個中完成。 |
BeforeBuild , AfterBuild |
在組建的任何其他項目之前或之後,將會執行其中一個目標中插入的工作。 注意︰BeforeBuild 和 AfterBuild 目標定義於大部分專案檔結尾的註解中,可讓您輕鬆地將建置前和建置後事件新增至專案檔。 |
BeforeRebuild , AfterRebuild |
在叫用核心重建功能之前或之後,執行插入至其中一個目標的工作。 Microsoft.Common.targets 中的目標執行順序是:BeforeRebuild 、Clean 、Build 和 AfterRebuild 。 |
BeforeClean , AfterClean |
在叫用核心清除功能之前或之後,執行插入至其中一個目標的工作。 |
BeforePublish , AfterPublish |
在叫用核心發行功能之前或之後,執行插入至其中一個目標的工作。 |
BeforeResolveReferences , AfterResolveReferences |
在解析組件參考之前或之後,會執行插入至其中一個目標的工作。 |
BeforeResGen , AfterResGen |
在產生資源之前或之後,會執行插入至其中一個目標的工作。 |
範例:AfterTargets 和 BeforeTargets
下列範例示範如何使用 AfterTargets
屬性來新增自訂目標,以使用輸出檔案執行某些動作。 在此情況下,它會將輸出檔案複製到新的資料夾 CustomOutput。 此範例也會示範如何使用 BeforeTargets
屬性並指定自訂清除作業在 CoreClean
目標之前執行,清除具有 CustomClean
目標的自訂建置作業所建立的檔案。
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<_OutputCopyLocation>$(OutputPath)..\..\CustomOutput\</_OutputCopyLocation>
</PropertyGroup>
<Target Name="CustomAfterBuild" AfterTargets="Build">
<ItemGroup>
<_FilesToCopy Include="$(OutputPath)**\*"/>
</ItemGroup>
<Message Text="_FilesToCopy: @(_FilesToCopy)" Importance="high"/>
<Message Text="DestFiles:
@(_FilesToCopy->'$(_OutputCopyLocation)%(RecursiveDir)%(Filename)%(Extension)')"/>
<Copy SourceFiles="@(_FilesToCopy)"
DestinationFiles=
"@(_FilesToCopy->'$(_OutputCopyLocation)%(RecursiveDir)%(Filename)%(Extension)')"/>
</Target>
<Target Name="CustomClean" BeforeTargets="CoreClean">
<Message Text="Inside Custom Clean" Importance="high"/>
<ItemGroup>
<_CustomFilesToDelete Include="$(_OutputCopyLocation)**\*"/>
</ItemGroup>
<Delete Files='@(_CustomFilesToDelete)'/>
</Target>
</Project>
警告
務必使用與上一節表格中所列的預先定義目標不同的名稱 (例如,我們在此將自訂建置目標命名為 CustomAfterBuild
,而不是 AfterBuild
),因為這些預先定義的目標會由也定義目標的 SDK 匯入所覆寫。 您看不到覆寫這些目標的目標檔案匯入,但是當您使用參考 SDK 的 Sdk
屬性方法時,它會隱含地新增至專案檔的結尾。
覆寫 DependsOn 屬性
覆寫預先定義的目標是擴充建置處理序的簡單方法,但因為 MSBuild 會循序評估目標的定義,所以沒有任何方法可防止另一個匯入您專案的專案覆寫您已覆寫的目標。 因此,例如,在匯入所有其他專案之後,專案檔中所定義的最後一個 AfterBuild
目標就是建置期間所使用的目標。
您可以覆寫整個通用目標中 DependsOnTargets
屬性中所使用的 DependsOn 屬性,來防止意外覆寫目標。 例如,Build
目標包含 "$(BuildDependsOn)"
的 DependsOnTargets
屬性值。 考量:
<Target Name="Build" DependsOnTargets="$(BuildDependsOn)"/>
這部分的 XML 指出必須先執行 BuildDependsOn
屬性中所指定的所有目標,才能執行 Build
目標。 BuildDependsOn
屬性定義為:
<PropertyGroup>
<BuildDependsOn>
BeforeBuild;
CoreBuild;
AfterBuild
</BuildDependsOn>
</PropertyGroup>
您可以在專案檔結尾宣告名為 BuildDependsOn
的另一個屬性,來覆寫此屬性值。 在新屬性中包含先前的 BuildDependsOn
屬性,即可將新目標新增至目標清單開頭和結尾。 例如:
<PropertyGroup>
<BuildDependsOn>
MyCustomTarget1;
$(BuildDependsOn);
MyCustomTarget2
</BuildDependsOn>
</PropertyGroup>
<Target Name="MyCustomTarget1">
<Message Text="Running MyCustomTarget1..."/>
</Target>
<Target Name="MyCustomTarget2">
<Message Text="Running MyCustomTarget2..."/>
</Target>
匯入您專案檔的專案可以覆寫這些屬性,而不覆寫您進行的自訂。
覆寫 DependsOn 屬性
識別通用目標中您要覆寫的預先定義 DependsOn 屬性。 如需經常覆寫的 DependsOn 屬性清單,請參閱下表。
在專案檔結尾定義另一個屬性執行個體。 在新屬性中,包含原始屬性 (例如
$(BuildDependsOn)
)。在屬性定義之前或之後,定義您的自訂目標。
建置專案檔。
經常覆寫的 DependsOn 屬性
屬性名稱 | 描述 |
---|---|
BuildDependsOn |
如果您想要在整個建置處理序之前或之後插入自訂目標,這是要覆寫的屬性。 |
CleanDependsOn |
如果您想要清除自訂建置處理序的輸出,這是要覆寫的屬性。 |
CompileDependsOn |
如果您想要在編譯步驟之前或之後插入自訂處理序,這是要覆寫的屬性。 |
範例:BuildDependsOn 和 CleanDependsOn
下列範例與 BeforeTargets
和 AfterTargets
範例類似,但示範如何達到類似的功能。 其會使用 BuildDependsOn
擴充組建,以新增自己的工作 CustomAfterBuild
,該工作會在建置之後複製輸出檔案,也會使用 CleanDependsOn
新增對應的 CustomClean
工作。
在此範例中,這是 SDK 樣式專案。 如本文稍早的 SDK 樣式專案相關附註所述,您必須使用手動匯入方法,而不是 Visual Studio 在產生專案檔時所使用的 Sdk
屬性。
<Project>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk"/>
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk"/>
<PropertyGroup>
<BuildDependsOn>
$(BuildDependsOn);CustomAfterBuild
</BuildDependsOn>
<CleanDependsOn>
$(CleanDependsOn);CustomClean
</CleanDependsOn>
<_OutputCopyLocation>$(OutputPath)..\..\CustomOutput\</_OutputCopyLocation>
</PropertyGroup>
<Target Name="CustomAfterBuild">
<ItemGroup>
<_FilesToCopy Include="$(OutputPath)**\*"/>
</ItemGroup>
<Message Importance="high" Text="_FilesToCopy: @(_FilesToCopy)"/>
<Message Text="DestFiles:
@(_FilesToCopy->'$(_OutputCopyLocation)%(RecursiveDir)%(Filename)%(Extension)')"/>
<Copy SourceFiles="@(_FilesToCopy)"
DestinationFiles="@(_FilesToCopy->'$(_OutputCopyLocation)%(RecursiveDir)%(Filename)%(Extension)')"/>
</Target>
<Target Name="CustomClean">
<Message Importance="high" Text="Inside Custom Clean"/>
<ItemGroup>
<_CustomFilesToDelete Include="$(_OutputCopyLocation)**\*"/>
</ItemGroup>
<Delete Files="@(_CustomFilesToDelete)"/>
</Target>
</Project>
元素的順序很重要。 匯入標準 SDK 目標檔案之後,BuildDependsOn
和 CleanDependsOn
元素必須出現。
相關內容
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應