共用方式為


教學課程:使用 MSBuild

MSBuild 是適用於 Microsoft 和 Visual Studio 的建置平臺。 本教學課程將介紹 MSBuild 的建置組塊,並示範如何撰寫、操作和偵錯 MSBuild 專案。 您瞭解:

  • 建立和操作項目檔。

  • 如何使用組建屬性。

  • 如何使用建置項目。

您可以從 Visual Studio 或從 指令視窗執行 MSBuild。 在本教學課程中,您會使用 Visual Studio 建立 MSBuild 項目檔。 您可以在 Visual Studio 中編輯項目檔,並使用 命令視窗 來建置專案並檢查結果。

安裝 MSBuild

如果您有 Visual Studio,則表示您已經安裝 MSBuild。 使用 Visual Studio 2019 和更新版本時,它會安裝在 Visual Studio 安裝資料夾下。 針對 Windows 10 上的一般預設安裝,MSBuild.exe 位於 MSBuild\Current\Bin中的安裝資料夾底下。

在安裝程式中,請確保已選取您所用工作負載的 MSBuild 工具,然後選擇 安裝

安裝 MSBuild

若要在沒有 Visual Studio 的系統上安裝 MSBuild,請移至 Build Tools for Visual Studio 2019,或安裝 .NET SDK

如果您有 Visual Studio,則表示您已經安裝 MSBuild。 使用 Visual Studio 2022 時,它會安裝在 Visual Studio 安裝資料夾下。 針對 Windows 10 上的一般預設安裝,MSBuild.exe 位於 MSBuild\Current\Bin中的安裝資料夾底下。

在 Visual Studio 安裝程式中,瀏覽至 [個別元件],然後找出 MSBuild 複選框。 當您選擇要安裝的任何其他工作負載時,系統會自動選取它。

若要在沒有 Visual Studio 的系統上安裝 MSBuild,請移至 下載頁面上的 Build Tools for Visual Studio 2022。 取得 MSBuild 的另一種方式是安裝 .NET SDK

建立 MSBuild 專案

Visual Studio 項目系統是以 MSBuild 為基礎。 使用 Visual Studio 建立新的項目檔很容易。 在本節中,您會建立 C# 項目檔。 您可以選擇改為建立 Visual Basic 項目檔。 在本教學課程的內容中,兩個專案檔之間的差異很小。

