VC PlusPlus:MSBuild

提供:yonewiki
2024年2月8日 (木) 13:10時点におけるYo-net (トーク | 投稿記録)による版 (→‎Targetの細かい部分)

VC Cpp記事に戻る。

概要

 MSBuildは*.slnや*.vcxprojファイル(プロジェクトファイル)を実行するときに使われるコマンドのようなものです。言語によってはもう少しいろいろな拡張子が処理されます。ここでは、*.slnや*.vcxprojと*.targetファイルに絞って説明を進めます。つまりC++以外の言語の事は知らないというスタンスです。


 この記事では、MSBuildコマンドの実行の基礎Targetの基礎に触れます。その他の技術については、別の子記事として記述します。


 *.vcxprojファイルの中身を処理していくものですが、*.slnはMSBuild形式では書かれていません。MSBuildコマンドが*.slnをMSBuildフォーマットに変換しているので、実行ができるようになっています。


 VisualStudioのメニューから起動するコマンドプロンプトやパワーシェルでMSBuildというコマンドが使えるようにパス設定がなされます。起動の仕方はVisualStudioのメニュー[ツール]-[コマンドライン]-[開発者コマンドライン]or[開発者用PowerShell]から起動できます。コマンドプロンプトの方がいろいろと安心なのですが、ここでは便利なパワーシェルの方を使います。

 

MSBuildの基礎

 例えば、プロジェクトファイルをビルドするには以下のようなコマンドを使います。


MSBuild (プロジェクトファイル名).vcxproj /t:build /p:Configuration=Debug /p:Platform=x64


 ソリューションファイルをビルドすることもできる。


MSBuild (プロジェクトファイル名).sln /t:build


 のようにする。このようにConfigurationやPlatformの設定を省略した場合は最後に保存したときに指定されていたものを覚えているので、その設定でビルド処理がされます。/tはターゲットというものを指定しています。

 

Targetの基本

ターゲットには、ものすごく細かいステップの一部であるものもあれば、buildのように一連のビルドプロセス全体を差すようなものまであります。ここでは一般的によく使うターゲットを列挙します。見やすさのために大文字小文字を使い分けている記述をしますが、実際は大文字小文字の区別はありません。


  • Build(ビルド)
  • Rebuild(BeforeRebuild;Clean;Build;AfterRebuildと同じ)


 というものがあります。


 複数のビルドターゲット名を実行するときは ; で接続して記述します。では、MSBuildが読み取るvcxprojファイルの中身を少しづつ理解していきましょう。

 

Targetの細かい部分

 ちなみに、VisualStudioが規定で呼び出そうとする内部的なTargetには以下のようなものがあります。


_CheckForInvalidConfigurationAndPlatform
SetTelemetryEnvironmentVariables
_PrepareForBuild
_PrepareForReferenceResolution
BeforeResolveReferences
_SplitProjectReferencesByFileExistence
_AddOutputPathToGlobalPropertiesToRemove
_GetProjectReferenceTargetFrameworkProperties
PrepareProjectReferences
ResolveProjectReferences
GetFrameworkPaths
GetReferenceAssemblyPaths
AddExternalIncludDirectoriesToPaths
SetBuildDefaultEnvironmentVariables
SetUserMacroEnvironmentVariables
GetResolvedWinMD
_CheckWindowsSDKInstalled
FixCAExcludePath
SetCABuildNativeEnvironmentVariables
PrepareForBuild
ResolveSDKReferences
ExpandSDKReferences
ResolveAssemblyReferences
AfterResolveReferences
ResolveReferences
InitializeBuildStatus
BuildGenerateSourcesTraverse
BeforeBuildGenerateSources
PreBuildEvent
_SelectedFiles
SelectCustomBuild
ComputeCustomBuildOutput
CustomBuild
CopyFileToFolders
_Xsd
MakeDirsForMidl
ComputeMIDLGeneratedCompileInputs
AfterMidl
_Midl
AfterBuildGenerateSources
AfterBuildGenerateSourcesEvent
_BuildGenerateSourcesAction
BuildGenerateSources
BuildCompileTraverse
BeforeClCompile
ComputeCLInputPDBName
FindReferenceAssembliesForReferences
GetReferencedVCProjectsInfo
ComputeReferenceCLInput
WarnCompileDuplicatedFilename
ComputeStdModulesCompileInputs
FixupCLCompileOptions
MakeDirsForCl
SetModuleDependencies
SelectClCompile
ClCompile
AfterClCompile
_ClCompile
BeforeResourceCompile
MakeDirsForResourceCompile
■AfterResourceCompile
_ResourceCompile
AfterBuildCompileEvent
_BuildCompileAction
BuildCompile
BuildLinkTraverse
ComputeLegacyManifestEmbedding
BeforeLink
ComputeRCOutputs
ComputeRCGeneratedLinkInputs
ComputeManifestGeneratedLinkerInputs
ComputeCLOutputs
ComputeCLGeneratedLinkInputs
ComputeLinkInputsFromProject
ComputeManifestInputsTargets
AssignTargetPaths
SplitResourcesByCulture
CreateCustomManifestResourceNames
PrepareResourceNames
MakeDirsForLink
DoLinkOutputFilesMatch
PreLinkEvent
ComputeLinkSwitches
Link
AfterLink
MakeDirsForMuiLink
_Link
_ALink
_Manifest
ResolvedXDCMake
ComputeCLCompileGeneratedXDCFiles
MakeDirsForXdcMake
_XdcMake
ComputeCLCompileGeneratedSbrFiles
MakeDirsForBscMake
_BscMake
RunMergeNativeCodeAnalysis
RunNativeCodeAnalysis
BuiltProjectOutputGroup
SatelliteDllsProjectOutputGroup
MakeDirsForFxc
ContentFilesProjectOutputGroup
CreateRecipeFile
_GenerateSatelliteAssemblyInputs
CreateSatelliteAssemblies
_Appverifier
_Deploy
_PopulateCommonStateForGetCopyToOutputDirectoryItems
GetCopyToOutputDirectoryXamlAppDefs
_GetCopyToOutputDirectoryItemsFromTransitiveProjectReferences
_GetCopyToOutputDirectoryItemsFromThisProject
GetCopyToOutputDirectoryItems
_CopySourceItemsToOutputDirectory
_CheckForCompileOutputs
CopyFilesToOutputDirectory
PrepareForRun
PostBuildEvent
_BuildLinkAction
BuildLink
AfterBuild
_CleanGetCurrentAndPriorFileWrites
IncrementalClean
TlogCleanup
FinalizeBuildStatus


 いっぱいありすぎる。けどこれらの細かいターゲットを実行しても、基本的にはなにも起こらないか、ごく一部が処理されるだけのことになります。Visual Studioはこれだけおおくのビルドステップを実行しようとするんですね。他にも特定のプロパティ値$(xxxx)という表記をする変数にビルドターゲット名を設定すると更に細かいターゲットも設定できます。


 もともと何も実行しないステップと、何かしらの処理をするターゲットがありますが、ユーザが再定義していいターゲットは、何も実行しないターゲットが使っていいターゲットと考えるべきでしょう。何もしない設定かどうかはプロジェクトファイルの設定にも左右されるので、ここで簡単に切り分けすることはできませんね。

 

