アプリケーションに静的にリンクされた CRT と動的にリンクされた CRT が混在する原因を確認するにはどうすればよいですか
-
21-09-2019 - |
質問
続いて長文になってしまい申し訳ありません。
Microsoft が提供する、静的にリンクされた C ランタイムと動的にリンクされた C および C++ ランタイムを混在させるのは得策ではないことはわかっています。残念なことに、私たちが働いているアプリケーションではすでにそれらが混在しており、それを修正しようと努めてきました。さまざまな理由 (MSI に慣れていないこと、MSM を十分にサポートしていない可能性がある NSIS を使用していること、時間とリソースの不足など) により、CRT を動的ではなく静的にリンクすることにしました。これが良いアイデアではない理由はわかっていますが、現時点ではこれが私たちの選択でした。
私たちのコードはほとんどが標準 C++ であり、他の多くのオープンソース ライブラリによって補完されています。
アプリケーションの構造は次のとおりです。さまざまなモジュールが静的ライブラリを生成し、それら自体がリンクされてさまざまなものが作成され、その中の 1 つの実行可能ファイルが問題を引き起こします。
リリースではすべてをビルドします 私たちの /MT付きのコードです。オープンソース ライブラリの一部ではプリコンパイルされたバイナリを使用し、それらの一部は /MD でプリコンパイルされた DLL だったので、ランタイムを混在させました。そこで、/MT を使用してこれらを自分たちで再コンパイルし、DLL ではなく静的ライブラリが生成されるようにしました。この変換はライブラリごとに行われないため、/MD を使用する一部の DLL とリンクします。
結果は、depends.exe にすべての内容が含まれることになります。 1 つの実行可能ファイルを除いて しません 直接 msvcr80.dll または msvcp80.dll に依存します。による 直接依存しない つまり、msvcr80.dll は、depends.exe で示されるツリーのルートの子ではありません。場合によっては、ライブラリ DLL の 1 つによって msvcr80.dll が取り込まれているのが見つかることがありますが、それはツリーのさらに深いレベルにあります。
msvcr80.dll が厄介な実行可能ファイルの最初のレベルにある理由を調べるにはどうすればよいですか?その実行可能ファイルが msvcr80.dll に直接リンクされるのはなぜですか?
理由の 1 つは、リンクが /MD を使用しているため、CRT と動的にリンクしているライブラリ A に静的にリンクしていることが考えられます。したがって、ライブラリ A のコードは実行可能ファイルになり、実行可能ファイルは msvcr80.dll にリンクされます。しかし、どのライブラリがそれを行っているかをどうやって調べればよいのでしょうか?
これまでに試したこと:
- 静的にリンクされた .lib ファイルを depend.exe にロードします -> depends.exe は静的ライブラリではなく実行可能ファイルまたは DLL を想定しているため、機能しません
- 静的にリンクされた .lib ファイルで dumpbin.exe /DIRECTIVES を使用します -> それらのどれも msvcrt80.dll を表示しませんでした (デバッグでは、すべてに /MDd を使用しようとしましたが、msvcrt80d.dll が表示されました。これは、この方法がこれは、静的にリンクされたすべてのオープンソース ライブラリが /MT で正しくコンパイルされていることを証明します)
- /VERBOSE:LIB リンカー フラグを使用します -> 実際に msvcr80.dll のインポート ライブラリである msvcrt.lib を取り込んでいることが示されたため、問題が発生しましたが、なぜそのようなことを行うのかは示されていませんでした
- Visual Studio で /VERBOSE リンカー フラグ + を使用します。追加の依存関係 libcmt.lib + すべてのデフォルト ライブラリを無視する YES + 特定のライブラリを無視する:msvcrt.lib を削除するか、誰がそれをプルするかを確認しようと必死の試みです。その結果は私を困惑させました:
Searching C:\Program Files\Microsoft Visual Studio 8\VC\lib\msvcrt.lib: Found "public: virtual void * __thiscall type_info::`vector deleting destructor'(unsigned int)" (??_Etype_info@@UAEPAXI@Z) Referenced in libcmt.lib(typinfo.obj) Loaded msvcrt.lib(ti_inst.obj) msvcrt.lib(ti_inst.obj) : error LNK2005: "private: __thiscall type_info::type_info(class type_info const &)" (??0type_info@@AAE@ABV0@@Z) already defined in libcmt.lib(typinfo.obj) msvcrt.lib(ti_inst.obj) : error LNK2005: "private: class type_info & __thiscall type_info::operator=(class type_info const &)" (??4type_info@@AAEAAV0@ABV0@@Z) already defined in libcmt.lib(typinfo.obj) Found "void __stdcall `eh vector destructor iterator'(void *,unsigned int,int,void (__thiscall*)(void *))" (??_M@YGXPAXIHP6EX0@Z@Z) Referenced in msvcrt.lib(ti_inst.obj) Loaded msvcrt.lib(ehvecdtr.obj)
私が理解している限り、libcmt.lib の typinfo.obj はシンボルを参照し、msvcrt.lib でそれを検索し、ti_inst.obj で見つかった後、それが 2 回定義されているというエラーをスローします。しかし、これでは意味がありません。libcmt.lib に既にシンボルがある場合、msvcrt.lib でそのシンボルを検索し、実行可能ファイルに msvcr80.dll を含めるのはなぜですか?さらに一般的には、なぜ静的ライブラリは動的インポート ライブラリ内のシンボルを検索するのでしょうか?msvcrt.lib が [特定のライブラリを無視] にある場合、リンカーはなぜ msvcrt.lib を参照するのでしょうか?
お待ち頂きまして、ありがとうございます :-)。
解決
私は私の問題への解決策を持っています。それはおそらく古代から残っ愚かな間違いだった。
MSVCRT.LIBは明示的に、私たちはしなかったので、ボックスにテキストをたくさん持っていることを追加の依存関係で私たちによってボックス:-(ので、もちろんそれは、DLLの依存関係を作った。述べそしてなぜなら、すべてのオープンソースライブラリのましたそれに気づく。そして、私たちも、私たちは私たちのプロジェクトでは、このような総間違いがある可能性が想像していなかったので、慎重にその箱を見て考えていなかった正直に言うと。
他のヒント
を開きます実行アップするDepends.exeとし、依存に組み込まれてプロファイラを実行します。私はすべてのあなたのDLLがロードされている理由は、これがログに記録されますと信じて、そしてどこからそれらがロードされます。 「ログLoadLibrary関数の呼び出し」オプションを参照してください。