建立項目檔

  1. 開啟 Visual Studio 並建立專案:

    在搜尋方塊中,輸入 winforms,然後選擇 [建立新的 Windows Forms 應用程式 (.NET Framework)。 在出現的對話框中,選擇 建立

    在 [項目名稱] 方塊中,輸入 BuildApp。 輸入解決方案 位置,例如,D:\

  2. 按一下 [確定][建立] 來建立項目檔。

檢查項目檔

在上一節中,您使用 Visual Studio 建立 C# 項目檔。 項目檔會以名為 BuildApp 的項目節點 [方案總管] 來表示。 您可以使用 Visual Studio 程式代碼編輯器來檢查項目檔。

查看專案文件

  1. [方案總管]中,按一下 BuildApp項目節點。

  2. Properties 檢視工具中,請注意 Project File 的屬性是 BuildApp.csproj。 所有專案檔案都以 proj作為後綴命名。 如果您已建立 Visual Basic 專案,專案檔名稱會 BuildApp.vbproj

  3. 再次以滑鼠右鍵按下專案節點,然後按一下 [編輯 BuildApp.csproj]。

    項目檔會出現在程式代碼編輯器中。

注意

對於某些項目類型,例如C++,您必須卸除項目檔(以滑鼠右鍵按兩下項目檔,然後選擇 [卸除專案],才能開啟和編輯項目檔。

目標和工作

項目檔是 XML 格式的檔案,具有根節點 Project

大部分的 .NET 專案都有 Sdk 屬性。 這些項目稱為 SDK 樣式專案。 參考 SDK 表示 MSBuild 會匯入一組檔案,以提供該 SDK 的建置基礎結構。 如果您未參考任何 SDK,您仍然可以使用 MSBuild,但不會自動擁有所有 SDK 特定的屬性和目標可供使用。

<Project Sdk="Microsoft.NET.Sdk">

適用於特殊用途的 .NET SDK 有許多變化;描述於 .NET 專案 SDK

建置應用程式的工作是使用 TargetTask 元素來完成。

  • 任務是最小的工作單位,換句話說,是構建的「原子」。 工作是獨立的可執行元件,可以有輸入和輸出。 項目檔中目前沒有參考或定義的工作。 您會在下列各節中將工作新增至項目檔。 如需詳細資訊,請參閱 工作

  • 目標為具名的任務序列。 它可能是一系列具名的工作,但關鍵是,它代表要建置或完成的工作,因此應該以目標導向的方式加以定義。 如需詳細資訊,請參閱 目標

默認目標未定義於項目檔中。 而是在匯入的專案中指定。 Import 專案會指定匯入的專案。 例如,在 C# 專案中,預設目標會從 Microsoft.CSharp.targets 檔案匯入。

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

匯入的檔案會在參考處有效地插入到項目檔中。

在 SDK 樣式專案中,您看不到此匯入項目,因為 SDK 屬性會隱含匯入此檔案。

MSBuild 會追蹤組建的目標,並保證每個目標建置不超過一次。

新增目標和工作

將目標新增至項目檔。 將列印訊息的指令新增至目標。

新增目標和工作

  1. 將這幾行新增至項目檔,就在 Import 語句或開啟的 Project 元素之後。

    <Target Name="HelloWorld">
    </Target>
    

    此程式代碼會建立名為 HelloWorld 的目標。 編輯專案檔案時,請注意,您會有 IntelliSense 的支援。

  2. 將行新增至 HelloWorld 目標,讓產生的區段看起來像這樣:

    <Target Name="HelloWorld">
      <Message Text="Hello"></Message>
      <Message Text="World"></Message>
    </Target>
    
  3. 儲存項目檔。

Message 任務是 MSBuild 附帶的多個任務之一。 如需可用工作和使用方式資訊的完整清單,請參閱 工作參考

Message 工作會採用 Text 屬性的字串值做為輸入,並在輸出裝置上顯示它(如果適用的話,請將它寫入一或多個記錄檔)。 HelloWorld 目標會執行訊息工作兩次:先顯示「Hello」,然後再顯示「World」。

建置目標

如果您嘗試從Visual Studio建置此專案,則不會建置您定義的目標。 這是因為 Visual Studio 會選擇預設目標,這仍然是匯入 .targets 檔案中的目標。

從 Visual Studio 開發人員命令提示字元 執行 MSBuild,以建置先前定義的 HelloWorld 目標。 使用 -target-t 命令行參數來選取目標。

注意

我們將在下列各節中將 開發人員命令提示字元 稱為 命令視窗

若要建置目標:

  1. 開啟 指令視窗

    在工作列的搜尋方塊中,開始輸入工具的名稱,例如 devdeveloper command prompt。 隨即會出現符合搜尋模式的已安裝應用程式清單。

    如果您需要手動尋找它,檔案會在 [{Visual Studio 安裝資料夾}\Common7\Tools 資料夾中 LaunchDevCmd.bat

  2. 從命令視窗中,流覽至包含項目檔的資料夾,在此案例中,D:\BuildApp\BuildApp

  3. 使用命令開關 -t:HelloWorld執行 msbuild。 此命令會選取並建置 HelloWorld 目標:

    msbuild buildapp.csproj -t:HelloWorld
    
  4. 檢查 [命令] 視窗中的輸出,。 您應該會看到兩行 「Hello」 和 「World」:

    Hello
    World
    

注意

如果您看到 The target "HelloWorld" does not exist in the project,您可能會忘記將專案檔儲存在程式碼編輯器中。 儲存盤案,然後再試一次。

藉由在程式代碼編輯器與命令視窗之間交替,您可以變更項目檔並快速查看結果。

建置屬性

組建屬性是引導組建的名稱/值組。 專案檔頂端已定義數個建置屬性:

<PropertyGroup>
...
  <ProductVersion>10.0.11107</ProductVersion>
  <SchemaVersion>2.0</SchemaVersion>
  <ProjectGuid>{30E3C9D5-FD86-4691-A331-80EA5BA7E571}</ProjectGuid>
  <OutputType>WinExe</OutputType>
...
</PropertyGroup>

所有屬性都是 PropertyGroup 元素的子元素。 屬性的名稱是子元素的名稱,而屬性的值則是子元素的文本元素。 例如

<TargetFrameworkVersion>net8.0</TargetFrameworkVersion>

定義名為 TargetFrameworkVersion的屬性,併為其提供字串值 “net8.0”

您可以隨時重新定義組建屬性。 如果

<TargetFrameworkVersion>net6.0</TargetFrameworkVersion>

後來會出現在專案檔中,或在專案檔中稍後匯入的檔案中,然後 TargetFrameworkVersion 會取得新值 "net6.0"

檢查屬性值

若要取得屬性的值,請使用下列語法,其中 PropertyName 是屬性的名稱:

$(PropertyName)

使用此語法來檢查項目檔中的某些屬性。

檢查屬性值

  1. 從程式代碼編輯器中,以下列程式代碼取代 HelloWorld 目標:

    <Target Name="HelloWorld">
      <Message Text="Configuration is $(Configuration)" />
      <Message Text="MSBuildToolsPath is $(MSBuildToolsPath)" />
    </Target>
    
  2. 儲存項目檔。

  3. 從 [命令視窗]中,輸入並執行這一行:

    msbuild buildapp.csproj -t:HelloWorld
    
  4. 檢查輸出。 您應該會看到這兩行(您的輸出可能不同):

    Configuration is Debug
    MSBuildToolsPath is C:\Program Files\Microsoft Visual Studio\2022\MSBuild\Current\Bin\amd64
    
    Configuration is Debug
    MSBuildToolsPath is C:\Program Files (x86)\Microsoft Visual Studio\2019\MSBuild\16.0\Bin
    

條件屬性

許多屬性,例如 Configuration 會有條件地定義,也就是說,屬性元素中會出現 Condition 屬性。 只有在條件評估為 「true」 時,才會定義或重新定義條件屬性。未定義的屬性會獲得空字串的預設值。 例如

<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

表示「如果 Configuration 屬性尚未定義,請加以定義,併為其提供 『Debug』 值。」

幾乎所有 MSBuild 元素都可以有 Condition 屬性。 如需使用 Condition 屬性的詳細資訊,請參閱 條件

保留的屬性

MSBuild 會保留一些屬性名稱,以儲存項目檔和 MSBuild 二進位檔的相關信息。 MSBuildToolsPath 是保留屬性的範例。 保留的屬性會以$ 這種表示法進行參考,就像任何其他屬性一樣。 如需詳細資訊,請參閱 如何:參考專案檔的名稱或位置,MSBuild 保留和已知屬性

環境變數

您可以參考項目檔中的環境變數,方式與建置屬性相同。 例如,若要在項目檔中使用 PATH 環境變數,請使用 $(Path]。 如果專案包含與環境變數同名的屬性定義,則專案中的屬性會覆寫環境變數的值。 如需詳細資訊,請參閱 如何:在組建中使用環境變數

從命令行設定屬性

您可以使用命令列參數 -property-p 命令行參數來定義屬性。 從命令行收到的屬性值會覆寫專案檔和環境變數中設定的屬性值。

若要從命令行設定屬性值:

  1. 從 [命令視窗]中,輸入並執行這一行:

    msbuild buildapp.csproj -t:HelloWorld -p:Configuration=Release
    
  2. 檢查輸出。 您應該會看到這一行:

    Configuration is Release.
    

MSBuild 會建立 Configuration 屬性,並提供 “Release” 值。

特殊字元

某些字元在 MSBuild 項目檔中具有特殊意義。 這些字元的範例包括分號(;)和星號(*)。 若要將這些特殊字元當做項目檔中的常值使用,必須使用語法 %<xx>來指定,其中 <xx> 代表字元的 ASCII 十六進位值。

將 Message 工作變更為顯示 Configuration 屬性值及其特殊字元,以提高可讀性。

若要在訊息工作中使用特殊字元:

  1. 從程式碼編輯器中,用這一行取代兩個訊息任務:

    <Message Text="%24(Configuration) is %22$(Configuration)%22" />
    
  2. 儲存項目檔。

  3. 從 [命令視窗]中,輸入並執行這一行:

    msbuild buildapp.csproj -t:HelloWorld
    
  4. 檢查輸出。 您應該會看到這一行:

    $(Configuration) is "Debug"
    

如需詳細資訊,請參閱 MSBuild 特殊字元

建置項目

項目是一段資訊,通常是檔名,作為建置系統的輸入。 例如,代表原始檔案的項目集合可能會傳遞至名為 Compile 的工作,以將它們編譯成一個組件。

所有專案都是 ItemGroup 元素的子專案。 專案名稱是子項目的名稱,而專案值是子元素的 Include 屬性值。 具有相同名稱的項目值會彙整至該名稱的項目類型中。 例如

<ItemGroup>
    <Compile Include="Program.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>

定義包含兩個項目的項目群組。 Item type Compile 有兩個值:Program.csProperties\AssemblyInfo.cs

下列程式代碼會在一個 Include 屬性中宣告這兩個檔案,並以分號分隔,以建立相同的項目類型。

<ItemGroup>
    <Compile Include="Program.cs;Properties\AssemblyInfo.cs" />
</ItemGroup>

如需詳細資訊,請參閱 專案

注意

檔案路徑相對於包含 MSBuild 專案檔的資料夾,即使專案檔是匯入的項目檔也一樣。 這方面有一些例外,例如使用 ImportUsingTask 元素時。

檢查項目類型值

若要取得專案類型的值,請使用下列語法,其中 ItemType 是專案類型的名稱:

@(ItemType)

使用此語法來檢查項目檔中的 Compile 項目類型。

若要檢查項目類型值:

  1. 從程式代碼編輯器中,以下列程式代碼取代 HelloWorld 目標工作:

    <Target Name="HelloWorld">
      <Message Text="Compile item type contains @(Compile)" />
    </Target>
    
  2. 儲存項目檔。

  3. 從 [命令視窗]中,輸入並執行這一行:

    msbuild buildapp.csproj -t:HelloWorld
    
  4. 檢查輸出。 您應該會看到這個長行字:

    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),以每行顯示一個編譯項目。

顯示每行一個項目類型值

  1. 從程式代碼編輯器中,以這一行取代訊息工作:

    <Message Text="Compile item type contains @(Compile, '%0A%0D')" />
    
  2. 儲存項目檔。

  3. 從 [命令視窗]中,輸入並執行這一行:

    msbuild buildapp.csproj -t:HelloWorld
    
  4. 檢查輸出。 您應該會看到下列幾行:

    Compile item type contains Form1.cs
    Form1.Designer.cs
    Program.cs
    Properties\AssemblyInfo.cs
    Properties\Resources.Designer.cs
    Properties\Settings.Designer.cs
    

包含、排除和通配符

您可以使用通配符 “*”、“**” 和 “?” 搭配 Include 屬性,將專案新增至項目類型。 例如

<Photos Include="images\*.jpeg" />

影像 資料夾中,將擴展名為 .jpeg 的所有檔案新增至 [相片] 項目類型。

<Photos Include="images\**\*.jpeg" />

會將所有擴展名為 .jpeg 的檔案,從 圖片 資料夾及其所有子資料夾中,新增至「相片」項目類型。 如需更多範例,請參閱 如何:選取要建置的檔案

請注意,當項目宣告時,它們會被新增至項目類型。 例如

<Photos Include="images\*.jpeg" />
<Photos Include="images\*.gif" />

會建立名為 Photo 的項目類型,其中包含 影像 資料夾中所有檔案,擴展名為 .jpeg.gif。 這些行相當於下列這一行:

<Photos Include="images\*.jpeg;images\*.gif" />

您可以使用 Exclude 屬性,從項目類型中排除專案。 例如

<Compile Include="*.cs" Exclude="*Designer*">

除了名稱包含字串 Designer的檔案外,所有擴展名為 Compile 的檔案都會加入至 項目類型。 如需更多範例,請參閱 如何:從組建排除檔案。

Exclude 屬性只會影響包含兩者之專案專案中 Include 屬性新增的專案。 例如

<Compile Include="*.cs" />
<Compile Include="*.res" Exclude="Form1.cs">

不會排除在前述元素項中新增的檔案 Form1.cs

包含和排除項目

  1. 從程式代碼編輯器中,以這一行取代訊息工作:

    <Message Text="XFiles item type contains @(XFiles)" />
    
  2. 在 Import 元素之後新增此項目群組:

    <ItemGroup>
       <XFiles Include="*.cs;properties/*.resx" Exclude="*Designer*" />
    </ItemGroup>
    
  3. 儲存項目檔。

  4. 從 [命令視窗]中,輸入並執行這一行:

    msbuild buildapp.csproj -t:HelloWorld
    
  5. 檢查輸出。 您應該會看到這一行:

    XFiles item type contains Form1.cs;Program.cs;Properties/Resources.resx
    

項目元數據

除了從 IncludeExclude 屬性收集的資訊之外,項目還可以包含元數據。 需要比僅僅是項目值更多資訊的工作可以使用此元數據。

專案檔中的項目中繼資料是透過建立一個具有中繼資料名稱的元素來宣告,並作為該項目的子元素。 專案可以有零個或多個元數據值。 例如,下列 CSFile 專案具有文化特性元數據,值為 “Fr”:

<ItemGroup>
    <CSFile Include="main.cs">
        <Culture>Fr</Culture>
    </CSFile>
</ItemGroup>

若要取得專案類型的元數據值,請使用下列語法,其中 ItemType 是專案類型的名稱,而MetaDataName是元數據的名稱:

%(ItemType.MetaDataName)

若要檢查項目元資料:

  1. 從程式代碼編輯器中,以這一行取代訊息工作:

    <Message Text="Compile.DependentUpon: %(Compile.DependentUpon)" />
    
  2. 儲存項目檔。

  3. 從 [命令視窗]中,輸入並執行這一行:

    msbuild buildapp.csproj -t:HelloWorld
    
  4. 檢查輸出。 您應該會看到下列幾行:

    Compile.DependentUpon:
    Compile.DependentUpon: Form1.cs
    Compile.DependentUpon: Resources.resx
    Compile.DependentUpon: Settings.settings
    

請注意片語 「Compile.DependentUpon」 的出現次數。 在目標內使用此語法的元數據會導致「批處理」。批處理表示目標內的工作會針對每個唯一元數據值執行一次。 批處理是 MSBuild 腳本,相當於常見的「foreach 迴圈」程式設計結構。 如需詳細資訊,請參閱 Batching

已知的元數據

每當專案新增至專案清單時,該專案就會指派一些已知的元數據。 例如,%(Filename) 傳回任何項目的檔名。 如需已知元資料的完整清單,請參閱 已知專案元資料

檢查已知的元數據:

  1. 從程式代碼編輯器中,以這一行取代訊息工作:

    <Message Text="Compile Filename: %(Compile.Filename)" />
    
  2. 儲存項目檔。

  3. 從 [命令視窗]中,輸入並執行這一行:

    msbuild buildapp.csproj -t:HelloWorld
    
  4. 檢查輸出。 您應該會看到下列幾行:

    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')的表達式,可以將來源檔案的專案清單轉換成物件檔的集合。 如需詳細資訊,請參閱 轉換

使用元數據轉換項目

  1. 從程式代碼編輯器中,以這一行取代訊息工作:

    <Message Text="Backup files: @(Compile->'%(filename).bak')" />
    
  2. 儲存項目檔。

  3. 從 [命令視窗]中,輸入並執行這一行:

    msbuild buildapp.csproj -t:HelloWorld
    
  4. 檢查輸出。 您應該會看到這一行:

    Backup files: Form1.bak;Form1.Designer.bak;Program.bak;AssemblyInfo.bak;Resources.Designer.bak;Settings.Designer.bak
    

請注意,在此語法中表示的元數據不會造成批處理。

後續步驟

若要瞭解如何一次一個步驟建立簡單的項目檔,請在 Windows 上嘗試 從頭開始建立 MSBuild 專案檔

如果您主要使用 .NET SDK,請繼續閱讀 .NET SDK 專案的 MSBuild 參考