Windows の LoadLibrary で奇妙な問題が発生しています。最初にいくつかの背景。このアプリケーションは Qt に依存しており、Qt はいくつかのライブラリに分割されています。Qt のバージョンをアップグレードしようとしていますが、誰にも影響を与えることはありません。新しい Qt ライブラリは、古いものと下位互換性があります。つまり、古いバージョンでビルドされたアプリケーションは、新しいバージョンをロードすると実行できます。その逆は当てはまりません。新しいバージョンでビルドされたアプリケーションは、古いバージョンが読み込まれると、シンボルが失われます。
Qt DLL はバージョン固有のディレクトリにあります (例としてc:\qt\qt-4.5.2\lib
とc:\qt\qt-4.8.1\lib
など)。ほとんどの開発者が PATH に持っている共通ディレクトリもあり、これには、使用するすべてのサードパーティ ライブラリの「現在の」バージョンが含まれています ( と呼びますc:\common\lib
)。これは、アプリケーションの実行時に通常 Qt ライブラリが見つかる場所です。
新しい Qt バージョンのライブラリを共通の場所に置きましたが、1 つのケースを除いて、すべてが正常に機能しているように見えました。問題のアプリケーションは複数のライブラリに分割されており、そのうちのいくつかは を呼び出すことによってロードされLoadLibrary()
ます。これらのランタイム ロード DLL の一部は、Qt ライブラリに依存しています。ロードされた DLL が に依存しQtXml
、それ自体が に依存している場合がありQtCore
ます。
ここが変なところです。アプリケーションは に依存しQtCore
、依存するライブラリをロードしますQtXml
。アプリケーションとライブラリは、旧バージョンの Qt とリンクしてビルドされています。このアプリケーションを PATH の common ディレクトリだけで実行すると、新しい Qt バージョンの DLL が common ディレクトリからロードされるため、すべてが機能します。ただし、パスに共通ディレクトリの前に古い Qt バージョンの DLL が保存されているディレクトリが含まれている場合、ランタイム DLL のロードはシンボルの欠落で失敗します。
(この状況は、特定のライブラリ バージョンを使用するように PATH を明示的に設定するスクリプトを使用して、自動化された単体テストを実行するときに発生します。)
私が把握できる限り、アプリケーションは の古いバージョンをロードしてQtCore.dll
おり、ランタイムにロードされた DLL は (どういうわけか) の新しいバージョンをQtXml.dll
ロードQtCore
しています。
しかし、PATH はc:\qt\qt-4.5.2\lib;c:\common\lib
(および他の無関係なパス) のようなものであるため、これは不可能に思えます。共通の lib ディレクトリから新しいものを削除するQtXml
と (古いバージョンに置き換えるのではなく、削除するだけです)、LoadLibrary()
すべての Qt ライブラリの 4.5.2 バージョンが読み込まれるため、成功します。しかし、PATH (共通) に Qt 固有のバージョン ディレクトリを指定せずに実行すると、QtXml
.
これはどうやってできるの?どのようLoadLibrary()
に (またはライブラリの依存関係を解決するために再帰的に呼び出すものは何でも)後でライブラリをロードできPATH
ますか? 共通ライブラリ ディレクトリが特別に考慮されていることを示すものは何も見つかりません (これは設定された DLL ディレクトリではありません)。ビルド プロセスでは言及されていませんが、開発者がPATH
便宜上持っているものです。
ところで、同様の状況が Linux と に存在しLD_LIBRARY_PATH
、dlopen()
そこでは問題なく動作します。これは、私には理解できない Windows のやり方の違いです。何がうまくいかないのかについての洞察を持っている人はいますか?