.NET用ビルドエンジン「MSBuild」の使い方と、簡単なサンプル。 MSBuildを使うことでコマンドラインからソリューション・プロジェクトのビルドを行ったり、高度なバッチ処理を行ったりすることができる。
MSBuildの基本
MSBuildの基本的な使い方とビルド方法。
パスを通す
まず、環境変数PATHを設定してMSBuildのパスを通す。
.NET Framework
「システムのプロパティ」→「詳細設定」→「環境変数」でPathに下記のパスを追加する。
または、コマンドライン上で下記のコマンドを入力する。
パスを通したら、MSBuildが起動するか確かめる。
上記のようにバージョンが表示されれば問題なし。
Mono
シェル上で下記のコマンドを入力する。 (Monoが/opt/mono/以下にインストールされている場合の例)
パスを通したら、MonoのMSBuild互換実装であるXBuildが起動するか確かめる。
上記のようにバージョンが表示されれば問題なし。 XBuildはコマンド名がxbuildとなっている点を除いて、コマンドラインオプションはすべてMSBuildと同じ。
MSBuildを使ったビルド
MSBuildの引数にソリューションファイル(*.sln)やプロジェクトファイル(*.csproj, *.vbproj)を指定することでソリューション・プロジェクトのビルドを行うことができる。
MSBuildのコマンドラインオプション
ビルド動作の指定 (/targetオプション)
/target(または/t)オプションを使うことでビルドの動作(ターゲット)を指定できる。 例えば、Cleanを指定すれば一時ファイルの削除、Runを指定すればビルド済みの実行可能ファイルの実行を行うことができる。 以下のようなターゲットを/target:targetsの形式で指定することができる。 ターゲットはカンマ , またはセミコロン ; で区切ることで複数することができる。 この場合、ターゲットが指定された順に動作する。 プロジェクトファイルではデフォルトのターゲットは「Build」になっているので、ターゲットを指定しない場合は「Build」の動作でプロジェクトのビルドが行われる。
ターゲット | 動作 |
---|---|
Build | ビルド |
Clean | クリーン 一時ファイルやビルド済みファイルを削除する |
Rebuild | リビルド (Build;Cleanを指定するのと同じ) |
Run | 実行 ビルド済み実行可能ファイルの実行を行う |
たとえば、
上記のようなソースを含むプロジェクトファイルをビルドする際、ターゲットを指定せずにMSBuildに渡した場合は次のような動作となる。
一方、オプション「/target:Rebuild,Run」を指定してビルドすると次のような動作となる。
ビルド構成・コンパイルスイッチの指定 (/propertyオプション)
/property(または/p)オプションを使うことでビルド時に使用するプロジェクトのプロパティ(ビルド構成やコンパイルスイッチなど)を指定することができる。 「/property:name=value」のように、変更したいプロパティ名とその値を指定する。
ビルド構成の指定 (Configurationプロパティ)
Configurationプロパティを指定することで、ビルド構成を指定してビルドすることが出来る。 たとえば、
上記のようなソースを含むプロジェクトファイルをビルドする際、「/property:Configuration=Release」を指定してビルドした場合は次のようにRelease構成でのビルドを行う動作となる。
「/property:Configuration=Debug」と指定すればDebug構成のビルドとなるが、デフォルトではConfigurationの値は "Debug" となっているので明示的に指定しなくてもDebug構成でのビルドが行われる。
コンパイルスイッチの指定 (DefineConstantsプロパティ)
DefineConstantsプロパティを指定することで、コンパイルスイッチを指定してビルドすることが出来る。 たとえば、
上記のようなソースを含むプロジェクトファイルをビルドする際、「/property:DefineConstants="DEBUG;PLATFORM_WIN32"」を指定してビルドした場合は次のような実行結果となる。
出力先の指定 (OutputPathプロパティ)
OutputPathプロパティを指定することで、ファイルの出力先を指定してビルドすることが出来る。
ログ粒度の指定 (/verbosityオプション)
/verbosity(または/v)オプションを使うことでMSBuildが出力するログの詳細度を指定することができる。 指定できる詳細度には次のようなものがある(詳細度の低い順)。
- quiet
- minimal
- normal (指定しなかった場合のデフォルト)
- detailed
- diagnostic
/nologoオプションと併用することでバナー表示も省略できる。
detailedおよびdiagnosticでは非常に詳細なログが出力される。
プロジェクトファイルの記述方法
MSBuildは、Visual Studioなどが生成するプロジェクトファイルだけでなく、MSBuild形式のプロジェクトファイルスキーマに則ったファイルをビルドすることができる。 プロジェクトのビルド以外にも様々なバッチ処理を記述することもできる。
まずはHello, world! (Messageタスク)
Messageタスクを使って「Hello, world!」と表示するだけのビルドファイルを作る。 HelloWorld.msbuild.xmlというファイルを作成し、下記の内容を書き込む。
ファイルが作成できたら、msbuildに作成したファイルを渡して「ビルド」を実行させる。
すると、下記のように表示される。
上記のように「ビルド」の結果が表示される。 ここでの要点は次の通り。
- XMLで書かれた「プロジェクトファイル」をMSBuildに渡すと、その内容に従って「ビルド」が行われる
- 中身がスキーマに則ったXMLであれば、拡張子はxmlでなくてもOK(例えば.vbprojなど)
- プロジェクトファイルはXMLの形式だが、XML宣言(?xml〜?)は無くても特にエラーとはならず正常に動作する
- プロジェクトファイルのルート要素はProjectで、その要素の中で様々な動作を定義する
- Target要素はビルドのターゲットを定義する要素で、ビルドの動作を定義する
- よく使われるターゲットの例として、ビルド済みファイルの削除を行うClean、ソースファイルのコンパイルを行うBuild、ビルドした実行可能ファイルの実行を行うRunなどがある
- この例では、Message要素を使ってメッセージを表示するターゲットにBuildという名前を付けている
- Project要素のDefaultTargets属性でターゲットBuildを指定しているため、デフォルトでこのターゲットがビルドされる
- Message要素を使用すると、任意の文字列を出力させることができる
プロパティ(PropertyGroup)
プロパティ(PropertyGroup)を使った例。 PropertyGroup要素を用いるとプロパティを宣言出来る。 プロパティは一種の定数のようなものであり、PropertyGroupの子要素として任意の名前で定義することができる。 Messageタスク等でプロパティの値を参照する場合は、「$(プロパティ名)」とすることでその値を参照できる。
また、/propertyオプションを指定した場合もプロパティを設定できる。 プロジェクトファイルに同名のプロパティが記述されている場合でも、/propertyオプションで指定された値が優先して使用される。
ここでの要点は次の通り。
- PropertyGroup要素を用いるとプロパティを宣言出来る
- PropertyGroup要素の子要素の名前がそのままプロパティ名となる
- プロパティは任意の名前で定義できる
- /propertyオプションでビルド時にプロパティの値を変更できる
- Messageタスクなどの文字列中でプロパティの値を参照する場合は、「$(プロパティ名)」とする
ターゲット(Target)
ターゲット(Target)を使った例。 ターゲットはいくつかのタスクをひとまとめにして動作を定義するためのもの。 ターゲットを使うことで一連の手続き(タスク)をまとめて一種のメソッドのようなものを作成することができる。
動作させるターゲットを指定せずに実行する場合、MSBuildはデフォルトのターゲット(ProjectのDefaultTargets属性で指定されているターゲット)を実行する。 この例ではDefaultTargetsに"Clean;Build"を指定しているが、これは「Cleanの後にBuildを実行する」という意味になる。 そのため、まずCleanターゲットで定義された動作が先に動き、続いてBuildターゲットで定義された動作が動く。
さらにこのファイルでは、BuildターゲットにてCallTargetタスクを使用して別のターゲットを起動している。 そのため、Buildターゲットを動作させると
- BeforeBuildターゲットが呼び出される
- BeforeBuildターゲット内のMessageタスクが動作して文字列"BeforeBuild"を出力する
- BuildターゲットのMessageタスクが動作して文字列"Build"を出力する
- AfterBuildターゲットが呼び出される
- AfterBuildターゲット内のMessageタスクが動作して文字列"AfterBuild"を出力する
という動きになる。 なお、DefaultTargets属性と同様にCallTargetタスクでも複数のターゲットを指定することができる。
/targetオプションを指定して実行すると、動作させるターゲットを指定することができる。 例えば、次のようにオプション"/t:Clean"を付けて実行するとターゲットCleanだけが動作する。
ここでの要点は下記の通り。
- Target要素では1つ以上のタスクを記述してビルドの動作を定義する
- /targetオプションを使用するとビルドするターゲットを指定できる
- /target:Cleanとした場合は、ターゲットCleanのみが動作する
- /targetを指定しなかった場合は、デフォルトのターゲットをビルドする
- デフォルトのターゲットは、ProjectのDefaultTargetsで定義する
- CallTargetタスクを使用すると、他のターゲットを呼び出すことが出来る
- デフォルトのターゲットやCallTargetタスクに指定するターゲットには、「Clean;Build」のように複数のターゲットを指定することも出来る
依存関係の定義(DependsOnTargets)
TargetのDependsOnTargets属性を使用してターゲット同士の依存関係を定義した例。
これはTargetの例に似ているが、CallTargetタスクの代わりにDependsOnTargets属性を指定して依存関係を定義している。 DependsOnTargets属性に任意のターゲットが指定されている場合は、そのターゲットが先に呼び出される。 その後、Target要素の中で定義されている動作が動く。
この例では、Buildターゲットを動作させようとする場合は、依存関係にあるCleanとBeforeBuildを順に呼び出してから、Buildで定義されている動作を順に実行していく。
ここでの要点は下記の通り。
- DependsOnTargets属性で依存関係にあるターゲットを定義することが出来る
- 依存関係にあるターゲットは、そのターゲットで定義されている動作を実行するよりも先に呼び出される
ターゲット・タスクを使った簡単なサンプル(Target, RemoveDir, MakeDir, Touch, Exec)
ここまでの例で使用してきたMessageタスクはメッセージを出力するものだが、これ以外にも様々なタスクが用意されている。 RemoveDir, MakeDir, Touch, Execなどのタスクを使った例。
まずはターゲットを指定しないでデフォルトであるBuildターゲットを実行させた場合。
続いてターゲットを指定してCleanターゲットを実行させた場合。
この例では、Buildターゲットを動作させた場合は、出力用のディレクトリbinを作成し、bin\Test.txtにターゲットを動作させた時間を記録している。 またCleanターゲットを指定した場合は、出力用のディレクトリbinを削除するようになっている。
ここでの要点は下記の通り。
- MakeDirタスクを使用すると、ディレクトリを作成すことが出来る
- MakeDirタスクにて作成するディレクトリは、Directories属性で指定する
- MakeDirタスクにてCondition属性を指定すると、Conditionで指定している条件が真と評価される場合にのみディレクトリが作成される
- RemoveDirタスクを使用すると、ディレクトリを削除することが出来る
- RemoveDirタスクでは、ディレクトリ内にファイルがあってもディレクトリを削除できる
- Touchタスクを使用すると、空のファイルを作成することが出来る
- TouchタスクにてAlwaysCreate属性にTrueを指定すると、ファイルが存在していない場合はファイルが作成される
- Execタスクを使用すると、DOSコマンドを実行できる(この例では、現在の時刻をbin\Test.txtファイルに書き出している)
アイテム(ItemGroup)
アイテム(ItemGroup)を使った例。
ItemGroupはPropertyGroupと似ているが、こちらは主にファイルのリストなどの「アイテム」を定義するために用いる。 タスクのパラメータとして引き渡す場合に用いる他、Copyタスクで実際にコピーされたファイルの一覧を取得するなど、タスクの出力パラメータとしてもアイテムを得ることができる。
ここでの要点は下記の通り。
- ItemGroup要素を用いるとプロパティを宣言出来る
- ItemGroup要素の子要素の名前がそのままアイテム名となる
- アイテムは任意の名前で定義できる
- アイテムの値を参照する場合は、「@(アイテム名)」とする
- Include属性でワイルドカードを指定した場合、カレントディレクトリにあるファイルのうち、ワイルドカードにマッチするファイルのみが指定される
- Exclude属性を指定すると、ワイルドカードにマッチするファイルは除外される
- Messageタスクで出力する際の区切り文字を変える場合は、アイテム名の後ろに使いたい区切り文字を指定する
タスク出力の取得 (Output)
Output要素を使った例。
Output要素を用いると、タスクの出力をアイテムもしくはプロパティとして取得できる。
ここでの要点は下記の通り。
- タスクの要素内でOutput要素を記述すると、タスクの出力を取得できる
- Output要素のTaskParameter属性で出力する値を指定する
- Output要素のItemName属性で出力先のアイテム名を指定する
- ItemName属性の代わりにPropertyName属性を使うことでプロパティ名を指定することもできる
具体例
Cscタスクを使ってC#ファイルをコンパイルする
Cscタスクを用いると、cscコンパイラを使ってC#ソースファイルをコンパイルすることが出来る。 ここではいくつかのソースファイル、リソースファイルからWindows実行可能ファイルを生成するための例を示す。
実行結果は次の通り。
ビルドに成功すると、コンパイルしたバイナリが起動し、ウィンドウが現れる。 ウィンドウを閉じてバイナリを終了すると、MSBuildの完了メッセージが出力される。