Tech Notes

CMakeで開発したソフトを配布する方法(Windows)

CMakeはC/C++製のプログラムをビルドする際にほぼ必須と言っても良いツールだが、ビルドしたものを配布する際の注意点というものはあまり共有されていないように思う。

まさか万人がソフトウェアをソースコードからビルドするという訳にも行くまい。この記事ではCMakeを利用してソフトウェアを開発し、そのバイナリを配布する際の注意点について書きたいと思う。環境はWindowsに絞る。

とりあえずWindows向けのビルドでは殆どの場合においてMSVCかMinGWを用いるものと思うので、その2ツールを対象に解説する。

注意点1. リリースビルド

当然のことながら、ソフトウェアを一般に配布する場合はリリースビルドで配布するべきだ。デバッグビルドはサイズが多少大きく、遅い可能性があり、また開発者のPCの情報も含まれる可能性がある。性能的にも情報保護のためにもリリースビルドしたものを配布するようにしよう。

MSVCの場合

CMakeで使うビルドツールとしてMSVCを用いる場合、いわゆるマルチコンフィギュレーション・ビルドになる。速い話がcmake .とかやった後にデバッグビルドかリリースビルドか選ぶということだ。

リリースビルドの場合はこのようにする。

# ビルドディレクトリのパスが「./build」の場合
cmake --build ./build --config Release

こうすると./build/Debug/下ではなく./build/Release/の下にビルド成果物が生成されるはずだ。

MinGWの場合

MinGWを用いる場合はシングルコンフィギュレーションなので、ビルド時ではなくコンフィギュレーション時にデバッグビルドかリリースビルドかを指定する。

これはCMAKE_BUILD_TYPEの値で指定する。

cmake . -B ./build -DCMAKE_BUILD_TYPE=Release
cmake --build ./build

注意点2. VC++再頒布可能パッケージ問題

MSVCでビルドしたソフトには1つ大きな罠がある。

何の設定もなくMSVCでビルドしたアプリケーションは、基本的にVC++再頒布可能パッケージに依存するのである。 これはMicrosoftが用意しているいわゆるランタイムライブラリで、無設定のMSVC製のプログラムはこれがないと動かない。

これの対処法には主に2つある。

対処法A. 再頒布可能パッケージの頒布

再頒布可能パッケージは再頒布可能だから再頒布可能と銘打っているのである。

自分の開発したソフトと一緒に、「このソフトを動かすにはこのパッケージをインストールしてください」という形でインストーラ(vc_redist.x64.exeなど)を同梱する。もしくはREADMEなどにMicrosoft公式配布のリンクを書くとかしてしまえばよい。実際、そうしたソフトは世の中によくある。

再頒布可能パッケージのインストーラは以下の記事にリンクがある。

https://learn.microsoft.com/ja-jp/cpp/windows/latest-supported-vc-redist

ユーザーには多少面倒をかけるかもしれないが、例えばRPGツクール製ソフトもRTPのインストールを求めるし、そんなものだろう。

対処法B. 再頒布可能パッケージに依存しない形でビルド

設定次第では再頒布可能パッケージに依存しないようにビルドすることもできる。 これはつまりEXEファイルに組み込むということであって、その分バイナリのサイズはやや大きくなる(+200KB程度)。そこはトレードオフだ。

この方法はVisual Studio自体に慣れている人であれば知っている通り、Visual Studioで開いてプロジェクトのC/C++>コード生成>ランタイム ライブラリの設定でマルチスレッド DLL(/MD)マルチスレッド(/MT)に変えるだけだ。だがもちろんいちいちVisual Studioを開くのは手間がかかる。

この設定はCMake越しでも行えるようになっている。 具体的にはCMakeプロパティのMSVC_RUNTIME_LIBRARYの値を設定することによって行える。

set_target_properties(main PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreaded")

実際にはリリースビルドのときMultiThreaded、デバッグビルドのときMultiThreadedDebugにしたいので、以下のようになるだろう。

set_target_properties(main PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")

参考: https://cmake.org/cmake/help/latest/prop_tgt/MSVC_RUNTIME_LIBRARY.html

なお、MSVC_RUNTIME_LIBRARYの内容はCMake変数CMAKE_MSVC_RUNTIME_LIBRARYの値で初期化される。CMakeLists.txtには手を加えず、ビルド時に指定する運用にしても良いだろう。

cmake . -B ./build -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded

再頒布可能パッケージ依存の確認

Visual Studioを起動してプロジェクトを開き、「コード生成>ランタイム ライブラリ」の設定項目を直接確認すればよい。

また、Visual Studio付属のdumpbinでEXEファイルを確認しても良い。

# 依存がある場合
> dumpbin /DEPENDENTS C:\hoge\hoge\build\Release\app.exe
Microsoft (R) COFF/PE Dumper Version 14.42.34436.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file C:\hoge\build\Release\app.exe

File Type: EXECUTABLE IMAGE

  Image has the following dependencies:

    KERNEL32.dll
    MSVCP140.dll
    VCRUNTIME140.dll
    VCRUNTIME140_1.dll
    api-ms-win-crt-runtime-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-stdio-l1-1-0.dll
    api-ms-win-crt-locale-l1-1-0.dll
# 依存がない場合
> dumpbin /DEPENDENTS C:\hoge\build\Release\app.exe
Microsoft (R) COFF/PE Dumper Version 14.42.34436.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file C:\hoge\build\Release\app.exe

File Type: EXECUTABLE IMAGE

  Image has the following dependencies:

    KERNEL32.dll

(重要補足)CMakeのバージョン指定について

重要な注意点だが、MSVC_RUNTIME_LIBRARYに対応するのはCMake 3.15からである。ビルドに使うCMakeはこれ以上のバージョンでなくてはならず、また最新のCMakeを使っていても適切なcmake_minimum_requiredの設定がなければ有効にならない。

cmake_minimum_required(VERSION 3.15) # 3.15以上のバージョンを設定する

これはかなり忘れがちなので、もしもMSVC_RUNTIME_LIBRARYまたはCMAKE_MSVC_RUNTIME_LIBRARYの指定をしているのに再頒布可能パッケージ依存がなくならなかったら、CMakeLists.txtを確認して見るとよい。

おわりに

Windowsアプリ開発でVisual Studioの重さに辟易している人は多いと思う。VSCodeなどへ乗り換えている人も多いだろう。

VSCodeと組み合わせるC++環境としてはWSL&GCCやMinGW&GCCという選択肢もあり、C++の基礎の勉強が目的であればこれで事欠かないかもしれない。しかしこと一般向けのWindowsネイティブアプリ開発となると、WSLは論外だしMinGWはMicrosoft公式でないという心許なさがある。やはりMSVCのツールチェインをVSCodeから使いたくなる。

この目的においてCMakeはかなり強い選択肢で、Visual Studioのインストールさえしておけばあとは任意のテキストエディタと任意のシェルで開発を完結できる。ぜひCMake+MSVCをWindowsアプリ開発の有力な手段として検討してみてはいかがだろうか。Meson?あれはPythonアンチとしては勧める訳に行かないから...

コメント