🧩

【Visual C++】自己完結型バイナリの作り方

2024/01/09に公開

Visual C++ には再頒布可能パッケージが必要

Visual C++で作成したEXEやDLLは、デフォルトだとランタイムDLLが動的リンクされるようになっています。

起動するにはユーザーに再頒布可能パッケージをインストールしてもらう必要があり、ちょっとした用途のソフトを配布するときには煩雑です。

作業環境

  • Windows 10
  • Visual Studio 2022

解決方法

ハイブリッドCRT[1]を使います。

ターゲットが Windows 10 以前の場合

Windows 10以前はハイブリッドCRTに必要なUCRTが同梱されていません。
手順2のみを行い、完全な静的リンクにしてください。

  1. プロジェクトプロパティを開きます。

  2. 構成プロパティ > C/C++ > コード生成 > ランタイム ライブラリ
    マルチスレッド(/MT)に変更。
    Alt text

  3. 構成プロパティ > リンカー > 入力 > 特定の既定のライブラリの無視
    libucrt.libを追加。
    Alt text

  4. 構成プロパティ > リンカー > コマンドライン > 追加のオプション
    /DEFAULTLIB:ucrt.libを追加。
    Alt text

以上で完了です。

デバッグ構成の場合

それぞれ、マルチスレッド デバッグ(/MTd)libucrtd.lib/DEFAULTLIB:ucrtd.libに変更してください。

ハイブリッドCRTとは

ハイブリッドCRTとは、Universal CRT(UCRT)動的リンクVisual C++ CRT静的リンクするハイブリット方式のことです。

ハイブリッドCRTには以下のメリットがあります。

  • 自己完結型になる
  • 完全な静的リンクに比べ、バイナリサイズが小さい
  • UCRTにセキュリティアップデートが適応される

UCRTとVisual C++ CRT

Visual C++のCRTは元々一つでしたが、Visual Studio 2015のリファクタリングでUCRTとVisual C++ CRTに分けられました。
UCRTには標準Cライブラリ、Visual C++ CRTにはVisual C++固有の機能が含まれます。

また、UCRTはWindows 10以降、OSの一部として同梱されています。

https://learn.microsoft.com/ja-jp/cpp/porting/visual-cpp-change-history-2003-2015?view=msvc-170#BK_CRT

他リンク方法との比較

Visual Studioのコンソールアプリテンプレートを作成し、Release構成(x64)を元に比較します。

テンプレートコード
#include <iostream>
int main()
{
    std::cout << "Hello World!\n";
}
CRTのリンク方法 依存関係[2] バイナリサイズ
静的リンク KERNEL32.dll 202 KB (207,360 バイト)
動的リンク KERNEL32.dll
MSVCP140.dll
VCRUNTIME140.dll
VCRUNTIME140_1.dll
api-ms-win-crt-runtime-l1-1-0.dll
api-ms-win-crt-stdio-l1-1-0.dll
api-ms-win-crt-heap-l1-1-0.dll
api-ms-win-crt-math-l1-1-0.dll
api-ms-win-crt-locale-l1-1-0.dll
12.0 KB (12,288 バイト)
ハイブリッド KERNEL32.dll
api-ms-win-crt-runtime-l1-1-0.dll
api-ms-win-crt-stdio-l1-1-0.dll
api-ms-win-crt-heap-l1-1-0.dll
api-ms-win-crt-math-l1-1-0.dll
api-ms-win-crt-locale-l1-1-0.dll
api-ms-win-crt-string-l1-1-0.dll
api-ms-win-crt-filesystem-l1-1-0.dll
72.5 KB (74,240 バイト)

ハイブリッドはVisual C++ CRTへ依存がなく、UCRT[3]を動的リンクすることでバイナリサイズも縮小しています。

Visual C++が依存するDLL

Visual C++で作成したアプリは、Win32 APIやUCRTの他に以下のDLLに依存しています。

  • VCRUNTIME140.dll (旧msvcr<version>.dll):Visual C++ CRT
  • MSVCP<version>.dll:C++ STL

それぞれ、dがつくデバッグ用や、clrがつくCLR用があります。
また、末尾に_<数字>がつくDLL(VCRUNTIME140_1.dllなど)は、既存のDLLを変更せずに機能を追加するためのDLLです。特定の機能を利用すると追加で参照されます。

これらのDLLもUCRTに依存しています。ハイブリッドCRTを使ったときに依存するUCRT APIが増えるのはそのためです。

Reference

https://learn.microsoft.com/ja-jp/cpp/windows/deployment-in-visual-cpp?view=msvc-170#local-deployment

https://github.com/microsoft/WindowsAppSDK/blob/main/docs/Coding-Guidelines/HybridCRT.md#what-is-the-hybrid-crt

https://learn.microsoft.com/ja-jp/cpp/c-runtime-library/crt-library-features?view=msvc-170

https://nishy-software.com/ja/dev-sw/vc-vcruntime140_1-dll-1/

脚注
  1. Cランタイムライブラリ(C Runtime Library)の略称です。 ↩︎

  2. 依存関係はdumpbinで調べました。 ↩︎

  3. api-ms-win-crt-[subset].dllはAPIセットのコントラクト名です。
    実体はUCRTのDLL、ucrtbase.dllです。 ↩︎

Discussion