TargetのImport部分

 Visual Studioでコンソールアプリケーションのプロジェクトを新規作成したときにできるvcxprojファイルには以下のようなターゲットが設定されているのが見受けられます。


  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />


 とここだけですね。


 この中身っていうのは、VisualStudioのバージョンによってパスは異なりますが、2022版ならC:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VC\v170\Microsoft.Cpp.targetsのことです。その中にTargetの設定が以下のように設定されています。


<!--省略-->
    <Target Name="InstallBuildTools"  />
<!--省略-->


 このような部分があり、これこそがTargetの定義になります。この場合 InstallBuildTools という名前のTargetが設定されたことになります。

 

Targetの自己定義

 このような<Target Name="">の宣言を開発者が宣言することもできます。例えば、何も実行する予定の無いTargetを自分の開発しているプロジェクトの*.vcxprojファイルに以下のように定義すると、ビルド処理の流れに自分で考えた処理を挟み込むことができます。


<!--省略-->
  <Target Name="AfterResourceCompile">
  </Target>
<!--省略-->

 

TargetによるMessage HelloWorldの出力

 何もしない部分を追加しても何も起こらないので、何かビルド中に文字列を出力するように設定するHelloWorld!的なものを記述してみましょう。


<!--省略-->
  <Target Name="AfterResourceCompile">
    <Message Text="MSbBuild Hello,World!" Importance="High" />
  </Target>
<!--省略-->


 上記のようにMessageタグでテキストを出力できます。Importance="High"という要素を指定しておくとVisualStudioのビルド出力の対象にもなります。Importance="High"を省くとMSbuildコマンドでビルドしたときだけ表示される灰色のメッセージになります。Importance="High"が指定されているとMSBuildでも強調された白色文字になります。パワーシェルで操作したときの文字色の違いが発生します。

 

TargetからDependsOnTargetsで更に子Targetを設定した方法によるMessage HelloWorldの出力

 更に、違うTargetsを呼び出すことができます。例えばTargetタグに DependsOnTargets という要素を新たに追加し、その値をMessageTextという内容にして、Targetを呼び出すなら以下のようにします。


<!--省略-->
  <Target Name="AfterResourceCompile" DependsOnTargets="MessageText">
    <Message Text="MSbBuild Hello,World!" Importance="High" />
  </Target>
  <Target Name="MessageText">
    <Message Text="MessageText Target Hello,World!" Importance="High" />
  </Target>
<!--省略-->


 これでMessageTextターゲットが先に呼ばれ、その後に自分で定義したAfterResourceCompileが呼び出されることになる。MessageTextターゲット以外のターゲットを続けて呼び出したい場合はDependsOnTargets="MessageText;MessageText1;MessageText2"のようにセミコロン区切りで複数を設定できます。


>MSBuild (プロジェクトファイル名).vcxproj /t:build /p:Configuration=Debug /p:Platform=x64


 のように実行すると


>MSBuild (プロジェクトファイル名).vcxproj /t:build /p:Configuration=Debug /p:Platform=x64
(省略)
MessageText:
MessageText Target Hello,World!
AfterResourceCompile:
MSbBuild Hello,World!
(省略)


 のように出力されるようになります。

 

関連記事

 

VC Cpp記事に戻る。