VS2019のVC++で追加されたvcruntime140_1.dll ♯1

Visual Studio 2019からVC++のランタイムライブラリファイルの一つとして追加されたvcruntime140_1.dllに関する投稿です。

Visual StudioのVC++のラインタイムライブラリのファイル名

msvcrXXX.dll

Visual Studio 2013まではVC++のランタイムライブラリのファイル名は、msvcrXXX.dllでした。XXXはバージョン番号が入り、Visual Studio 2013のVC++ (Ver.12)では、msvcr120.dllでした。

この形式のファイル名は、歴史が古く1990年代から使われています。1996年のVisual C++ 4.0でもこの形式のファイル名が使われており、実際にはそれより古い時代から使用されているファイル名です。

vcruntime140.dll

Visual Studio 2015のVC++ (Ver. 14)ではランタイムライブラリのファイル名はvcruntime140.dllになりました。その後、Visual Studio 2017 (Ver. 15) / 2019 (Ver. 16) / 2022 (Ver. 17)の後継バージョンにおいても vcruntime140.dllです。ファイル名の中のバージョン番号に相当する部分の140は変化はありませんでした。

vcruntime140_1.dll

Visual Studio 2019から、ランタイムライブラリの構成ファイルとしてvcruntime140.dllに加えてvcruntime140_1.dllが追加されました。VC++の特定の機能を利用するとこの追加されたファイルを参照します。その機能は、Visual Studio 2019の初期バージョンでは既定で無効化されていました。その後、Visual Studio 2019 Update 3のバージョン(16.3)から既定で有効化されました。Visual Studio 2019の最新版(2022年2月時点では16.11.10)、および、Visual Studio 2022以降のバージョンでも引き続き既定で有効化されており、既定の設定でVC++のビルドをすると、この vcruntime140_1.dll への参照が発生することになります。

vcruntime140_1.dllが追加されたことによる共有ライブラリーなどで発生する問題

Visual Studio 2015 / Visual Studio 2017 / Visual Studio 2019 / Visual Studio 2022 まで、VC++のランタイムライブラリのメインのファイルのファイル名は vcruntime140.dllです。バージョンにより、ファイル名は変更になっていません。

異なるバージョン間でファイル名が同じということは、Visual Studio 2015のランタイムライブラリがインストールされている環境で、Visual Studio 2019のランタイムライブラリをインストールすと、ランタイムライブラリのファイルが上書き更新されることを意味ます。また、このライブラリが更新された状態でも、Visual Studio 2015のVC++でビルドしたアプリが問題なく動作することが保証されていることを意味します。

Windowsのデスクトプアプリにおいて、アプリが使用しているライブラリーは、容易にアプリのインストーラーに取り込めるように、ライブラリーをマージモジュールとして提供されます。ライブラリーを使うアプリのインストーラーはライブラリーのマージモジュールを取り込む形で作成します。ライブラリーをアプリとは別のインストーラーではなく、アプリのインストーラーに取り込むことにより、アプリのインストーラーを実行するだけで、そのアプリが動作するようになります。

通常、アプリのインストーラーはアプリが必要とするバージョンのランタイムライブラリーも一緒にインストールします。そのため、ランタイムライブラリーのファイルが追加になってもアプリと一緒にインストールされるので、特に問題は発生しません。

しかし、アプリ間で共有され、同じ場所にインストールされるライブラリーでは、アプリのインストーラーがライブラリーを取り込んでいたとしても、問題になることがあります。

例えば、AAAというアプリとBBBというアプリがCCCというライブラリーを共有していることを考えます。

各アプリ、ライブラリのビルド状況は以下とします。

  • AAAアプリはVS2015でビルドされており、CCCライブラリーのバージョン1.0を使用。
  • BBBアプリはVS2022でビルドされており、 CCCライブラリーのバージョン2.0を使用。
  • CCCライブラリーはバージョン1.0(VS2015でビルド)とバージョン2.0 (VS2022でビルド)でファイル名は同じ。

VS2015でビルドしたモジュールはvcruntime140_1.dllは不要です。しかし、VS2022でビルドしたモジュールはvcruntime140_1.dllが必要となります。そのため、上記のビルド状況の場合、各アプリのインストーラーは以下の構成となります。

インストーラーが抱える
モジュール
AAAアプリのインストーラー
(アプリはVS2015でビルド)
BBBアプリのインストーラー
(アプリはVS2022でビルド)
アプリ本体の
モジュール
AAAApp.exe Ver.1.0
(vcruntime140_1.dllは不要)
BBBApp.exe Ver.1.0
(vcruntime140_1.dllは必要)
VCランタイムライブラリーの
マージモジュール
VS2015のマージモジュール(14.0)
vcruntime140.dll Ver.14.0
VS2022のマージモジュール(14.30)
vcruntime140.dll Ver.14.30
vcruntime140_1.dll Ver.14.30
CCCライブラリーの
マージモジュール
Ver.1.0のマージモジュールCCCLibrary.dll Ver.1.0
(vcruntime140_1.dllは不要)
Ver.2.0のマージモジュール
CCCLibrary.dll Ver.2.0
(vcruntime140_1.dllは必要)

