Visual Studio(MSBuild)でVC++をビルドするときの箇条書きメモ. MyProjectというウインドウを持つMFCプロジェクトのx64ビルドを想定.
実行環境
項目 | 説明 |
---|---|
OS | Windows11 |
Visual Studio | 2017 |
ビルドターゲット | x64 |
関連するパス
パス | 主なファイル | 説明 |
---|---|---|
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\Hostx64\x64 | cl.exe, link.exe, nmake.exe, dumpbin.exe | バイナリツール |
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\include | iostream, algorithm | VC++用ヘッダー |
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\lib\x64 | msvcrt.lib, legacy_stdio_definitions.lib | VC++用ライブラリ |
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\atlmfc\include | afx.h, about_.rc | MFCのヘッダー, デフォルトのリソース |
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\atlmfc\lib\x64 | mfc140.lib | MFCのインポートファイル |
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools | MSBuild.exe, VsDevCmd.bat | MSBuild及びパスを指定するためのbat |
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE | devenv.exe | Visual Studio 本体 |
C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64 | rc.exe | Windows開発用のツール |
C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0 | winsock.h, WinBase.h | C言語によるWinアプリケーション用ヘッダーファイル |
C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\um\x64 | kernel32.LIB, d3d12.lib | C言語によるWinアプリケーション用インポートファイル |
C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\ucrt\x64 | libucrt.lib, ucrt.lib | C言語によるWinアプリケーション用インポートファイル |
C:\Windows\System32 | kernel32.dll, msvcp140.dll, mfc140.dll, D3D12.dll, curl.exe | 64bit用ランタイム, 基本コマンド |
ランタイムとSDK
ざっくり言うと、ランタイムはdllで実行時に必要. SDKはヘッダー、インポートライブラリあるいはスタティックライブラリでビルド時に必要. いかなる時も必要なランタイムと、プロジェクトの種類によっては必要なランタイムがある. ランタイムが欲しい場合は再配布可能パッケージを取得すればよい.
主要なランタイム | 説明 |
---|---|
kernel32.dll | よくみるけどなにしてるんだろう |
ucrtbase.dll | よくみるけどなにしてるんだろう |
vcruntime140.dll | Visual Studio2015以降のVC++ビルドツールで作ったアプリの実行に必要 |
mfc140.dll | Visual Studio2015以降のVC++ビルドツールで作った動的MFCアプリの実行に必要 |
ランタイムをざっくり分けると
とがある.
ファイルの配置規則
- ヘッダーファイルはターゲットごとに分けずに配置
- インポートファイルはターゲットごとにフォルダを分けて配置
- インポートファイルとdllファイルは一対一対応とは限らない
- VC++のビルドツールはバージョンごとに分かれているが、ビルドツールを追加でインストールしない限りは1つしかない
- WinSDKのツールやライブラリはバージョンごとに分かれている. 一部フォルダはWinSDKインストール前から存在する
ファイルの命名規則
- dが拡張子の前についているファイルはデバッグビルド用
- uが拡張子の前についているファイルはUnicode対応
- LIB〇〇.LIBというファイルはインポートライブラリではなくスタティックライブラリ
- C:\Windows\System32は64bit用(紛らわしい!). C:\Windows\SysWOW64は32bit用(紛らわしい!).
- ランタイムは32bitも64bitも同名にしている. kernel32.dllにも64bit用のものと32bit用のものがある.
ビルドの流れ
CL.exeによるコンパイル → rc.exeによるリソースコンパイル → link.exeによるリンク
詳細
- ビルドターゲットに対応するコマンドプロンプトを開く
- msbuild.batが呼び出され、MSBuild.exeへのパスが追加される.
- winsdk.batが呼び出され「WindowsSDKVersion」が自動的に指定される(おそらくPCに入っているものの中で最新のもの)
- vcvars.batによりVCビルドツールのバージョン、WinSDKのバージョン、ターゲットに対応したインクルードフォルダ、ライブラリフォルダへのパスを環境変数に追加.
- 1で開いたコマンドプロンプトで MSBuild <MyProjectへのパス>\MyProject.vcxproj と叩く.
- MyProject.vcxproj内のVCビルドツールのバージョンとWinSDKのバージョンで環境変数を上書きしたうえでビルド開始.
IDE上からビルドするとMSBuildのオプションを指定したうえでビルドできる(後述)
インポートライブラリ
vcvars.batのおかげでもとからいくつかのディレクトリへのパスが通っている. 例えば、IDE上で以下のように書いてもリンクエラーにならないのは「C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\atlmfc\lib\x64」や「C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\um\x64」などへのパスがvcvars.batのおかげで通っているから.
/******************************************/ /* afx.hからの抜粋 */ /*****************************************/ #ifndef _AFXDLL #ifdef _AFX_NO_MFC_CONTROLS_IN_DIALOGS #ifdef _DEBUG #pragma comment(lib, "afxnmcdd.lib") #else #pragma comment(lib, "afxnmcd.lib") #endif #pragma comment(linker, "/include:__afxNoMFCControlSupportInDialogs") #pragma comment(linker, "/include:__afxNoMFCControlContainerInDialogs") #endif #ifndef _UNICODE #ifdef _DEBUG #pragma comment(lib, "nafxcwd.lib") #else #pragma comment(lib, "nafxcw.lib") #endif #else #ifdef _DEBUG #pragma comment(lib, "uafxcwd.lib") #else #pragma comment(lib, "uafxcw.lib") #endif #endif #else #ifndef _UNICODE #ifdef _DEBUG #pragma comment(lib, "mfc" _MFC_FILENAME_VER "d.lib") #pragma comment(lib, "mfcs" _MFC_FILENAME_VER "d.lib") #else #pragma comment(lib, "mfc" _MFC_FILENAME_VER ".lib") #pragma comment(lib, "mfcs" _MFC_FILENAME_VER ".lib") #endif #else #ifdef _DEBUG #pragma comment(lib, "mfc" _MFC_FILENAME_VER "ud.lib") #pragma comment(lib, "mfcs" _MFC_FILENAME_VER "ud.lib") #else #pragma comment(lib, "mfc" _MFC_FILENAME_VER "u.lib") #pragma comment(lib, "mfcs" _MFC_FILENAME_VER "u.lib") #endif #endif #endif #ifdef _DLL #if defined(_DEBUG) #pragma comment(lib, "msvcrtd.lib") #else #pragma comment(lib, "msvcrt.lib") #endif #else #if defined(_DEBUG) #pragma comment(lib, "libcmtd.lib") #else #pragma comment(lib, "libcmt.lib") #endif #endif #pragma comment(lib, "kernel32.lib") #pragma comment(lib, "user32.lib") #pragma comment(lib, "gdi32.lib") #pragma comment(lib, "msimg32.lib") #pragma comment(lib, "comdlg32.lib") #pragma comment(lib, "winspool.lib") #pragma comment(lib, "advapi32.lib") #pragma comment(lib, "shell32.lib") #pragma comment(lib, "comctl32.lib") #pragma comment(lib, "shlwapi.lib") #pragma comment(lib, "uxtheme.lib") #pragma comment(lib, "windowscodecs.lib")
追加のディレクトリ
vcvars.batで追加されたディレクトリ以外へのパスを追加する場合は、プロジェクトプロパティから「追加のインクルードディレクトリ」と「追加のライブラリディレクトリ」の項目にディレクトリへのパスを指定する. ライブラリに関してはプロジェクトプロパティの「追加の依存ファイル」に指定してもよいし、#pragma comment(lib, "libName") をソースファイル内に記述すればよい. おそらく、プロプロセスかどこかで依存ファイルを自動的に作成してくれる. vcvars.batはあくまでパスを指定するだけなので、ヘッダ内で #pragma comment(lib, "libName")を記述することでデフォルトの依存関係を指定している.
ログ
MyProject.tlogフォルダにCL、rc、linkのログが出力される. 特にCLとlinkは参照したファイルがすべてフルパスで出力されているので必見.
MSBuildのオプション
MSBuildをコマンドラインからオプションなしで実行すると、x64 Debug ビルドになってしまう. /property (/p for short)オプションを指定するとコマンドラインからターゲットを指定できる.
MSBuild MyProject.vcxproj /p:Configutation=Release # x64 Release Build MSBuild MyProject.vcxproj /p:Configutation=Release /p:Platform=Win32 # x86 Release Build
NuGetとの相性
.NET Frameworkの場合NuGetからインストールしたdllへのパスや依存関係が自動的にプロジェクトファイルに追加される. VC++の場合はすべて手動で設定する必要がある.