見切り発車

とりあえずかきとめたい

MSBuild でvcxproj に独自の処理を追加する

vcxproj からソースファイル名やインクルードパス、プリプロセッサマクロ定義などを取り出してlibclang に渡して処理するという目的のため試行錯誤しているのですが、 断片的な情報でハックするようなやり方ではなかなか思ったような結果にならないため改めてMSBuild のドキュメントに記載されている公式に提供されている手段で実現する方法を調べました。

今回は特にvcxproj のビルドプロセスに独自の処理を追加する方法と、コンパイラに渡されるパラメータを利用する方法について記述します。

MSBuild のドキュメント

https://learn.microsoft.com/ja-jp/visualstudio/msbuild/msbuild?view=vs-2022

MSBuild についての情報はこちらに記載されています。 今回の内容はこちらに記載されているものとGitHub で提供されているサンプルを参考にしました。

基本的にはMSBuild のドキュメントをしっかり読み込むことができればほぼすべての情報は得られると思います。

独自ターゲットをビルドプロセスに組み込む

vcxproj などのMSBuild のプロジェクトファイルでは各種の処理を行うタスク要素をターゲット要素の子要素としてまとめています。 そしてMSBuild の実行時に起点となるターゲットを指定すると依存関係のあるターゲットに含まれるタスクが実行されます。

独自の処理を追加したい場合、C# で独自のタスククラスを含むクラスライブラリを作成しこれを呼び出す独自ターゲットを定義して既定のターゲットとの依存関係を設定します。

例えば、vcxproj でコンパイルを行うターゲットはClCompile という名前ですが、 コンパイル処理の前に独自の処理を実行したい場合、独自のターゲットを作成してBeforeTargets 属性にClCompile を指定します。

<Target Name="MyPreClCompile" BeforeTargets="Clcompile">
  <Message Text="MyPreClCompile" />
</Target>

コンパイラに渡される情報を利用する

MSBuild には項目、メタデータ、プロパティといったパラメータがあります。

項目はItemGroup で定義される主にファイルを指すパラメータです。 @(ClCompile) のように@ を付けて参照します。

メタデータはItemGroup やItemDefinitionGroup で項目の子要素として定義されます。 これには%(ClCompile.PreprocessorDefinitions) のように% を付けて項目の子要素として参照します。

プロパティはPropertyGroup で定義されるパラメータです。 $(IncludePath) のように$ を付けて参照します。

ClCompile でどのようなメタデータが利用できるかは C:\Program Files\Microsoft Visual Studio\2022\Community\Msbuild\Microsoft\VC\v170 などのディレクトリから探すこともできますが、 vcxproj をMSBuild の/pp オプションでプリプロセスして出力したファイルから読み取ることもできます。

独自ターゲットでMessage タスクを利用して各パラメータの値を確認することができます。

<Target Name="MyPreClCompile" BeforeTargets="Clcompile">
  <Message Text="ClCompile=@(ClCompile)" />
  <Message Text="IncludePath=$(IncludePath)" />
  <Message Text="PreprocessorDefinitions=%(ClCompile.PreprocessorDefinitions)" />
</Target>

パラメータの種類に合わせた参照するための記号を使用するよう注意が必要です。

独自ターゲットの挿入位置

プロパティやメタデータは同じ要素がvcxproj 内の複数個所にある場合には出現順序によって最終的な結果が決まるため、 ターゲットでこれらを定義している場合には順序に気を付ける必要がありますが、 今回のように参照するだけであれば他のターゲットとの前後関係はあまり気にしなくてよさそうです。 vcxproj に直接挿入する以外に、vcxproj と同じ階層に置いたDirectory.Build.targets ファイルに記述する方法もあり、 こちらのほうが独立して取り扱いがしやすいかもしれません。

まとめ

vcxproj に独自処理を追加してvcxproj の情報を利用する場合には独自ターゲットを追加して既定ターゲットとの依存関係を指定し、 種類ごとに決められた記号を使用してパラメータの値を参照します。

これらはMSBuild のドキュメントに書いてあり、時間はかかりますが理解しておくと目的に合わせたアレンジがしやすくなりそうです。