У меня странная проблема с LoadLibrary в Windows. Сначала немного предыстории. Это приложение зависит от Qt, а Qt разбит на несколько библиотек. Пытаюсь обновить версии Qt, но никого не ломая. Новая библиотека Qt обратно совместима со старой. Это означает, что приложение, созданное с использованием более старой версии, может работать, если оно загружает более новую версию. Обратное неверно — приложение, созданное с использованием более новой версии, будет иметь отсутствующие символы, если загружена более старая версия.
Библиотеки Qt находятся в каталогах конкретной версии (например, c:\qt\qt-4.5.2\lib
и c:\qt\qt-4.8.1\lib
). Существует также общий каталог, который большинство разработчиков имеет в своем PATH, который содержит «текущие» версии всех сторонних библиотек, которые мы используем (назовем его c:\common\lib
). Именно здесь библиотеки Qt обычно находятся при запуске приложения.
Я поместил библиотеки новой версии Qt в общее расположение, и все вроде бы работало нормально, за исключением одного случая. Рассматриваемое приложение разделено на несколько библиотек, некоторые из которых загружаются с помощью вызова LoadLibrary()
. Некоторые из этих DLL, загружаемых во время выполнения, зависят от библиотек Qt. В одном случае загруженная DLL зависит от QtXml
, которая сама зависит от QtCore
.
Вот где это становится странным. Приложение зависит от QtCore
, а также загружает библиотеку, зависящую от QtXml
. Приложение и библиотека были собраны со старой версией Qt. Если это приложение запускается только с общим каталогом в PATH, все работает, потому что библиотеки DLL новой версии Qt загружаются из общего каталога. Однако, если PATH содержит каталог, в котором старые библиотеки DLL версии Qt хранятся перед общим каталогом, то загрузка DLL времени выполнения завершится ошибкой с отсутствующими символами.
(Эта ситуация возникает при выполнении автоматизированного модульного тестирования, когда сценарии явно задают PATH для использования конкретной версии библиотеки.)
Насколько я могу судить, приложение загружает старую версию QtCore.dll
, а загружаемая во время выполнения DLL (каким-то образом) загружает новую версию QtXml.dll
, что не удается, потому что уже загруженный QtCore
не имеет нужных символов.
Но это кажется невозможным, поскольку PATH — это что-то вроде c:\qt\qt-4.5.2\lib;c:\common\lib
(плюс другие несвязанные пути). Если я удалю более новую версию QtXml
из общего каталога lib (не заменю ее старой версией, а просто удалю), то LoadLibrary()
преуспеет, потому что она загружает версию 4.5.2 всех библиотек Qt. Но это не очень хорошее долгосрочное решение, так как запуск без каталога конкретной версии Qt в PATH (общий) не сможет найти QtXml
.
Как это могло произойти? Как может LoadLibrary()
(или что-то, что он рекурсивно вызывает для разрешения зависимостей библиотеки) загрузить библиотеку из позже в PATH
? Я не могу найти ничего, что указывало бы на то, что каталогу общей библиотеки уделяется особое внимание (это не установленный каталог DLL). Это не упоминается в процессе сборки, это просто то, что разработчики имеют в своем PATH
для удобства.
Кстати, аналогичная ситуация существует в Linux с LD_LIBRARY_PATH
и dlopen()
, и там все работает отлично. Это то, что Windows делает по-другому, чего я не понимаю. Кто-нибудь знает, что может пойти не так?