前回は、VCランタイムをスタティックリンクして生成させるという話で終了しましたが、今回はその続きに当たるダイナミックリンク版のVCランタイムを使用しつつ前回の条件を満たす、ということを考えてみたいと思います。
前回はこちらに。 現在のWindowsサイドバイサイドについて
ここでは2005,2008と2010,2012での谷間によって、大きく違います。
2010以降で生成されたアプリケーションでは、VCランタイムに関する埋め込みマニフェストがないため、そのまま必要なDLLをexeと同じ場所にコピーしておくことで対処できます。
一方で、2005,2008はカレントに決められた名前でフォルダを作成してその中にDLLを配置する手法をとります。
これはプライベートアセンブリというものに該当します。
図示するとこんな感じです
-- Application.exe + Microsoft.VC90.CRT + msvc***.dll + Microsoft.VC90.CRT.manifest
Microsoft.VC90.CRT というフォルダはVCインストールフォルダでredistというフォルダの中で見つけることが出来ます。
このように配置してアプリケーションを動かしたいということは、その環境ではランタイムが入っていないわけですので、
Application.exe が要求するバージョンの Microsoft.VC90.CRT を配置しなくてはなりません。
ここがくせ者でして、VisualStudio2005,2008にはそれぞれで違った挙動を示してくれます(涙
- 2005の場合
- ビルド環境の最新状態のVCランタイムバージョンにバインドされる
- 2008の場合
- ビルド環境の最新状態のVCランタイムバージョンではなく、2008RTM版のランタイムバージョンにバインドされる
つまり、2005のこの挙動であれば、ビルド環境のredistフォルダからコピーして配置で問題なく動くようになるわけです。
一方、2008のこの挙動ではビルド環境のVCインストールフォルダのredistも最新状態のランタイムに更新されているため、redistフォルダからのコピーではバージョン違いにより動作させることが出来ない状態となります。
これらの挙動を修正するのに、exeが要求するランタイムバージョンを変更するという方法が1つあげられます。それが外部マニフェストです。
exeと同じ場所に、exe名(拡張子含む).manifestというファイルを作成することで、処理されるマニフェストを上書きする形で制御できます。ここにredist内で見つかったバージョンを要求するように書き換えてしまえばうまく動くという考えです。
この方法はXPまでであれば考え通りに動きますが、2003以降マニフェストの処理優先順が変わりました。そのため現在主流となっているWindows7周辺のバージョンでは埋め込みマニフェストが優先されてしまうため、動かない状態となります。
この状態でとれる案として以下のものが考えられます。
- 2008の場合において、ビルド時に
_BIND_TO_VCLIBS_CURRENT_VERSION=1 (プリプロセッサ定義で指定する) - 生成されたexeの埋め込みマニフェストを編集する
(1)の場合、ビルド時のVCランタイムバージョンにバインドされるようになります。
依存するライブラリ全てにおいてこのプリプロセッサ定義を行いexeを生成できれば、ビルド環境のredistからランタイムをコピーだけで動くようになります。
(2)の場合、mt.exe というツールを用いて、manifest取り出し → 編集 → 再度埋め込み という手順を行います。
具体的には、下記のような感じになります。
取り出し mt.exe -inputresource:Application.exe;#1 -out:result.manifest
取り出したマニフェストファイルを開き、要求しているバージョンを変更します。
埋め込み mt.exe -manifest result.manifest -outputresource:Application.exe;#1
以上で、exe単体で動かす場合の話は終了です。
しかし、オープンソースのライブラリや自作の他ライブラリを用いており、それがDLL版だったりすると話はまだ続きます。
これについてはまた次回に。