この状態で作成されたAAAアプリとBBBアプリは、単独インストール、および、両方のインストールでは特に問題置きません。しかし、AAAアプリとBBBアプリをインストールした後に、BBBアプリをアンインストールするとCCCライブラリが正常動作しなくなり、AAAアプリの実行に問題が出ます。

  1. AAAアプリをインストール
  2. BBBアプリをインストール
  3. BBBアプリをインストール
  4. AAAアプリをインストール

上記の手順でアプリをインストール・アンインストールした場合にシステム上のファイルがどのようになるかをまとめたのが以下の表となります。

#操作AAAアプリ 本体ファイルBBBアプリ 本体ファイルVC ランタイム ライブラリー ファイルCCCライブラリー ファイル
0アプリのインストール前なしなしなしなし
1AAAアプリをインストール後AAAApp.exe Ver.1.0
(vcruntime140_1.dllは不要)
なしvcruntime140.dll Ver. 14.0CCCLibrary.dll Ver.1.0
(vcruntime140_1.dllは不要)
2BBBアプリをインストール後AAAApp.exe Ver.1.0
(vcruntime140_1.dllは不要)
BBBApp.exe Ver.1.0
(vcruntime140_1.dllは必要)
vcruntime140.dll Ver.14.30
vcruntime140_1.dll Ver.14.30
CCCLibrary.dll Ver.2.0
(vcruntime140_1.dllは必要)
3BBBアプリをアンインストール後AAAApp.exe Ver.1.0
(vcruntime140_1.dllは不要)
なしvcruntime140.dll Ver.14.30
(注意: vcruntime140_1.dll Ver.14.30 は削除され存在しない)
CCCLibrary.dll Ver.2.0
(vcruntime140_1.dllは必要)
4BBBアプリをアンインストール後なしなしなしなし
CCCLibrary.dll Ver.2.0 が vcruntime140_1.dll に依存しする場合

この表の手順1では、AAAアプリしかインストールされておらず、AAAの実行は何も問題ありません。

手順2で、BBBアプリをインストールすると、BBBアプリのファイルが追加されると同時に、ランタイムライブラリーやCCCライブラリーのファイルは、新しいバージョンのファイルに置き換わります。このとき、vcruntime140_1.dll Ver.14.30のファイルも追加されます。

手順2の直後では、AAAアプリ、BBBアプリ共にアプリの実行に必要となるファイルが存在するため正常動作します。

つぎに、手順3でBBBアプリをアンインストールします。このとき、BBBのインストーラーが追加インストールしたvcruntime140_1.dllは削除されます。しかし、 vcruntime140.dllCCCLibrary.dllは、AAAアプリが参照しているので削除されません。

この手順3が終わった状態では、ユーザーはAAAアプリをアンインストールしたわけではないので、AAAアプリが正常に動作することを期待します。しかし、実際には正常動作しません。なぜなら、CCCライブラリーはVer.2.0のファイルがシステム上に残っている状態です。CCCライブラリーのVer.2.0では vcruntime140_1.dll のファイルが必要です。しかし、 vcruntime140_1.dll が存在しないため正常動作しません。

なお、手順4で、AAAアプリをアンインストールした場合は、ごみファイルは残らず、すべてのファイルが削除されます。

この手順3が終わった状態が、vcruntime140_1.dllへの参照が追加されたことが原因で、共有ライブラリーで発生する問題となります。

vcruntime140_1.dll の追加により共有ライブラリーなどで発生する問題を解決方法の検討

この問題を解決する方法はあるのでしょうか?

この問題は、手順3が終わった段階で、 CCCLibrary.dll Ver.2.0の正常動作のために必要なファイル vcruntime140_1.dll が存在していないことです。そのため、CCCLibrary.dll Ver.2.0がファイル vcruntime140_1.dll に依存しないようにビルドができれば、問題を解決できます。

その方法には二つあります。

  • CCCLibrary.dllがVC++のランタイムライブラリーのすべてのDLLファイルを参照しないようにする
  • CCCLibrary.dllがVC++のランタイムライブラリーの中のvcruntime140_1.dllファイルのみを参照しないようにする

上記のいずれかを実現できると、CCCLibrary.dllvcruntime140_1.dllに依存しなくなります。

