Как собрать программу на C++ c загружаемыми модулями таким образом, чтобы приложение находило файлы библиотечных модулей не в каталоге запуска, а в отдельном подкаталоге? Например, исполняемому файлу для работы требуется библиотечный файл "db2.dll", который расположен в папке "libs":
Application
|
+-- main.exe
+-- config.txt
+-- libs
|
+-- net.dll
+-- db2.dll
Вопрос относится только к сборке приложений для ОС MS-Windows в разных компиляторах/сборщиках (MS-VC, MinGW, CodeBlocks и т.д.). Под Linux/Unix/*BSD для таких случаев просто используется параметр компилятора (линковщика): "-Wl,-rpath,./libs"
Ответ
Как ни странно, задача имеет решение и библиотеки, необходимые для приложения действительно можно положить в отдельный каталог и при этом не использовать динамическую загрузку библиотек, используя только статическое связывание. Это делается при помощи так называемых Assemblies (сборок), поддержка которых появилась в Windows XP
Вкратце технология выглядит следующим образом. В исполняемый файл приложения внедряется манифест-файл, который предписывает приложению использовать некоторую сборку. Загрузчик исполняемых файлов читает этот манифест и ищет каталог со сборкой, причём среди путей поиска присутствует и каталог с исполняемым файлом приложения.
Теперь более подробно, на примере и в деталях.
Создадим простейшее приложение на C++
#include
int main(int, char*[]) {
std::cout << "Hello, World!" << std::endl;
}
Будучи скомпилированным при помощи компилятора MinGW (MinGW-builds 6.3.0), это приложение в моём случае требует для своей работы файлы libgcc_s_sjlj-1.dll, libstdc++-6.dll и libwinpthread-1.dll. При этом сам исполняемый файл импортирует только libstdc++-6.dll, которая, в свою очередь, импортирует две остальные. Назовём нашу "сборку", например, libs, создадим в каталоге с основным исполняемым файлом нашего приложения каталог libs и разместим внутри него три обозначенных выше DLL.
Далее создаём манифест. Имя файла манифеста должно состоять из имени сборки и иметь расширение .manifest, т.е., в нашем случае, libs.manifest. Содержимое файла должно быть следующим:
Особо следует отметить, что хотя наше приложение импортирует только одну библиотеку, в манифесте нужно прописать все, иначе приложение работать не будет. Таким образом, у нас получилась следующая структура каталогов и файлов (app.exe - имя нашего приложения):
├─ app.exe
└─ libs
├─ libs.manifest
├─ libgcc_s_sjlj-1.dll
├─ libstdc++-6.dll
└─ libwinpthread-1.dll
И, наконец, финальный аккорд! Создаём манифест, который будем внедрять в наше приложение. Пусть он лежит в файле с именем manifest.xml
Параметры сборки, указанные в этом манифесте, должны совпадать с теми, что мы указали ранее. Теперь осталось только создать файл ресурсов, в котором указать на наш манифест
#include
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "manifest.xml"
и прикомпоновать его к приложению (в случае CMake, например, указав имя файла ресурсов в списке исходников).
Комментариев нет:
Отправить комментарий