LNK2038:RuntimeLibraryを /MDと /MTのどちらに揃えるか

LNK2038:RuntimeLibrary を /MD と /MT のどちらに揃えるか

コンパイルは全部通ったのに、リンクの最後で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)」と出ている
赤枠の行が[ランタイム ライブラリ]です(構成Debug / プラットフォームx64)

ただ、ここの表示とエラー行に出る値は字面が違います。下の表で見比べてください。

プロパティ ページの表示LNK2038に出る値定義されるマクロリンカーが引くCRT
マルチスレッド デバッグDLL (/MDd)MDd_DynamicDebug_DEBUG _MT _DLLMSVCRTD.lib
マルチスレッドDLL (/MD)MD_DynamicRelease_MT _DLLMSVCRT.lib
マルチスレッド デバッグ (/MTd)MTd_StaticDebug_DEBUG _MTLIBCMTD.lib
マルチスレッド (/MT)MT_StaticRelease_MTLIBCMT.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行が出ます。設定を戻してもう一度リビルドすると消えます。

EXE側と静的ライブラリ側のランタイムライブラリ設定・LNK2038に出る値・既定のCRT・_MSC_VERを1行ずつ並べ、両側がそろっていることを示したMFC実行結果
揃っている状態をEXE側と静的ライブラリ側で並べたところ。設定・LNK2038に出る値・既定のCRT・_ITERATOR_DEBUG_LEVELが両側で一致している(Visual Studio 2026 / Debug / x64)

ここでリンクが通ってしまうことがあります。手元の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も一緒に見る。直したらリビルドして確かめる。リンクが通っただけでは、設定がそろった証拠にならない。
目次