VC PlusPlus:MSBuild
VC Cpp記事に戻る。
概要
MSBuildは*.slnや*.vcxprojファイル(プロジェクトファイル)を実行するときに使われるコマンドのようなものです。言語によってはもう少しいろいろな拡張子が処理されます。ここでは、*.slnや*.vcxprojと*.targetファイルに絞って説明を進めます。つまりC++以外の言語の事は知らないというスタンスです。
*.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が読み取るvcxファイルの中身を少しづつ理解していきましょう。
Targetの細かい部分
ちなみに、内部的な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>
<!--省略-->
そして、何もしない部分を追加しても何も起こらないので、何かビルド中に文字列を出力するように設定するHelloWorld!的なものを記述してみましょう。
<!--省略-->
<Target Name="AfterResourceCompile">
<Message Text="MSbBuild Hello,World!" />
</Target>
<!--省略-->
TargetによるMessage HelloWorldの出力
更に、違うTargetsを呼び出すことができます。例えばMessageTextというTargetを呼び出すなら以下のようにします。
<!--省略-->
<Target Name="AfterResourceCompile" DependsOnTargets="MessageText">
<Message Text="MSbBuild Hello,World!" />
</Target>
<Target Name="MessageText">
<Message Text="MessageText Target Hello,World!" />
</Target>
<!--省略-->
これでMessageTextターゲットが先に呼ばれ、その後に自分で定義したAfterResourceCompileが呼び出されることになる。
>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記事に戻る。