這個Target會輸出當前日期。它的命令要做的事情就是“echo %25date%25”,但是“%”字符在MSBuild中有特殊含義,所以這個命令需要被轉義。當遇到轉義字符的時候,“%”后面的十進制字符會被轉成對應的ASCII碼。MSBuild只會執行Project元素中的第一個Target。要執行其他Target的時候,需要把/target開關(可簡寫為 /t)加上Target名稱傳給MSBuild。你也可以指定MSBuild執行多個Target,只要用分號分割Target名字就可以。
C:\>msbuild basics.msbuild /nologo /verbosity:minimal /t:EchoGreeting;EchoDate
Hello from MSBuild
Thu 08/02/2012
更實用的構建腳本
演示就先到這里。下面來用MSBuild來構建一個真實項目。首先把示例代碼下載下來,或是自己創建一個ASP.NET應用。給它添加一個MSBuild腳本,以solution或project名字給腳本命名,擴展名用“.msbuild”。照先前一樣指定MSBuild命名空間。
開始寫腳本之前,先把腳本要干的事情列出來:
創建BuildArtifacts目錄
構建solution,把構建產物(DLL,EXE,靜態內容等等)放到BuildArtifacts目錄下。
運行單元測試。
因為示例應用叫做HelloCI,于是這個腳本也就命名為HelloCI.msbuild。先添加命名空間,然后就可以添加第一個Target了,我管它叫做Init。
這個Target會調用MakeDir Task創建一個新的目錄,名叫BuildArtifacts,跟腳本在同一目錄下。運行腳本,你會發現該目錄被成功創建。如果再次運行,MSBuild就會跳過這個Task,因為同名目錄已經存在了。
接下來寫一個Clean Target,它負責刪除BuildArtifacts目錄和里面的文件。
理解了Init之后,這段腳本就應該很好懂了。試著執行一下,BuildArtifacts目錄應該就被刪掉了。下面再來把代碼中的重復干掉。在Init和Clean兩個Target里面,我們都把BuildArtifacts的目錄名硬編碼到代碼里面了,如果未來要修改這個名字的話,就得同時改兩個地方。這里可以利用Item或Property避免這種問題。
Item和Property只有些許差別。Property由簡單的鍵值對構成,在腳本執行的時候還可以用 /property 賦值。Item更強大一些,它可以用來存儲更復雜的數據。我們這里不用任何復雜數據,但需要用Items獲取額外的元信息,例如文件全路徑。
接下來修改一下腳本,用一個Item存放路徑名,然后修改Init和Clean,讓它們引用這個Item。
Item是在ItemGroup里面定義的。在一個Project中可以有多個ItemGroup元素,用來把有關系的Item分組。這個功能在Item較多的時候特別有用。我們在ItemGroup里定義了BuildArtifactsDir元素,并用Include屬性指定BuildArtifacts目錄。記得BuildArtifacts目錄后面要有個斜杠。最后,我們用了@(ItemName)語法在Target里面引用這個目錄?,F在如果要修改目錄名的話,只需要改BuildArtifactsDir的Include屬性就好了。
接下來還有個問題要處理。在BuildArtifacts目錄已經存在的情況下,Init是什么事都不干的。也是就說,在調用Init的時候磁盤上的已有文件還會被保留下來。這一點著實不妥,如果能每次調用Init的時候,都把目錄和目錄里面的所有文件都一起刪掉再重新創建,就能保證后續環節都在干凈的環境下執行了。我們固然可以在每次調用Init的時候先手工調一下Clean,但給Init Target加一個DependsOnTargets屬性會更簡單,這個屬性會告訴MSBuild,每次執行Init的時候都先執行Clean。
現在MSBuild會幫我們在調Init之前先調Clean了。跟DependsOnTargets這個屬性所暗示的一樣,一個Target可以依賴于多個Target,之間用分號分割就行。
接下來我們要編譯應用程序,把編譯后的結果放到BuildArtifacts目錄下。先寫一個Compile Target,讓它依賴于Init。這個Target會調用另一個MSBuild實例來編譯應用。我們把BuildArtifacts目錄傳進去,作為編譯結果的輸出目錄。
Release
Any CPU
Properties="OutDir=%(BuildArtifactsDir.FullPath);Configuration=$(Configuration);Platform=$(BuildPlatform)" />
上面的腳本做了幾件事情。首先,ItemGroup添加了另一個Item,叫做SolutionFile,它指向solution文件。在構建腳本中用Item或Property代替硬編碼,這算的是一個優秀實踐吧。
其次,我們創建了一個PropertyGroup,里面包含兩個Property:Configuration和BuildPlatform。它們的值分別是“Release”和“Any CPU”。當然,Property也可以在運行時通過/property(簡寫為/p)賦值。我們還用了Condition屬性,它在這里的含義是,只有當這兩個屬性沒有值的情況下,才用我們定義的數據給它們賦值。這段代碼實際上就是給它們一個默認值。
接下來就是Compile Target了,它依賴于Init,里面內嵌了一個MSBuild Task。它在運行的時候會調用另外一個MSBuild實例。在腳本中定義了這個被內嵌的MSBuild Task要操作的項目。在這里,我們既可以傳入另外一個MSBuild腳本,也可以傳入.csproj文件(它本身也是個MSBuild腳本)。但我們選擇了傳入HelloCI應用的solution文件。Solution文件不是MSBuild腳本,但是MSBuild可以解析它。腳本中還指定了內嵌的MSBuild Task要執行的Target名稱:“Rebuild”,這個Target已經被導入到solution的.csproj文件中了。最后,我們給內嵌的Task傳入了三個Property。
OutDir
編譯結果的輸出目錄
原文轉自:http://www.anti-gravitydesign.com