#cpp #c #dll
Как собрать программу на 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"
Ответы
Ответ 1
Как ни странно, задача имеет решение и библиотеки, необходимые для приложения действительно можно положить в отдельный каталог и при этом не использовать динамическую загрузку библиотек, используя только статическое связывание. Это делается при помощи так называемых Assemblies (сборок), поддержка которых появилась в Windows XP. Вкратце технология выглядит следующим образом. В исполняемый файл приложения внедряется манифест-файл, который предписывает приложению использовать некоторую сборку. Загрузчик исполняемых файлов читает этот манифест и ищет каталог со сборкой, причём среди путей поиска присутствует и каталог с исполняемым файлом приложения. Теперь более подробно, на примере и в деталях. Создадим простейшее приложение на C++: #includeint 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, например, указав имя файла ресурсов в списке исходников). Ответ 2
Как вариант можно слинковать библиотеку вручную во время исполнения функциями: LoadLibraryW, GetProcAddress, FreeLibrary. Пример: #includeint main() { typedef void (*fn_t)(int a); HANDLE const dll = LoadLibraryW(L"libs\net.dll"); if (dll == NULL) { return EXIT_FAILURE; } fn_t fn = (fn_t)GetProcAddress(dll, "func_name"); if (fn == NULL) { FreeLibrary(dll); return EXIT_FAILURE; } fn(123); FreeLibrary(dll); return EXIT_SUCCESS; }
Комментариев нет:
Отправить комментарий