コンパイルは全部通ったのに、リンクの最後でerror LNK2038: ‘RuntimeLibrary’ の不一致が検出されました と出て、ビルドが止まる。
ランタイム ライブラリの設定が、リンクした相手どうしで食い違っています。まずはそのエラー行に並んだ2つの値を読んでみましょう。
LNK2038の行に並ぶ2つの値は、どちら側の設定か
下の3行は、手元で実際に出したものです。EXE側を /MDd、静的ライブラリ側を /MTdにして、Visual Studio 2026のDebug / x64でリンクしています。長いパスだけ省きました。ファイル名も値も、出たままの文字列です。
ReproLib.lib(ReproProbe.obj) : error LNK2038: 'RuntimeLibrary' の不一致が検出されました。値 'MTd_StaticDebug' が MDd_DynamicDebug の値 'ReproApp.obj' と一致しません。
LINK : warning LNK4098: defaultlib 'LIBCMTD' は他のライブラリの使用と競合しています。/NODEFAULTLIB:library を使用してください。
248_RuntimeLibraryMismatch_Repro.exe : fatal error LNK1319: 1 の不一致が検出されました
見るのは1行目だけでいいと思います。行頭と行末に .objの名前が1つずつ出ていますね。これがリンクでぶつかった相手どうしで、あいだの2つの値がそれぞれの側の設定です。
| 行の中の位置 | 指しているもの | 上の例の読み |
| 行頭の .lib(.obj) | 片方の側 | ReproProbe.objはMTd_StaticDebugでコンパイルされている |
| 行末の ‘….obj’ | もう片方の側 | ReproApp.objはMDd_DynamicDebugでコンパイルされている |
頭から順に読むと、値とファイル名が入れ替わって見えると思います。公式の書式は ‘name’ の不一致が検出されました。値 ‘value_1’ がfilename.objの値 ‘value_2’ と一致しません です。日本語版では、最後の2つの差し込みが逆に出ます。
あとの2行は、1行目の結果です。LNK4098は既定ライブラリの競合で、公式は種類の違うランタイム ライブラリを混ぜたときに出ると書いています。LNK1319は、不一致の件数を添えてリンクを打ち切る締めの行です。
値の文字列を、プロパティ ページの表示に読み替える
設定する場所は[構成プロパティ] > [C/C++] > [コード生成] > [ランタイム ライブラリ]です。下の画面がそこを開いたところです。
![Visual Studioのプロパティ ページで [構成プロパティ] > [C/C++] > [コード生成] を開き、[ランタイム ライブラリ] の行を赤枠で囲んだ画面。値は [マルチスレッド デバッグDLL (/MDd)]、下の説明欄には「リンクするランタイム ライブラリを指定します。(/MT, /MTd, /MD, /MDd)」と出ている](https://www.mfcguide.com/wp-content/uploads/248_lnk2038-runtimelibrary-mismatch-properties-049d1b7a9195.png)
ただ、ここの表示とエラー行に出る値は字面が違います。下の表で見比べてください。
| プロパティ ページの表示 | LNK2038に出る値 | 定義されるマクロ | リンカーが引くCRT |
| マルチスレッド デバッグDLL (/MDd) | MDd_DynamicDebug | _DEBUG _MT _DLL | MSVCRTD.lib |
| マルチスレッドDLL (/MD) | MD_DynamicRelease | _MT _DLL | MSVCRT.lib |
| マルチスレッド デバッグ (/MTd) | MTd_StaticDebug | _DEBUG _MT | LIBCMTD.lib |
| マルチスレッド (/MT) | MT_StaticRelease | _MT | LIBCMT.lib |
値の列のうちDebugの2つは、Visual Studio 2026の実機で出したものです。Releaseの2つは、Microsoft Learnに残る実際のエラー行から引きました。マクロとCRTの列は /MD、/MT、/LDの公式ページの記載です。第1列の文言はMicrosoft Learnの設定手順に合わせました(/MDdと /MD、/MTd、/MT)。
どちらに揃えるかは、変えられない側で決まる
公式が言っているのは、これだけです。リンカーの特定の呼び出しに渡されるすべてのモジュールは、同じランタイム ライブラリ コンパイラ オプション(/MD、/MT、/LD)でコンパイルされている必要があります。揃ってさえいれば、どちらでも構いません。どちらに寄せるかは、設定を変えられない側を見て決めてください。ソースの無い外部ライブラリやSDKが /MTでビルドされているなら、こちらを /MTへ寄せるほうが早いでしょう。
ただしMFCアプリでは寄せられないことがあります。公式のテクニカル ノートTN033(MFCのDLLバージョン)は、共有版に必要なコンパイラ フラグを /D_AFXDLL /MDとしています。そのうえで、アプリケーションはCランタイム ライブラリのDLLバージョンを使用する必要があると書いています。MFC共有DLLを使う側に /MT系の選択肢はありません。相手のライブラリを /MDでビルドし直すか、/MD版のバイナリを入手するか、どちらかです。
MFCをスタティック ライブラリとして使う構成なら、この制約は外れます。そちらは「MFCの使用」設定との組合せの話で、LNK2005とMFCの使用設定の記事で扱っています。
DebugとRelease、_ITERATOR_DEBUG_LEVELは別々に揃える
この設定は、ビルド構成ごとに別々に持ちます。Debugで揃えても、Release側が残っていれば構成を切り替えたときに同じエラーが出ます。
同じ理由で _ITERATOR_DEBUG_LEVELも食い違います。公式は、リンカーが突き合わせるシンボルとして _MSC_VER・_ITERATOR_DEBUG_LEVEL・RuntimeLibrary・_PPLTASKS_WITH_WINRTの4つを挙げています。_ITERATOR_DEBUG_LEVELの既定値は、デバッグで2、リリースで0です。どちらも既定のままなら、Debugでビルドした .libをReleaseのアプリへリンクしたときに、この値も食い違います。片方だけ直しても、もう一方が残ります。
_MSC_VERの不一致だけは意味が違います。ライブラリをビルドしたコンパイラの版が自分と違う、ということです。公式は、互換性のあるライブラリを入手もビルドもできない場合に、[プラットフォーム ツールセット]を以前のものへ変える手を示しています。
リンカーが不一致に気づく仕組み
からくりは .objの中です。detect_mismatchプラグマ(公式ドキュメントのpreprocessor/detect-mismatch)はオブジェクト内にレコードを置き、リンカーがそれを不一致の可能性として調べます。同じ名前で値の違う2つのオブジェクトが混ざるとLNK2038になります。
#pragma detect_mismatch("MFCGUIDE_248_SAMPLE_ABI", "1")
公式が書いているのは、この一方向だけです。そろわない場合のことは書かれていません。このレコードは、ソースに書かなくても入ります。書いた覚えのないMTd_StaticDebugがエラー行に出るのは、そのためです。
同じエラーは手元でも出せる
静的ライブラリのプロジェクトを1つ作り、関数を1本置いて、EXEから呼びます。静的ライブラリ側ではMFCを使いません。MFC共有DLLのプロジェクトは /MT系でコンパイルできないからです。EXE側はMFC共有DLLのままでかまいません。
両方の[ランタイム ライブラリ]が同じなら、リンクは通ります。次に、静的ライブラリ側だけを[マルチスレッド デバッグ (/MTd)]へ変えてリビルドします。さっきの3行が出ます。設定を戻してもう一度リビルドすると消えます。

ここでリンクが通ってしまうことがあります。手元のVisual Studio 2026では2回そうなりました。どちらも出たのはLNK4098の1行だけで、LNK2038もLNK1319も出ず、EXEができました。そのLNK4098が名指ししていたのは、/MTdのCRTであるLIBCMTDです。設定は食い違っていたのに、検査は働きませんでした。なぜ働かなかったのかは分かりません。当時のソースが残っておらず、ビルドのレポートにもソースの中身は載らないからです。リンクが通ったことを、設定がそろった証拠として読まないでください。
はじめの3行は、EXEをMFC共有DLLの /MDd、静的ライブラリをMFCなしの /MTdにして出しました。どちらもVisual Studio 2026 / Debug / x64 / Unicodeでビルドしました。
設定を直したのに消えないとき
先に古いオブジェクトを疑ってみてください。公式も、古い形式のオブジェクト ファイルで起きることがあると書いています。ほかの対処より先に、クリーン ビルドを実行するよう案内しています。設定を直したあとは、ビルドではなくリビルドで確かめましょう。
それでも残るなら、エラー行の先頭が名指ししている .libを誰が作ったかを見ます。自分のソリューション内のプロジェクトなら、その設定を直して再ビルドします。外部から受け取った .libなら、直せるのは自分の側だけです。その値へ揃えます。
LNK4098の行に出てくる /NODEFAULTLIBは、競合しているライブラリをリンクの対象から外すオプションです。RuntimeLibraryの値は揃わないままです。先に値を揃えて、それでも必要かどうかを決めてください。ほかのLNKも並んでいるなら、LNK1104 / LNK2019 / LNK2001の記事と、重複定義を扱うLNK2005 / LNK1169の記事へどうぞ。
まとめ:LNK2038を見たときの順番
- エラー行の2つの値を読む。行頭の .lib(.obj) が片方の側、行末の .objがもう片方の側。日本語版は語順が入れ替わって見える。位置で対応させる。
- 値の文字列を設定へ読み替える。Dynamicが /MD系、Staticが /MT系、d付きがDebug用。
- 設定を変えられない側に揃える。MFC共有DLLのプロジェクトは /MD系しか選べない。相手側をビルドし直す。
- DebugとReleaseを別々に揃え、_ITERATOR_DEBUG_LEVELも一緒に見る。直したらリビルドして確かめる。リンクが通っただけでは、設定がそろった証拠にならない。
