逐步解說:使用 MSBuild
MSBuild 是 Microsoft 和 Visual Studio 的組建平台。此逐步解說介紹 MSBuild 的建置組塊,以及顯示如何撰寫、管理和偵錯 MSBuild 專案。您將學習:
建立和管理專案檔。
如何使用建置屬性。
如何使用建置項目。
您可以從 Visual Studio 或 [命令視窗] 執行 MSBuild。在此逐步解說中,您可以使用 Visual Studio 建立 MSBuild 專案檔。您可在 Visual Studio 中編輯專案檔,並使用 [命令視窗] 來建置專案及檢查結果。
建立 MSBuild 專案
Visual Studio 專案系統是以 MSBuild 為基礎。這可讓您輕鬆使用 Visual Studio 建立新的專案檔。在本章節中,您會建立 Visual C# 專案檔。您也可以選擇建立 Visual Basic 專案檔。在此逐步解說中,這兩個專案檔之間的差異並不顯著。
若要建立專案檔
開啟 Visual Studio。
在 [檔案] 功能表上,指向 [新增],然後按一下 [專案]。
在 [新增專案] 對話方塊中,選取 Visual C# 專案類型,然後選取 [Windows Form 應用程式] 範本。在 [名稱] 方塊中,輸入 BuildApp。輸入方案的 [位置],例如 D:\。接受 [為方案建立目錄] (已選取)、[加入至原始檔控制] (未選取) 和 [方案名稱] ( BuildApp) 的預設值。
按一下 [確定] 建立專案檔。
檢查專案檔
在上一節中,您已使用 Visual Studio 建立 Visual C# 專案檔。在 [方案總管] 中,專案檔是以名為 BuildApp 的專案節點表示。您可以使用 Visual Studio 程式碼編輯器來檢查專案檔。
若要檢查專案檔
在 [方案總管] 中,按一下 BuildApp 專案節點。
在 [屬性] 瀏覽器中,請注意 [專案檔] 屬性是 BuildApp.csproj。所有專案檔都會以尾碼 "proj" 命名。如果您建立了 Visual Basic 專案,則專案檔名會是 BuildApp.vbproj。
以滑鼠右鍵按一下專案節點,然後按一下 [卸載專案]。
再次以滑鼠右鍵按一下專案節點,然後按一下 [編輯 BuildApp.csproj]。
專案檔會顯示在程式碼編輯器中。
目標和工作
專案檔是根節點為 Project 的 XML 格式檔案。
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="https://schemas.microsoft.com/developer/msbuild/2003">
您必須在專案項目中指定 xmlns 命名空間。
工作 (Task) 是工作 (Work) 的最小單位,換言之,就是組建的「原子」。工作 (Task) 是可具有輸入和輸出的獨立可執行元件。專案檔中目前並未參考或定義工作。在以下各節中,您會將工作加入至專案檔。如需詳細資訊,請參閱MSBuild 工作主題。
目標是具名的工作序列。在專案檔的結尾處目前有兩個以 HTML 註解括住的目標:BeforeBuild 和 AfterBuild。
<Target Name="BeforeBuild"> </Target> <Target Name="AfterBuild"> </Target>
如需詳細資訊,請參閱MSBuild 目標主題。
專案節點具有選擇性 DefaultTargets 屬性,可選取要建置的預設目標,在此案例中為 Build。
<Project ToolsVersion="4.0" DefaultTargets="Build" ...
Build 目標並未定義於專案檔中。但是,此目標是使用 Import 項目從 Microsoft.CSharp.targets 檔案匯入。
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
每次參考匯入的檔案時,匯入的檔案便會有效地插入到專案檔中。
MSBuild 會追蹤組建的目標,並保證每個目標只會建置一次。
加入目標和工作
在專案檔中加入目標。將工作加入至可印出訊息的目標。
若要加入目標和工作
在專案檔中加入下列各行,並緊接在 Import 陳述式之後:
<Target Name="HelloWorld"> </Target>
這會建立名為 HelloWorld 的目標。請注意,您在編輯專案檔時可以取得 IntelliSense 支援。
將文字行加入至 HelloWorld 目標,結果產生的區段看起來會像以下的樣子:
<Target Name="HelloWorld"> <Message Text="Hello"></Message> <Message Text="World"></Message> </Target>
儲存專案檔案。
Message 工作是 MSBuild 隨附的許多工作之一。如需可用工作的完整清單和用法的相關資訊,請參閱 MSBuild 工作參考。
Message 工作會將 Text 屬性的字串值視為輸入並顯示於輸出裝置上。HelloWorld 目標會執行 Message 工作兩次:首先顯示 "Hello",然後再顯示 "World"。
建置目標
從 [Visual Studio 命令提示字元] 執行 MSBuild,以建置上面定義的 HelloWorld 目標。使用 /target 或 /t 命令列參數來選取目標。
注意事項 |
---|
在以下各節中,我們會以 [命令視窗] 代表 [Visual Studio 命令提示字元]。 |
若要建置目標
按一下 [開始],然後按一下 [所有程式]。找到 [Visual Studio Tools] 資料夾並按一下其中的 [Visual Studio 命令提示字元]。
從命令視窗巡覽至含有專案檔的資料夾,在此案例中是 D:\BuildApp\BuildApp。
使用命令參數 /t:HelloWorld 執行 msbuild。這會選取並建置 HelloWorld 目標:
msbuild buildapp.csproj /t:HelloWorld
檢查 [命令視窗] 中的輸出。您應該會看到 "Hello" 和 "World" 這兩行:
Hello World
注意事項 |
---|
如果您看到 The target "HelloWorld" does not exist in the project ,可能是您忘了在程式碼編輯器中儲存專案檔。請儲存檔案,然後再試一次。 |
交替使用程式碼編輯器和命令視窗,您即可變更專案檔而且迅速看到結果。
注意事項 |
---|
如果您未使用 /t 命令參數執行 msbuild,msbuild 會建置 Project 項目的 DefaultTarget 屬性所提供的目標,在此案例中是 "Build"。這會建置 Windows Form 應用程式 BuildApp.exe。 |
建置屬性
建置屬性是可引導建置的名稱/值組。專案檔的頂部已經定義數個建置屬性:
<PropertyGroup>
...
<ProductVersion>10.0.11107</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{30E3C9D5-FD86-4691-A331-80EA5BA7E571}</ProjectGuid>
<OutputType>WinExe</OutputType>
...
</PropertyGroup>
所有屬性都是 PropertyGroup 項目的子項目。屬性的名稱是子項目的名稱,而屬性的值是子項目的文字項目。例如:
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
會定義名為 TargetFrameworkVersion 的屬性,並提供字串值 "v4.0" 給它。
建置屬性可以隨時重新定義。如果
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
之後出現在專案檔中,或出現在之後匯入專案檔的檔案中,則 TargetFrameworkVersion 會採用新值 "v3.5"。
檢查屬性值
若要取得屬性的值,請使用下列語法,其中 PropertyName 是屬性的名稱:
$(PropertyName)
使用此語法來檢查專案檔中的部分屬性。
若要檢查屬性值
在程式碼編輯器中,以下列程式碼取代 HelloWorld 目標:
<Target Name="HelloWorld"> <Message Text="Configuration is $(Configuration)" /> <Message Text="MSBuildToolsPath is $(MSBuildToolsPath)" /> </Target>
儲存專案檔案。
從 [命令視窗] 輸入並執行此行:
msbuild buildapp.csproj /t:HelloWorld
檢查輸出結果,您應該會看到下列兩行 (您的 .NET Framework 版本可能不同):
Configuration is Debug MSBuildToolsPath is C:\Windows\Microsoft.NET\Framework\v4.0.20317
注意事項 |
---|
如果您沒有看到這兩行,可能是您忘了在程式碼編輯器中儲存專案檔。請儲存檔案,然後再試一次。 |
條件式屬性
許多屬性 (如 Configuration) 會視條件而定義,也就是說,Condition 屬性 (Attribute) 會出現在屬性 (Property) 項目中。只有當條件評估為 "true" 時,才能定義或重新定義條件式屬性。請注意,未定義的屬性的預設值為空字串。例如:
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
表示「如果尚未定義 Configuration 屬性,則加以定義,並為其提供 'Debug' 值」。
幾乎所有 MSBuild 項目都可以有 Condition 屬性。如需使用 Condition 屬性的詳細討論,請參閱 MSBuild 條件。
保留的屬性
MSBuild 保留一些屬性名稱來儲存專案檔和 MSBuild 二進位檔案的相關資訊。MSBuildToolsPath 是保留屬性的範例 (MSBuild 3.5 的新增功能)。保留的屬性和其他任何屬性一樣,都使用 $ 標記法來參考。如需詳細資訊,請參閱HOW TO:參考專案檔的名稱或位置與MSBuild 保留屬性。
環境變數
在專案檔中參考環境變數的方式,就跟建置屬性的方式一樣。例如,若要在專案檔中使用 PATH 環境變數,請使用 $(Path)。如果專案含有與環境變數同名的屬性定義,則專案的屬性會覆寫環境變數的值。如需詳細資訊,請參閱HOW TO:在組建中使用環境變數。
從命令列設定屬性
您可以在命令列上使用 /property 或 /p 命令列參數定義屬性。從命令列接收的屬性值會覆寫在專案檔和環境變數中設定的屬性值。
若要從命令列設定屬性值
從 [命令視窗] 輸入並執行此行:
msbuild buildapp.csproj /t:HelloWorld /p:Configuration=Release
檢查輸出結果,您應該會看見此行:
Configuration is Release.
MSBuild 會建立 Configuration 屬性並提供給它 "Release" 值。
特殊字元
某些字元在 MSBuild 專案檔中有特殊意義,例如分號 (;) 和星號 (*) 這類字元。若要在專案檔中使用這些特殊字元做為常值,則必須使用 %xx 語法指定這些字元,其中 xx 代表字元的 ASCII 十六進位值。
變更 Message 工作,以特殊字元顯示 Configuration 屬性的值,讓它更容易判讀。
若要在 Message 工作中使用特殊字元
在程式碼編輯器中,以此行取代兩個 Message 工作:
<Message Text="%24(Configuration) is %22$(Configuration)%22" />
儲存專案檔案。
從 [命令視窗] 輸入並執行此行:
msbuild buildapp.csproj /t:HelloWorld
檢查輸出結果,您應該會看見此行:
$(Configuration) is "Debug"
如需詳細資訊,請參閱MSBuild 特殊字元。
建置項目
項目是做為建置系統之輸入的一段資訊 (通常是檔案名稱)。例如,代表原始程式檔的項目集合可能會傳遞至名為 Compile 的工作,以便編譯至組件中。
所有項目 (Item) 都是 ItemGroup 項目 (Element) 的子項目 (Child Element)。項目 (Item) 名稱是子項目 (Child Element) 的名稱,而項目 (Item) 值是子項目 (Child Element) 的 Include 屬性值。同名的項目 (Item) 值會收集到該名稱的項目類型中。例如:
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
定義包含兩個項目的項目群組。Compile 項目類型有兩個值:"Program.cs" 和 "Properties\AssemblyInfo.cs"。
下列程式碼會在一個 Include 屬性中宣告兩個檔案 (以分號分隔) 來建立相同的項目類型。
<ItemGroup>
<Compile Include="Program.cs;Properties\AssemblyInfo.cs" />
</ItemGroup>
如需詳細資訊,請參閱MSBuild 項目。
注意事項 |
---|
檔案路徑是含有 MSBuild 專案檔之資料夾的相對路徑。 |
檢查項目類型值
若要取得項目類型的值,請使用下列語法,其中 ItemType 是項目類型的名稱:
@(ItemType)
使用此語法來檢查專案檔中的 Compile 項目類型。
若要檢查項目類型值
在程式碼編輯器中,以下列程式碼取代 HelloWorld 目標工作:
<Target Name="HelloWorld"> <Message Text="Compile item type contains @(Compile)" /> </Target>
儲存專案檔案。
從 [命令視窗] 輸入並執行此行:
msbuild buildapp.csproj /t:HelloWorld
檢查輸出結果,您應該會看見以下很長的一行:
Compile item type contains Form1.cs;Form1.Designer.cs;Program.cs;Properties\AssemblyInfo.cs;Properties\Resources.Designer.cs;Properties\Settings.Designer.cs
項目類型的值預設會以分號分隔。
若要變更項目類型的分隔符號,請使用下列語法,其中 ItemType 是項目類型,而 Separator 是一個或多個分隔字元的字串:
@(ItemType, Separator)
變更 Message 工作,以使用歸位字元和換行字元 (%0A%0D) 顯示 Compile 項目 (每行一個)。
若要每行顯示一個項目類型值
從程式碼編輯器,以這行取代訊息工作:
<Message Text="Compile item type contains @(Compile, '%0A%0D')" />
儲存專案檔案。
從 [命令視窗] 輸入並執行此行:
msbuild buildapp.csproj /t:HelloWorld
檢查輸出結果,您應該會看見下列各行:
Compile item type contains Form1.cs Form1.Designer.cs Program.cs Properties\AssemblyInfo.cs Properties\Resources.Designer.cs Properties\Settings.Designer.cs
Include、Exclude 和萬用字元
您可以使用萬用字元 "*"、"**" 和 "?" 搭配 Include 屬性,將項目加入至項目類型。例如:
<Photos Include="images\*.jpeg" />
會將 images 資料夾中副檔名為 ".jpeg" 的所有檔案加入到 Photos 項目類型,而
<Photos Include="images\**.jpeg" />
會將 images 資料夾與其所有子資料夾中副檔名為 ".jpeg" 的所有檔案加入到 Photos 項目類型。如需更多範例,請參閱 HOW TO:選取要建置的檔案。
請注意,項目會在宣告時加入至項目類型。例如:
<Photos Include="images\*.jpeg" />
<Photos Include="images\*.gif" />
會在 image 資料夾中建立名為 Photo 的項目類型,而此項目類型會包含副檔名為 ".jpeg" 或 ".gif" 的所有檔案。這等於下面這一行:
<Photos Include="images\*.jpeg;images\*.gif" />
您可以從具有 Exclude 屬性的項目類型中排除項目。例如:
<Compile Include="*.cs" Exclude="*Designer*">
會將副檔名為 ".cs" 的所有檔案加入到 Compile 項目類型,但是名稱包含 "Designer" 字串的檔案除外。如需更多範例,請參閱 HOW TO:從組建中排除檔案。
只有在項目的項目 (Item Element) 同時包含 Exclude 屬性和 Include 屬性時,前者才會影響後者所加入的項目 (Item)。例如:
<Compile Include="*.cs" />
<Compile Include="*.res" Exclude="Form1.cs">
不會排除前述項目的項目 (Item Element) 中所加入的檔案 Form1.cs。
若要包含和排除項目
從程式碼編輯器,以這行取代訊息工作:
<Message Text="Compile item type contains @(XFiles)" />
將此項目 (Item) 群組加入到 Import 項目 (Element) 之後:
<ItemGroup> <XFiles Include="*.cs;properties/*.resx" Exclude="*Designer*" /> </ItemGroup>
儲存專案檔案。
從 [命令視窗] 輸入並執行此行:
msbuild buildapp.csproj /t:HelloWorld
檢查輸出結果,您應該會看見此行:
Compile item type contains Form1.cs;Program.cs;Properties/Resources.resx
項目中繼資料
項目 (Item) 中除了有從 Include 和 Exclude 屬性收集的資訊之外,還會包含中繼資料。這項中繼資料可供需要有關項目 (Item) 之詳細資訊 (不僅限於項目值) 的工作使用。
在專案檔中宣告項目 (Item) 中繼資料的方式,是使用中繼資料的名稱建立項目 (Element) 做為項目 (Item) 的子項目 (Element)。項目 (Item) 可以不包含或包含更多中繼資料值。例如,下列 CSFile 項目的 Culture 中繼資料值為 "Fr":
<ItemGroup>
<CSFile Include="main.cs">
<Culture>Fr</Culture>
</CSFile>
</ItemGroup>
若要取得項目類型的中繼資料值,請使用下列語法,其中 ItemType 是項目類型的名稱,而 MetaDataName 是中繼資料的名稱:
%(ItemType.MetaDataName)
若要檢查項目中繼資料
從程式碼編輯器,以這行取代訊息工作:
<Message Text="Compile.DependentUpon: %(Compile.DependentUpon)" />
儲存專案檔案。
從 [命令視窗] 輸入並執行此行:
msbuild buildapp.csproj /t:HelloWorld
檢查輸出結果,您應該會看見下列各行:
Compile.DependentUpon: Compile.DependentUpon: Form1.cs Compile.DependentUpon: Resources.resx Compile.DependentUpon: Settings.settings
請注意 "Compile.DependentUpon" 片語如何出現數次。在目標內使用中繼資料和此語法會造成「批次處理」。批次處理表示目標內的工作會針對每個唯一的中繼資料值執行一次。這是通用 "for loop" 程式設計建構的 MSBuild 指令碼對等項目。如需詳細資訊,請參閱MSBuild 批次處理。
已知的中繼資料
在項目 (Item) 清單中加入項目時,即指派了某些已知的中繼資料給該項目。例如,%(Filename) 會傳回任何項目的檔案名稱。如需已知中繼資料的完整清單,請參閱 MSBuild 已知的項目中繼資料。
若要檢查已知的中繼資料
從程式碼編輯器,以這行取代訊息工作:
<Message Text="Compile Filename: %(Compile.Filename)" />
儲存專案檔案。
從 [命令視窗] 輸入並執行此行:
msbuild buildapp.csproj /t:HelloWorld
檢查輸出結果,您應該會看見下列各行:
Compile Filename: Form1 Compile Filename: Form1.Designer Compile Filename: Program Compile Filename: AssemblyInfo Compile Filename: Resources.Designer Compile Filename: Settings.Designer
比較上面兩個範例,您即可發現當 Compile 項目類型中並非每一個項目都具有 DependentUpon 中繼資料時,所有項目都具有已知的 Filename 中繼資料。
中繼資料轉換
項目清單可以轉換為新的項目清單。若要轉換項目清單,請使用下列語法,其中 ItemType 是項目類型的名稱,而 MetadataName 是中繼資料的名稱:
@(ItemType -> '%(MetadataName)')
例如,使用類似 @(SourceFiles -> '%(Filename).obj') 的運算式,可以將原始程式檔的項目清單轉換為物件檔的集合。如需詳細資訊,請參閱MSBuild 轉換。
若要使用中繼資料轉換項目
從程式碼編輯器,以這行取代訊息工作:
<Message Text="Backup files: @(Compile->'%(filename).bak')" />
儲存專案檔案。
從 [命令視窗] 輸入並執行此行:
msbuild buildapp.csproj /t:HelloWorld
檢查輸出結果,您應該會看見此行:
Backup files: Form1.bak;Form1.Designer.bak;Program.bak;AssemblyInfo.bak;Resources.Designer.bak;Settings.Designer.bak
請注意,此語法表示的中繼資料不會造成批次處理。
下一步
若要了解如何逐步建立簡單專案檔,請嘗試逐步解說:從頭開始建立 MSBuild 專案檔案。