MSB8020 でビルドが止まったとき、直し方は古いツールセットをビルド機に入れるか、プロジェクトを再ターゲットするかです。MFCアプリで後者を選ぶと、exe が要求するMFCランタイムが mfc100.dll や mfc120.dll から14系へ変わり、配布先に入れる再頒布可能パッケージも入れ替わります。Visual Studio 2026 で v120 と v145 の両方をビルドし、動いた exe に実際に載ったランタイムを Debug 構成で確認します。
MSB8020 が指しているのはビルド機のツールセット
Visual Studio 2026 のビルド機で、PlatformToolset を v120 にしたMFCダイアログをビルドすると、こう出ます。
C:\Program Files\Microsoft Visual Studio\18\Professional\MSBuild\Microsoft\VC\v180\Microsoft.CppBuild.targets(473,5):
error MSB8020: Visual Studio 2013 (プラットフォーム ツールセット = 'v120') のビルド ツールが見つかりません。
v120 ビルド ツールを使用してビルドするには、Visual Studio 2013 ビルド ツールをインストールしてください。
または、[プロジェクト] メニューを選択するかソリューションを右クリックし [ソリューションの再ターゲット] を選択して、
現在の Visual Studio Tools にアップグレードすることもできます。
行番号 (473,5) が指しているのは Microsoft.CppBuild.targets の中で、自分のソースではありません。コンパイラーはまだ1行も読んでいません。#include を直しても、警告レベルを下げても、この行は消えません。
対処は、メッセージ自体が挙げています。「v120 ビルド ツールをインストールしてください」と「[ソリューションの再ターゲット] を選択して…アップグレード」の2つです。
MicrosoftのMSB8020 のリファレンスは、このエラーが出る条件を「ビルドが要求するプラットフォーム ツールセットがインストールされていないか、必要なフォルダーが存在しないとき」と書いています。そして $(PlatformToolset)(たとえば v143)は Visual Studio のインストール内の特定のフォルダーを指していて、そのフォルダーにそのツールセット用の MSBuild の .props / .targets がある、とも書いてあります。MSB8020 が伝えているのは、そのフォルダーが無いということだけです。
似た番号で MSB8041 がありますが、あちらはMFCのライブラリ自体が入っていない話で、原因も対処も別です。MFCコンポーネントの追加手順はMSB8041 の記事にあります。
世代は .vcxproj の PlatformToolset に書いてある
要求している世代は、テキストエディターで .vcxproj を開けば分かります。構成ごとに1行あります。
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseOfMfc>Dynamic</UseOfMfc>
<PlatformToolset>v120</PlatformToolset> <!-- ここ -->
</PropertyGroup>
番号とVisual Studio の対応は次のとおりです。v140 から v143 まではC++ バイナリ互換性のドキュメントに明記されている対応です。同じドキュメントは、バイナリ互換の対象として v140・v141・v142・v143 と並べて v145 を挙げ、Visual Studio 2026 を対象に含めています。v145 でビルドして動くことは、今回のビルド機(Visual Studio 2026)で実測しました。
| PlatformToolset | Visual Studio | メジャー番号 |
|---|---|---|
v100 | 2010 | 10 |
v120 | 2013 | 12 |
v140 | 2015 | 14 |
v141 | 2017 | 14 |
v142 | 2019 | 14 |
v143 | 2022 | 14 |
v145 | 2026(実測) | 14 |
見るのは右の列です。Visual Studio 2015 を境に、ビルドツールのメジャー番号は 14 で止まっています。公式ドキュメントは、2013 以前のビルドツールはメジャーバージョンをまたいだバイナリ互換を保証しない(オブジェクトファイル・静的ライブラリ・DLL・exe をリンクできない)と書き、2015 以降は互換だと書いています。v120 と v141 の間には壁がありますが、v140 と v145 の間には壁がありません。
動かしているのは、この1行だけです。同じ内容のMFCダイアログを2つ用意し、ソース10ファイル(App.cpp、HostDlg.cpp、pch.cpp ほか)が sha256 で完全に一致していることを確認したうえで、PlatformToolset を v120 と v145 にしました。コンパイルとリンクの意味を変えている設定の違いはこの1行だけです。残りの違いはプロジェクトファイル名と RootNamespace、.rc のファイル名、そして出力先(OutDir / IntDir)で、いずれも2つを別々にビルドしてぶつからないようにするための都合です。
再ターゲットで変わるのは配布先の再頒布パッケージ
v145 側は当然ビルドが通ります。確認したいのは、通ったあとにその exe が何を要求するようになったかです。そこで、ビルド時のツールセット名をプリプロセッサ定義で受け取り、実行中の自プロセスに読み込まれているモジュールを CreateToolhelp32Snapshot で列挙して、MFC / CRT のランタイムだけをフルパスで表示させました。ファイル名を決め打ちせず、実際に載ったものを見るためです。
// .vcxproj 側: /D SAMPLE_TOOLSET=v145 の形でトークンとして渡す
<PreprocessorDefinitions>SAMPLE_TOOLSET=$(PlatformToolset);%(PreprocessorDefinitions)</PreprocessorDefinitions>
// コード側: 文字列化してから表示する
#define SAMPLE_STRINGIZE2(x) _T(#x)
#define SAMPLE_STRINGIZE(x) SAMPLE_STRINGIZE2(x)
LPCTSTR const kToolset = SAMPLE_STRINGIZE(SAMPLE_TOOLSET);
Windows 11 / Visual Studio 2026 / Debug・x64 での実行結果がこれです。
PlatformToolset : v145
_MSC_VER : 1951
_MSC_FULL_VER : 195136248
_MFC_VER : 0x0E00
MFCの使用 : 共有DLL (_AFXDLL が定義されている)
構成 : Debug / x64
このプロセスへ読み込まれている MFC / CRT ランタイム
msvcp_win.dll C:\WINDOWS\System32\msvcp_win.dll
ucrtbase.dll C:\WINDOWS\System32\ucrtbase.dll
VCRUNTIME140_1D.dll C:\WINDOWS\SYSTEM32\VCRUNTIME140_1D.dll
mfc140ud.dll C:\WINDOWS\SYSTEM32\mfc140ud.dll
VCRUNTIME140D.dll C:\WINDOWS\SYSTEM32\VCRUNTIME140D.dll
ucrtbased.dll C:\WINDOWS\SYSTEM32\ucrtbased.dll

