本文討論:
Windows Installer XML 概述
創建 WiX 打包說明
集成 WiX 和 MSBuild
自動執行生成和打包
本文使用了以 下技術:Visual Studio, Windows Installer XML (WiX), MSBuild
目 錄
WiX 簡介
創建 WiX 文件WiX 和 MSBuildMSBuild 批處理自動執 行生成和打包分析 MSBuild 腳本綜述自定義過程總結
在開發過程中,重要的 是有自動的生成過程。同樣重要的是要有自動創建發布的手段。遺憾的是,在很 多組織中(尤其是較小的組織),並沒有這些。通常,您會發現發布內容只是在 最後一分鐘才被拼合在一起。但是,如果花時間建立自動生成和發布計劃,就會 節省無數的時間,您就可以將這些時間更好地用在完成任務上,而不是用來生成 和發布項目。
在本文中,我將介紹如何使用 Microsoft® Build Engine (MSBuild) 和 Windows® Installer XML (WiX) 工具集在組織中實現 自動和可重復的生成和發布過程。本文討論了 WiX v2(注意,當 WiX v3 發布時 ,不會直接轉換某些語法示例)。雖然 WiX 的確簡化了創建發布的過程,但無論 您是否使用 WiX 創建發布,本文描述的技術都可供您參考。也可以對這些技術進 行一些修改後,將它們應用於不使用 Microsoft .NET Framework 2.0 所開發的 應用程序(本文還包含指向英文網頁的鏈接)。
我將假定您熟悉 MSBuild (如果需要重新了解它,請參閱我在 2006 年 6 月的《MSDN®雜志》上的文 章 深入了解 MSBuild:通過 Microsoft Build Engine 的自定義任務以自己的方 式編譯應用程序)。我將為那些不熟悉該工具的人提供 WiX 工具集的概述。請參 見側欄“MSBuild 和 WiX 資源”中關於更多相關文章和工具的參考。 在本文中,為了進行演示,我將使用我的 Sedodream MSBuild 項目。您可以從 www.codeplex.com/Sedodream 獲得最新源代碼。
WiX 簡介
創建應 用程序時,通常最終結果是要在生產計算機上安裝並運行它。WiX 工具集可以幫 助您完成此任務。在這一節中,我將描述 WiX,並介紹如何使用 WiX 創建安裝程 序。
WiX 描述了在目標計算機上的安裝是什麼樣子的。從 Visual Studio® 到 Microsoft Office,在很多 Microsoft 應用程序中都使用了 Windows Installer。您可能會吃驚地發現:WiX 實際上是個開放源代碼的項目, 並且承載在 sourceforge.net 上。您可以從 wix.sourceforge.net 下載最新的 二進制文件和源文件。下載並安裝 WiX 後,您會發現計算機上安裝了如圖 1 中 總結的大量可執行文件。我將重點介紹 Candle.exe 和 Light.exe 工具的使用。
Figure1WiX 組件
名稱 說明 Candle.exe 將 WiX 源文件轉換為中間表示形式。 這實際上是另一個 XML 文件,但永遠不應手動更改這些生成的文件。 Dark.exe 將 MSI 文件轉換為適當的 WiX 源文件( 可以視為“反編譯”安裝程序)。 Light.exe 從 WiX 源文件的中間表示形式生成 Windows Installer。 Lit.exe 生成 WiX 庫,該庫 可用於生成其他安裝程序包。 Tallow.exe 用於創建 WiX 源 XML,以復制它在安裝目錄或文件中的文件和文件夾。 WixCop.exe 檢查 WiX 源文件中存在潛在問題的區 域,類似於 FxCop。
WiX 使用聲明性語言,而不是過程性 語言,這意味著您要描述您的安裝將是什麼樣子的,而不用描述為了實現它需要 執行哪些步驟。這可能與您的習慣不同,但它非常容易掌握。通常,要安裝在目 標計算機上的描述文件將填充 WiX 源文件。在這裡,我將重點介紹這些組件。
在 WiX 源文件中,有三個與您希望安裝的文件有關的主要元素:文件、 組件和功能。文件元素是對單個文件的引用。文件必須包含在組件元素中,組件 元素是最小的安裝單位。就是說,如果您有一個包含 100 個文件的組件,並且您 要安裝該組件,則會安裝它包含的所有文件。相反,如果不安裝該組件,則不安 裝任何文件。建議不要創建包含大量文件的組件。
組件始終包含在功能元 素中,並且可以包含在多個功能中。功能是一組組件,也可能是一組子功能。如 果安裝程序具有允許用戶選擇要安裝哪些項的圖形界面,則用戶實際是在選擇功 能。
創建 WiX 文件
可以在您選擇的任何文本或 XML 編輯器中創作 WiX 源 文件。還可以使用 Visual Studio,利用 IntelliSense® 創作 WiX 源文件 。如果在使用 Visual Studio 編輯 WiX 源文件時未啟用 IntelliSense,則您唯 一要做的是將 wix.xsd 文件復制到 Visual Studio 架構目錄中。通常,此目錄 位於 %Program Files%\Microsoft Visual Studio 8\Xml\Schemas。創建 WiX 源 文件時,還需要生成很多 GUID。Visual Studio 有一個可用於此目的工具,還有 一些 Visual Studio 宏也可用於分配快捷方式,以便直接插入新的 GUID。
現在,讓我們開始創建新的 WiX 源文件。第一個元素始終是 Wix 元素。Wix 元素的子元素包括 Product、Fragment、Module 和 PatchCreation。預期輸出的 類型將決定您將使用其中的哪個子元素。在這裡,我希望最終結果是我的項目的 安裝程序數據庫 (MSI) ,因此我將使用 Product 元素。下面是示例項目的 WiX v2 源文件 Sedodream.wxs 的開頭部分:
<?xml version='1.0' encoding='UTF-8'?> <Wix xmlns='http://schemas.microsoft.com/wix/2003/01/wi'> <Product Name='Sedodream MSBuild Project' Id='C9D25926-FCE0-4EB6-8FF5-4686EE5AB089' Language='1033' Codepage='1252' Version='1.0.0' Manufacturer='SedoTech' UpgradeCode='9C5E4073-EFDE-419B-935D-CE2632BC560E'> <Package Id='????????-????-????-????-????????????' Keywords='Installer' Description='Sedodream MSBuild Project Installer' InstallerVersion='100' Languages='1031' Compressed='yes' SummaryCodepage='1252' /> ...
可以看到,Product 元素有很多屬性,其中最重要的是 Id 和 Name 。Id 用於唯一標識產品。對於新的主要發布必須更改 Id。還應當記錄下它的值 ,以便隨後引用。Name 屬性的值是將顯示在“添加/刪除程序”面板 中的值,如果安裝程序有 UI,它將顯示在簡介頁上。
Product 元素的第 一個子項 Package 元素也顯示在這裡。注意,Id 屬性包含一系列 GUID 格式的 ? 字符。通過使用此語法,代碼指定應當在生成時生成 Id。創建安裝程序時,可 以讓所創建的每個安裝程序的 Package Id 各不相同,甚至讓每次生成的安裝程 序不同。這是您可以讓系統自動生成的唯一 GUID;其他所有 GUID 都需要保持相 同,並應記錄下來,供將來引用。
幾乎每個安裝程序都會將至少一個文件 放在目標計算機上,而且此安裝程序沒有差異。由於 WiX 使用聲明性方式,所以 我將聲明目錄結構是什麼,並且將在目標計算機上重新創建它。我使用一系列 Directory 元素完成該操作:
<Media Id='1' Cabinet='Sedodream.cab' EmbedCab='yes'/> <Directory Id='TARGETDIR' Name='SourceDir'> <Directory Id='ProgramFilesFolder' Name='PFiles'> <Directory Id='MSBuildDir' Name='MSBuild'> <Directory Id='INSTALLDIR' Name='Sedodrea' LongName='Sedodream'>
此示例中的 Media 元 素用於指定將生成一個壓縮文件,並且要將它放在安裝程序數據庫中。這是必需 元素,如果安裝文件跨越多個介質,則可以有多個該元素。例如,如果在 CD 上 分發應用程序,但它需要跨越多張盤。大多數情況下,不必擔心這個問題。
下面的 Media 是 Directory 元素系列。第一個 Directory 元素將是僅 封裝其他條目的虛擬元素。TARGETDIR 目錄元素下的條目的 Id 值是 ProgramFilesFolder。您可能已猜到,這是眾所周知的位置,並且 Windows Installer 將在啟動時設置它的值。還有其他可以使用的系統文件夾;若要查看 完整列表,請訪問 msdn.microsoft.com/library/en- us/msi/setup/system_folder_properties.asp。這些系統屬性始終解析為其完整 路徑。
接下來的元素提供自定義目錄的名稱。如果可能,該目錄將使用 LongName 屬性進行命名;否則使用 Name 屬性。如果這些目錄都不存在, Windows Installer 將在安裝時創建合適的目錄。在前面的代碼段中聲明的內容 的完整樹以C:\Program Files\MSBuild\Sedodream 結束。
聲明目錄結構之後,即可開始創建 Component 聲明。前面提到過,可以安裝 的最小單位是組件,組件可以由很多不同項組成,這些項包括文件、快捷方式、 注冊表項和證書。請設計您的組件,使它們相互獨立。就是說,安裝或卸載組件 時,不應當對其他組件有任何負面影響。實際上,這意味著這些項應當僅包含在 單個組件中。如果不是這種情況,則可能要重新考慮如何組織組件。組件只包含 單個文件是很平常的。
每個組件聲明必須有一個 Id 和一個 GUID 屬性。Id 是用於引用組件的名稱 ,GUID 是 Windows Installer 要使用的唯一標識符。非常重要的一點是,要確 保所有組件的 GUID 都不重復。
圖 2 顯示了示例 WiX 源文件中的組件。可以看到它包含四個 File 元素和兩 個 XmlFile 元素。File 元素只是對需要放在目標設備中的文件的引用。File 元 素可以有很多不同屬性,但您使用的最多的是 Id、Name、LongName、Source 和 DiskId,如圖 3 所示。
Figure3 文件屬性
屬性名稱 說明 Id 可用於引用文件的標識符。 Name 8.3 格式的文件短名稱。 LongName 文件的長名稱;這是將用在目標計算機上的名稱(如果該計算機支持 長文件名)。否則使用 Name 值。 Source 在要創建安裝程序數據庫的計算機上的文件的相對路徑。 DiskId 將包含此文件的介質項的標識符。
Figure2 定義組件
<Component Id='TaskBinFiles' Guid='38736E2E-BEB7-48A9-A2B3- 138A57A69D45'>
<File Id='MSBCommonDLL' Name='CommoDLL'
LongName='Sedodream.MSBuild.Common.dll'
Source='Sedodream.MSBuild.Common.dll' Vital='yes' DiskId='1'/>
<File Id='SedodreamLoggersDLL' Name='Logger'
LongName='Sedodream.MSBuild.Loggers.dll'
Source='Sedodream.MSBuild.Loggers.dll' Vital='yes' DiskId='1'/>
<File Id='SedodreamTasksDLL' Name='Tasks'
LongName='Sedodream.MSBuild.Tasks.dll'
Source='Sedodream.MSBuild.Tasks.dll' Vital='yes' DiskId='1'/>
<File Id='SedodreamTASKS' Name='SeTasks' LongName='Sedodream.tasks'
Source='Sedodream.tasks' Vital='yes' DiskId='1'/>
<!-- Merge in the Xsd for the custom tasks we have created to have
IntelliSense -->
<XmlFile Id='SedoSche'
File='C:\Program Files\Microsoft Visual Studio 8\
Xml\Schemas\1033 \Microsoft.Build.xsd'
Action='createElement' ElementPath='//xs:schema'
Name='xs:include' Permanent='no' Sequence='0'/>
<XmlFile Id='SedoSch2'
File='C:\Program Files\Microsoft Visual Studio 8\
Xml\Schemas\1033\Microsoft.Build.xsd'
Action='setValue'
ElementPath='//xs:schema/xs:include[\[]not(@schemaLocation)[\]]'
Name='schemaLocation' Value='MSBuild\Sedodream.MSBuild.xsd'
Permanent='no' Sequence='1' />
</Component>
XmlFile 元素實際上用於修改目標計算機上的現有 XML 文件。它將新元素插 入 Microsoft.Build.xsd 文件中,該文件允許對包含在示例項目中的自定義 MSBuild 任務啟用 IntelliSense。
Feature 是在安裝程序顯示 UI 的情況下用戶要選擇安裝的項。下面是示例項 目中的 Feature 聲明:
<Feature Id='Complete' Title='Sedodrem Core' Description='MSBuild libraries' Display='expand' Level='1' ConfigurableDirectory='INSTALLDIR'> <ComponentRef Id='TaskBinFiles'/> <ComponentRef Id='NUnitFiles'/> <Feature Id='Samples' Title='Samples' Description='Contains samples of Sedodream usage' Display='expand' Level='100' ConfigurableDirectory='INSTALLDIR'> <ComponentRef Id='Samples'/> </Feature> </Feature>
像其他很多 WiX 元素一樣,Feature 元素有很多可能的屬性,圖 4 描述了一 些較常用的屬性。
Figure4 功能屬性
屬性名稱 說明 Id 標識符,用於引用功能。 ConfigurableDirectory 允許您從屬性設置安裝位置,可以由用戶通過 UI 確定該位置。 Description 對功能的說明,它將通過 UI 向用戶顯示。 Level 指定功能的安裝級別。值為零意味著將不安裝該功能。小於或等於 INSTALLLEVEL 的非零值意味著安裝該功能。 Title 功能的標題,如果使用 UI,其值將顯示在功能樹中。在此 WiX 片段中,主要的功能“Complete”包含對兩個組件和一個子功能的 引用。子功能引用通過子 Feature 元素實現。WiX 源文件可以包含任何數目的這 些所需項。組件引用使用 ComponentRef 元素。使用 ComponentRef 元素時,所 使用的 ID 值必須與在嘗試引用的 Component 元素中所使用的該值相同。
WiX 和 MSBuild
在最新發布的 WiX v2 中,您將發現 wix.targets 文件,該文件包含的定義 將幫助您從 MSBuild 創建 WiX 發布。WiX 團隊已創建了一組被 wix.targets 文 件引用的 MSBuild 任務。這些任務全部包含在 WiXTasks.dll 程序集中,如圖 5 所示。
Figure5 WiX 的 MSBuild 任務
名稱 說明 Candle 通過調用 WiX 編譯器創建 WiX 源文件的中間表示形式。 Lit 從中間表示形式創建 WiX 庫。 Light 通過調用 WiX 連接器,從中間表示形式創建最終的安裝程序。
您生成安裝程序的方式非常類似於現在生成托管項目的方式。例如,創建 C# 項目時,項目文件將包含生成項目所需的所有屬性和項,但生成項目的所有步驟 則包含在 Microsoft.CSharp.targets 文件中。此文件將通過 MSBuild Import 元素包含到項目文件中。對於 WiX,項目文件將定義所有需要的屬性和項,然後 包含 wix.targets 文件以定義如何生成最終包的邏輯。圖 6 提供了使用 wix.targets 成功生成安裝程序所需的最低聲明的列表。
Figure6 生成安裝程序所需的聲明
名稱 說明 ToolPath 包含 WiX 安裝目錄的路徑。這是 wix.targets 文件的駐留位置。 OutputName 將創建的輸出的路徑和名稱。該名稱不應包含任何擴展名,因為中間 表示形式和最後的包文件都將使用它。此屬性類似於 Candle.exe 和 Light.exe 的 OutputFile 參數。 OutputType 表示最後的文件應當是什麼。可能的值是包、模塊、庫和對象。它將 確定要調用 Light 還是 Lit 任務,以及所創建的最終文件的擴展名。由於我們 要創建安裝程序,因此我們將為此屬性提供值 package。 Compile 包含要編譯的 WiX 源文件的 MSBuild 項。 BaseInputPath 作為源文件的輸入路徑。盡管該技術不是必需的,但在大多數情況下 應使用它。否則,您必須確保從正確的目錄調用 msbuild.exe。若要創建安裝程序,需要創建 MSBuild 文件,以定義必需的屬性和項。在這 裡,我將該文件命名為 SedodreamMSI.wproj。圖 7 中顯示了此文件。
Figure7 MSBuild 文件 SedodreamsMSI.wproj
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build"> <!-- =============================================================== These must be declared BEFORE the statement that imports the wix.targets file ==================================================================- -> <PropertyGroup> <!-- The location pointing where WiX is installed --> <ToolPath>C:\Data\Development\WiX\</ToolPath> <!-- Required Property by WiX --> <OutputName Condition="$(OutputName)==''" > $(Configuration)Sedodream</OutputName> <!-- Required property by WiX --> <OutputType Condition="$(OutputType)==''" >package</OutputType> <!-- Input path to source files --> <BaseInputPath Condition="$(BaseInputPath)==''"> $(PackageRoot)$(Configuration)</BaseInputPath> </PropertyGroup> <ItemGroup> <!-- Required WiX item. Files in this item are sent to the Candle tool. --> <Compile Include="$(BaseInputPath)\Sedodream.wxs"/> </ItemGroup> <Import Project="$(ToolPath)wix.targets"/> </Project>
可以看到,此 MSBuild 文件中的內容不是很多,只定義了少量屬性和一個單 項。該文件假定 WiX 源文件 Sedodream.wxs 已創建,並且駐留在 BaseInputPath 目錄中。WiX 文件還對文件的存放位置進行了一些假定。現在, 我們假定所有文件都在期望的位置。
為了生成安裝程序,我需要對項目文件調用 MSBuild。我打開 Visual Studio 2005 命令提示符,導航到文件所在位置,並執行以下命令:
msbuild Sedodream.wproj
輸出顯示在圖 8 中。
由於我沒有定義要執行的目標,因此會執行 DefaultTargets,並且它被定義 為 Sedodream.wproj 文件中的 Build。從輸出,可以看到在 bin\Release 文件 夾中創建了名為 ReleaseSedodream.msi 的文件。在這裡,可以執行安裝程序, 以確保它按期望工作。在繼續實現我們的主要目標之前,我將在下一節討論高級 MSBuild 主題:批處理。之所以需要這樣做,是因為在生成產品及其發布的整個 過程中要用到批處理。
圖 8從 MSBuild 實現的 WiX 安裝程序創建輸出
MSBuild 批處理
使用 MSBuild 時,您將發現找不到循環構造。您可以使用批處理來代替循環 ,批處理使用項的元數據將項劃分成不同的類別,這些類別稱為批或桶,它們是 由一個或多個項組成的。一旦劃分了項,就可以迭代遍歷每個批。這種方式在托 管項目的整個生成過程中使用。批處理有兩個大的類別:任務批處理和目標批處 理。在任務批處理中,當您執行任務時,MSBuild 引擎將確定需要創建什麼存儲 桶,並通過這些存儲桶執行任務。若要使用任務批處理,則要向任務提供項的元 數據。
若要演示批處理,請想象您面對以下情形。您必須將一組文件從一個位置復制 到一個或多個其他位置,並且您有兩個選項:可以使用單個 Copy 任務將文件復 制到每個位置,也可以使用批處理在一個復制元素中實現該操作。第一個方案盡 管簡單,但不是個好的解決方案,因為它難以維護。為了說明第二個方案,請參 考下面這個非常簡單的 MSBuild 文件 batching01.proj:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="CopyFiles"> <ItemGroup> <SourceFiles Include="*.txt"/> <Dest Include="One;Two;Three;Four;Five"/> </ItemGroup> <Target Name="CopyFiles"> <Copy SourceFiles ="@(SourceFiles)" DestinationFolder="%(Dest.FullPath)"/> <Message Text="Fullpath: %(Dest.FullPath)"/> </Target> </Project>
在此文件中,我聲明了一個 SourceFiles 項,包括以 .txt 結尾的任何文件 ,然後我還聲明了一個 Dest 項,包括五個位置。在目標 CopyFiles 中,我使用 Copy 任務將 SourceFiles 復制到每個目標位置。由於我將 FullPath 元數據傳 遞到 Copy 任務中,因此 MSBuild 引擎將創建一個由所有具有不同 FullPath 值 的 Dest 項組成的批,然後對每個批調用 Copy 任務。這就是任務批處理。為了 執行它,我可以從包含 batching01.proj 文件的目錄調用以下命令:
msbuild.exe batching01.proj
現在,我將用目標批處理演示相同結果。對於目標批處理,批是基於目標的 Inputs 和 Outputs 創建的,因此我必須為這些值傳遞項的元數據:
<Project xmlns="http://schemas. microsoft.com/developer/msbuild/2003" DefaultTargets="CopyFiles"> <ItemGroup> <SourceFiles Include="*.txt"/> <Dest Include="One;Two;Three;Four; Five"/> </ItemGroup> <!-- These targets demonstrate target batching --> <Target Name="CopyFiles" Inputs="@(SourceFiles)" Outputs="%(Dest.FullPath)"> <Copy SourceFiles="@(SourceFiles)" DestinationFolder= "%(Dest.FullPath)"/> </Target> </Project>
目標批處理是以目標 Inputs 和 Outputs 驅動的。由於 Outputs 包含 Dest.FullPath 聲明,因此每存儲桶將調用目標一次。這類似於任務批處理,不 同的是整個目標的內容將每批重復一次,如圖 9 所示。
圖 9目標批處理的 MSBuild 輸出
從此輸出中,可以看到對於 Dest 項,每批調用一次目標 CopyFiles。在自動 執行生成/打包過程的示例中,我將使用批處理為配置平台與風格的每個組合創建 安裝程序。
自動執行生成和打包
對於每個組織來說,有時由於所使用的技術,有時由於組織要求,使得生成和 打包所涉及的步驟略微不同。我將一組我認為可以很好地適合很多組織的步驟放 在一起,雖然可能需要根據特定情形對它進行一些微調。自動的生成和打包過程 的目標是雙重的:創建可重復的公用生成過程,以及創建自動的可重復打包過程 。有三個核心步驟:更新、生成和打包,但這又細分成很多更小的步驟,如圖 10 所示。
圖 10生成過程
一個非常重要的步驟是標記源文件。之所以要這樣做,是因為如果沒有此步驟 就不能重復該過程。創建一個將發送用於生產的生成版本時,需要能夠重新創建 完全相同的生成版本,以便維護所部署的代碼。根據用作源代碼管理提供程序的 工具,此步驟將有所不同。針對各種不同的源代碼管理提供程序,可以下載很多 不同的 MSBuild 任務來實現此目的。有關詳細信息,請參見側欄“MSBuild 和 WiX 資源”。
分析 MSBuild 腳本
在這一節中,我將介紹可以用於生成和打包示例應用程序的 MSBuild 腳本。 總體結構非常類似於托管項目的生成方式。就是說,您將定義一個項目文件,在 其中包含應當處理的各項,然後導入另一個用於定義過程流的項目文件 Sedodream.Package.targets。請將這些過程視為句子。打包項目文件用於定義名 詞,導入的文件用於定義謂詞。我將通過對 Solution 文件使用 MSBuild 任務來 生成項目。若要生成安裝程序,將使用前面的項目文件 SedodreamMSI.wproj。
如果您有一個過程具有多個分離元素,那麼需要將它們以某種方式聚合在一起 。可以通過定義一組公用的屬性、項和目標來完成該操作(參見圖 11)。
Figure1 1用於連接元素的屬性和項
名稱 說明 SolutionFilePath 用於定義將用來生成產品的解決方案文件的位置的屬性。 PackageRoot 用於定義在哪裡生成項目並作為 WiX 的臨時生成位置的屬性。 WiXSourceFiles 包含要發送到 Candle 工具進行編譯的所有 WiX 文件的項。 AllConfigurations 包含生成此過程要針對的所有配置的項。每個配置都應當包含 FlavorToBuild 和 PlatformToBuild 的元數據值。示例聲明是:<AllConfigurations Include="Release|Any CPU"> <FlavorToBuild>Release</FlavorToBuild> <PlatformToBuild>Any CPU</PlatformToBuild> </AllConfigurations>OtherFiles 可選項,其中包含應當復制到包目錄中的其他文件。這些項應當包含 Destination 元數據。此元數據定義了目標相對於包的根目錄的相對路徑。這是 示例聲明:
<OtherFiles Include= "..\Sedodream.MSBuild.Tasks\SampleTargets\**\*"> <Destination>Samples\</Destination> </OtherFiles>
在此過程中,將生成解決方案,並且會將 WiX 源文件復制到相同目錄中。您 應當定義您的 WiX 源文件,並記住此路徑。不管 WiX 文件包含於源代碼管理中 的什麼位置,都將從生成產品的相同目錄中生成這些文件。其他必需文件也將由 CopyFilesForPackaging 目標復制到此目錄。
在此過程中,PackageRoot 屬性還將定義在哪裡生成項目以及 WiX 將在哪裡 生成安裝程序。在示例中,目錄處於與解決方案文件相同的級別,但它可以是生 成計算機上的任何位置(雖然我建議此位置不要使用網絡共享)。
圖 12 顯示了 Sedodream.Package.targets 文件中聲明的主要目標。所有這 些目標(以及目標文件中的其他很多目標)都有其在屬性中定義的依賴項,因此 您可以在此過程中完全更改事件的順序。例如,如果需要在 Build 目標執行項目 文件之前注入步驟,則可以在 Sedodream.Package.targets 文件的 Import 語句 之後直接插入以下片段:
<BuildDependsOn> CustomBeforeBuild; $(BuildDependsOn); </BuildDependsOn>
Figure1 2在示例項目中生成目標
名稱 說明 Package 只調用 DefaultTargets 列表中的目標以執行整個過程。 Build 生成解決方案文件。在調用 MSBuild 任務時,通過重寫 OutputPath 屬性,將把此生成過程的輸出發送到正確的目錄。 CopyFilesForPackaging 將所有未生成但需要用到的文件復制到生成目錄。 DeployPackage 接近過程結束時調用。在示例中此目標為空,但在實現時可以決定重 寫該目標,以便將包發送到 QA 環節或部署團隊。 Clean 清理其他目標造成的混亂。
由於已重新定義了 BuildDependsOn 屬性,因此可以有效地將 CustomBeforeBuild 步驟注入到當前過程中,而不用修改現有目標文件。若要了 解對這個問題的更詳細討論,應參閱我在 2006 年 6 月的文章(前面已引用)。
在創建安裝程序之前,讓我們快速看一下生成解決方案的 CoreBuild 目標( 參見圖 13)。它將演示如何針對每個已定義的配置,使用目標批處理來生成解決 方案。
Figure 13 CoreBuild 目標
<Target Name="CoreBuild"
Inputs="% (AllConfigurations.PlatformToBuild);
% (AllConfigurations.FlavorToBuild)"
Outputs="% (AllConfigurations.PlatformToBuild);
% (AllConfigurations.FlavorToBuild)" >
<Message Text="Building for Flavor/Platform:
% (AllConfigurations.FlavorToBuild)/
% (AllConfigurations.PlatformToBuild)"/>
<MSBuild Projects="@(SolutionFile)"
Targets="Build"
Properties="OutputPath=$(PackageRoot)
% (AllConfigurations.FlavorToBuild);
Configuration=% (AllConfigurations.FlavorToBuild);
Platform=% (AllConfigurations.PlatformToBuild)">
<Output ItemName="OutputFiles" TaskParameter="TargetOutputs"/>
</MSBuild>
</Target>
具體來說,首先要注意的是 Inputs 和 Outputs;它們是 AllConfigurations 項的元數據值,該項將使目標按每個平台/風格配對分別執行一次。然後,調用 MSBuild 任務以生成具有所有相應屬性的解決方案文件。之所以提供 OutputPath ,是因為我要將輸出重定向到另一個目錄。
綜述
至此,我已討論了如何使用 WiX 創建安裝程序、某些高級 MSBuild 概念以及 MSBuild 打包腳本的結構。對於為示例項目創建安裝程序,剩下的唯一問題是創 建 MSBuild 項目文件,以定義必需屬性。這非常的簡單。最後,我將介紹如何根 據具體需要自定義該過程。
圖 14 顯示了 MSBuild 文件 Sedodream.Package.dproj,它將驅動示例項目 的該過程。前面討論過,此項目文件的主要目的是描述需要生成什麼。導入的文 件 Sedodream.Package.targets 知道如何創建最後產品的所有細節,還可以通過 向生成過程注入步驟來自定義該過程。
Figure 14 Sedodream.Package.dproj MSBuild 項目
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
DefaultTargets="Package">
<!-- Required properties by the deployment.targets file -->
<PropertyGroup>
<SolutionFilePath>..\Sedodream.MSBuild.sln</SolutionFilePath&g t;
<PackageRoot>..\Package\</PackageRoot>
</PropertyGroup>
<ItemGroup>
<WiXSourceFiles Include="Sedodream.wxs"/>
<OtherFiles Include="..\Sedodream.MSBuild.Tasks\
SampleTargets\**\*">
<Destination>Samples\</Destination>
</OtherFiles>
<!-- Copy the license to the BaseSearchPath so it can
be included into the installer - ->
<OtherFiles Include="License.rtf">
<Destination></Destination>
</OtherFiles>
<!-- Copy the custom installer bitmaps -->
<OtherFiles Include="bitmaps\dlgbmp.bmp">
<Destination>bitmaps\</Destination>
</OtherFiles>
</ItemGroup>
<!-- Define all the configurations that you want to build here -->
<ItemGroup>
<AllConfigurations Include="Debug|x86">
<FlavorToBuild>Debug</FlavorToBuild>
<PlatformToBuild>Any CPU</PlatformToBuild>
</AllConfigurations>
<AllConfigurations Include="Release|Any CPU">
<FlavorToBuild>Release</FlavorToBuild>
<PlatformToBuild>Any CPU</PlatformToBuild>
</AllConfigurations>
</ItemGroup>
<PropertyGroup>
<DropLocation>C:\Data\Drops\MSBuild-Wix\</DropLocation>
</PropertyGroup>
<!-- Import the deployment target to do all the work for us -->
<Import Project="Sedodream.Package.targets"/>
</Project>< /pre>
在此項目文件中,可以看到已定義的必需的 SolutionFilePath 屬性。 這是將用於生成產品的解決方案文件的路徑。而且,可以看到 WixSourceFiles 項的聲明,其中包括將用於編譯安裝程序的文件集合。它們是將發送給 Candle.exe 工具進行編譯的文件。
同時還提供了 OtherFiles 項的聲明,其中包含那些應當復制到將用於創建 安裝程序的位置的文件。這些文件將復制到用於創建安裝程序的 BaseInputPath 中。通過使用 Destination 元數據值,可以將它們復制到 BaseInputPath 下面 的任何位置。在此示例中,我會將用於生成安裝程序的自定義位圖復制到位圖文 件夾中。當調用 Light.exe 工具來創建 MSI 文件時,它將在選取位於本地目錄 中的任何默認文件之前,先選取在此目錄中的文件。
注意 DropLocation 屬性的聲明。通過聲明此屬性,在 PackageRoot 中的所 有文件都將復制到 DropLocation 中的目錄內。當需要快速進行某些修改時,將 二進制文件和安裝程序文件放在同一個位置將大有幫助。
若要看到為示例項目執行的生成文件和包,請打開 Visual Studio 2005 命令 提示符,並導航到項目部署文件夾。然後執行以下命令:
msbuild SedodreamPackage.dproj
命令提示符下會生成很多輸出,您將在 Package 目錄下發現兩個目錄:Debug 和 Release。這兩個目錄都將包含所生成的安裝程序及其關聯文件。
自定義過程
為產品設置此過程時,將需要創建類似於 SedodreamPackage.dproj 文件的文 件。可以將自定義內容直接放在該文件內。應當不需要更改 Sedodream.Package.targets 文件本身。如果要注入步驟,可以執行先前描述的 過程。如果要重新定義目標,可以通過在 import 語句之後重新聲明目標,直接 重寫它們。例如,Sedodream.Package.targets 文件定義了目標 GetLatest,但 它為空。在此目標中,應當放入必要的任務,以便從存儲庫獲得最新的源文件。 下面是它在項目中的大致模樣:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
DefaultTargets="Package">
<!-- Your properties and items defined here -->
<!-- Import the deployment target to do all the work for us -->
<Import Project="Sedodream.Package.targets"/>
<!-- Place overriding customizations after this point -->
<Target Name="GetLatest">
<Message Text="Getting latest sources"/>
<!-- Insert tasks to get latest from source control -->
</Target>
</Project>
圖 15 提供了在 Sedodream.Package.targets 文件中定義的重要目標的列表 。可以自定義這些目標,以適合具體需要。
剩下的主要問題是如何自動執行此過程,現在這一問題非常簡單。您唯一要做 的是對部署文件自動執行 MSBuild.exe,在這裡,該文件是 SedodreamPackage.dproj。如何完成該操作將取決於當前如何生成公用生成文件 。如果正在使用 Visual Studio Team Foundation Server,則可以使用 Team Build 來執行此操作。可以使用 TFSBuild.proj 文件中的 MSBuild 任務。如果 使用其他某些技術,則很可能它們對 MSBuild 有本機支持。如果不借用任何一種 上述技術,可以使用 Windows Scheduler 定時執行此操作。
總結
在本文中,我介紹了如何基於 WiX 工具集創建自動的生成文件和打包過程。 一旦完成了此集成,就可以按可靠和可重復的方式生成和打包產品。這對即將發 送到部署位置的應用程序是非常重要的。
如果 WiX 不是您的安裝程序技術, 仍然可以在進行某些修改後使用其理念和文件。所有我知道的安裝程序技術都支 持某種形式的命令行執行方式。您可以借用此方式,以使用這些其他技術來創建 您的安裝程序。另外隨 MSBuild 任務和目標一同提供了某些第三方安裝程序技術 ,它們可幫助您重新創建此過程。
配套源碼:http://msdn.microsoft.com/zh-cn/magazine/cc164501.aspx