Страницы

Поиск по вопросам

понедельник, 15 октября 2018 г.

Размещение файлов библиотек в подкаталоге

Как собрать программу на 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, например, указав имя файла ресурсов в списке исходников).

Комментариев нет:

Отправить комментарий