ツールセットは v145 ですが、読み込まれたMFCランタイムは mfc140 でした。_MFC_VER も 0x0E00、つまり 14.00 です。前の節の表の右列が、実行時のファイル名にそのまま出ています。
これは配布側の話に直結します。公式ドキュメントは、再頒布可能パッケージのメジャーバージョン番号を Visual Studio 2015・2017・2019・2022・2026 で同じに保っている、と明言しています。再ターゲット先が v140 から v145 のどれであっても、配布先に入れるものは14系の再頒布可能パッケージ1つです。v120 から上げるということは、配布手順から VC++ 2013 の再頒布可能パッケージ(mfc120.dll を提供していたもの)が消えて、14系が入る、という変更になります。DLL名から必要なパッケージを特定する手順はmfc140.dll / mfc120.dll / mfc100.dll が見つからないにまとめてあります。
実測しているのは Debug 構成なので、載っているのは末尾に D の付くデバッグ版で、これは再頒布できません。Release 構成のファイル名は測っていないので断定しませんが、_MFC_VER が 0x0E00 である以上、世代が 14 であることは変わりません。
一覧のうち ucrtbase.dll は Universal CRT で、公式ドキュメントは UCRT を「Microsoft Windows のオペレーティング システム コンポーネント」と明記しています(Windows 10 以降と Windows Server 2016 以降では OS に含まれます)。この行は、再ターゲットの判断で配布物として数えるものではありません。再頒布可能パッケージは UCRT が入っていない環境に初期バージョンを入れますが、世代の話に効いてくるのは mfc* と VCRUNTIME* / MSVCP140* の行です。なお msvcp_win.dll は名前が紛らわしいですが、再頒布可能パッケージが入れる msvcp140.dll とは別のファイルです。
配布まわりでは、次の決まりが事故につながります。いずれも公式ドキュメントに明記されています。
- メジャー番号が同じなので、再頒布可能パッケージは同時に1つしか入りません。新しい版が古い版を上書きします。
- 逆向きは入りません。新しい版が入っている環境へ古い版を入れようとすると、インストーラーが
0x80070666 - Another version of this product is already installed.で失敗します。これは仕様です。自社インストーラーがこのエラーで止まらないようにしておく必要があります。 - 複数のビルドツールで作ったバイナリを混ぜる場合、再頒布可能パッケージは使ったうちで最も新しいビルドツール以上である必要があります。
そしてレガシー保守で見落としやすいのが Windows XP です。公式は、最新の再頒布可能パッケージには Windows XP 向けのランタイムサポートがもう無く、XP をサポートする最後の再頒布可能パッケージはバージョン 16.7(ファイルバージョン 14.27.29114.0)だと書いています。それより新しい版で配布・更新すると XP 上のアプリは動きません。配布先に XP が残っているなら、再ターゲットは配布先のOSごと考え直す話になります。
もう1つ、混在させるときの例外があります。/GL(全プログラム最適化)でコンパイルした、あるいは /LTCG でリンクしたオブジェクトファイルと静的ライブラリは、マイナーバージョン違いでも互換がありません。コンパイルと最終リンクで完全に同じビルドツールを使う必要があり、違反すると C1047 が出ます。第三者から /GL 付きの .lib を受け取っている場合、ここが再ターゲットの制約になります。
古いツールセットを足せるかは個別コンポーネント次第
2択のもう片方、ツールセットを足すほうです。MSB8020 は「フォルダーが無い」と言っているだけなので、まず確認するのはそのフォルダーです。Windowsデスクトップのプロジェクトの場合、ツールセットの Toolset.props / Toolset.targets が置かれるのは $(VCTargetsPath)\Platforms\<アーキテクチャ>\PlatformToolsets\<番号>\ です($(VCTargetsPath) は Visual Studio のインストール先の MSBuild\Microsoft\VC\<VCのバージョン>\)。番号のフォルダーは MSBuild\Microsoft\VC\ の直下ではなく、アーキテクチャごとの PlatformToolsets の下にある点に注意してください。この PlatformToolsets 配下のフォルダー名が、そのままプロジェクトのプロパティの [プラットフォーム ツールセット] の選択肢になります。今回のビルド機では、エラーの発生元のパスから VS2026 側の v180 があることは分かりますが、その配下に v120 が無かったので MSB8020 になりました。
足せるかどうかは、Visual Studio インストーラーの「個別のコンポーネント」に、その世代が並んでいるかで決まります。MSB8020 のリファレンスは、ネイティブのツールはアーキテクチャごとに入れる必要があること(たとえば Windows デスクトップ ARM64 なら MSVC ARM64 のコンポーネントを個別のコンポーネントから入れる)、UWP プロジェクトでは UWP 用の MSVC が別コンポーネントであること、そして不足しているツールセットが Visual Studio の拡張機能として提供されている場合があることを挙げています。「どの世代でも個別コンポーネントで足せる」とは書かれていません。手元の Visual Studio インストーラーを開いて、その番号があるかを確かめるのが唯一確実な方法です。
実務では再ターゲットを既定にして、古いツールセットを足すほうは、再ターゲットすると壊れるものが特定できているときだけ選びます。当たるのは次の場合です。
- ソースを持っていない第三者製の
.libがv120以前でビルドされている。前の節のとおり 2013 以前は 14系とバイナリ互換が無いので、この場合は再ターゲットできません。ライブラリを14系版に入れ替えるまで、古いツールセット側に留まる以外にありません。 /GLや/LTCGでビルドされた入力が混ざっていて、同じビルドツールを揃えられない(C1047)。- 配布先に Windows XP が残っていて、14系の最新再頒布可能パッケージを入れられない。
これらに当たらないなら、古いツールセットを足す選択は、ビルド機を1台ずつ手作業で特別扱いし続けることになります。新しく入った人のPCでも、CIサーバーを立て直したときも、同じインストール作業が要ります。手順書に残していないと、特定の1台でしかビルドできない状態になります。
なお再ターゲット自体は、メッセージが案内しているとおり [プロジェクト] メニュー、またはソリューションの右クリックから [ソリューションの再ターゲット] で行えます。.vcxproj の PlatformToolset を直接書き換えても同じ効果になりますが、構成が複数ある場合は全構成ぶん揃っているかを確認してください。Debug だけ直して Release が v120 のまま、という取りこぼしがよくあります。
まとめ
- MSB8020 は
Microsoft.CppBuild.targetsから出ます。ソースの問題ではなく、$(PlatformToolset)が指すフォルダーがビルド機に無いという意味です。 - 世代は
.vcxprojのPlatformToolset1行に書いてあります。v140以降はメジャー番号が 14 で共通で、v120以前との間にだけバイナリ互換の壁があります。 v145でビルドしても、実行時に載るのはmfc140ud.dllでした(Debug/x64 実測)。再ターゲット先がv140〜v145のどれでも、配布先に入れるのは14系の再頒布可能パッケージ1つです。- 再頒布可能パッケージは同時に1つだけで、古い版は後から入れられません(
0x80070666)。XP 向けは 16.7 が最後です。 - 古いツールセットを足すのは、
v120以前でビルドされた第三者製ライブラリ、/GL混在(C1047)、XP 配布のいずれかに当たるときだけにします。