この場合でもBBBアプリの作成方法(ビルド方法)には影響ありません。CCLibrary.dll Ver.2.0の vcruntime140_1.dll への依存をなくすだけであり、BBBアプリでは、 vcruntime140_1.dll への依存は残ったままでも問題ありません。

この方法をとった場合、先ほどの表の内容は以下の表に置き換わります。

#操作AAAアプリ 本体ファイルBBBアプリ 本体ファイルVC ランタイム ライブラリー ファイルCCCライブラリー ファイル
0アプリのインストール前なしなしなしなし
1AAAアプリをインストール後AAAApp.exe Ver.1.0
(vcruntime140_1.dllは不要)
なしvcruntime140.dll Ver. 14.0CCCLibrary.dll Ver.1.0
(vcruntime140_1.dllは不要)
2BBBアプリをインストール後AAAApp.exe Ver.1.0
(vcruntime140_1.dllは不要)
BBBApp.exe Ver.1.0
(vcruntime140_1.dllは必要)
vcruntime140.dll Ver.14.30
vcruntime140_1.dll Ver.14.30
CCCLibrary.dll Ver.2.0
(vcruntime140_1.dllは不要)
3BBBアプリをアンインストール後AAAApp.exe Ver.1.0
(vcruntime140_1.dllは不要)
なしvcruntime140.dll Ver.14.30
(注意: vcruntime140_1.dll Ver.14.30 は削除され存在しない)
CCCLibrary.dll Ver.2.0
(vcruntime140_1.dllは不要)
4BBBアプリをアンインストール後なしなしなしなし
CCCLibrary.dll Ver.2.0 が vcruntime140_1.dll に依存しない場合

変化しているのは、オレンジ背景色の部分のみです。たったこれだけですが、問題が解決します。

手順2では、BBBアプリ本体のモジュールが vcruntime140_1.dll を必要とするため引き続き vcruntime140_1.dll がインストールされます。

手順3では、BBBアプリがアンインストールされたことにより、vcruntime140_1.dllがアンインストールされます。しかし、CCCLibrary.dll Ver.2.0は、vcruntime140_1.dll に依存していないので、正常動作が可能です。その結果、AAAアプリも正常動作が可能です。

この結果、すべての手順で、AAAアプリもBBBアプリもユーザーの期待通りの動作をすることになります。

vcruntime140_1.dll の追加により共有ライブラリーなどで発生する問題を解決方法の検討

問題を解決する方法は、CCCLibrary.dllvcruntime140_1.dllへの依存をなくすることであり、二つの方法がありました。

  • CCCLibrary.dllがVC++のランタイムライブラリーのすべてのDLLファイルを参照しないようにする
  • CCCLibrary.dllがVC++のランタイムライブラリーの中のvcruntime140_1.dllファイルのみを参照しないようにする

実際、この二つの方法は、実現する手段があるのでしょうか?

前者の方法は、CCCLibrary.dllのビルド時にVC++のランタイムライブラリーを静的ライブラリーとしてリンク(/MT)することで可能です。 これでランタイムライブラリーのすべてのDLLに対して、依存をなくすことができます。しかし、ランタイムライブラリーを静的ライブラリーとしてリンクすると、 CCCLibrary.dll のファイルサイズが巨大化します。ファイルサイズの巨大化は避けたいのでこの方法を採用することはしたくありません。

後者の方法は二つの実現手段があります。

後者の方法の一つ目の手段は、CCCLibrary.dllをVisual Studio 2017以前を使ってビルドすることです。Visual Studio 2017以前であれば、 そもそもvcruntime140_1.dll ファイルが存在しないので問題は発生しません。しかし、開発環境のライフサイクル的にも、セキュリティ的にも、CCCライブラリーのビルドをするときには、その時点での最新の開発環境(Visual Studio)を使うことが推奨されます。そのため、ライブラリーの新しいバージョンをリリースするときには、この方法は避けたいです。

後者の方法の二つ目の手段は、最新の開発環境(Visual Studio 2022)で、vcruntime140_1.dllを必要とする機能を無効化して、ビルドすることです。機能を無効化することにより、 vcruntime140_1.dll への参照がなくなります。これにより、問題が発生しなくなります。

vcruntime140_1.dll を必要とするVisual Studioの機能とは?

さて、Visual Studio 2019やVisual Studio 2022で追加されたvcruntime140_1.dll を必要とする機能とは、どのような機能でしょうか?また、その機能の無効化はできるのでしょうか?

次回の投稿で、そのあたりを探っていきたいと思います。


今回の投稿では、Visual Studio 2019のVC++のランタイムライブラリーで追加されたのvcruntime140_1.dllに関して、共有ライブラリーで発生する問題についての説明でした。次回は、その対策について投稿したいと思います。

コメントを残す