Использование сторонних библиотек, Как использовать функции из .dll? |
Здравствуйте, гость ( Вход | Регистрация )
Использование сторонних библиотек, Как использовать функции из .dll? |
Iron Bug |
22.4.2010, 23:36
Сообщение
#21
|
Профессионал Группа: Модератор Сообщений: 1611 Регистрация: 6.2.2009 Из: Yekaterinburg Пользователь №: 533 Спасибо сказали: 219 раз(а) Репутация: 12 |
ну вот тебе кусок из реального проекта. весь не привожу - там дохрена и файлов, и вызовов. но не важно.
(тут libftdi - библиотека драйвера для одной микросхемы) Раскрывающийся текст
(тут много дополнительных мелких ухищрений: просто у меня уже есть стандартизированный подход к работе с разными библиотеками и мне так привычнее. но не суть.) вот это компилится без единого упоминания .a файла. линкуется с dl (ну там ещё rt и pthread, но это не существенно для примера). я и libftdi.а и libftdi.la убрала вообще из /usr/lib и больше их нет нигде и доступа к ним нет вообще - они под рута убраны. остались только libftdi.so файлы. однако, компилится и рекомпилится с нуля - будь здоров! потому что для работы с .so нужны только имена точек входа и имя самой .so библиотеки. и это у меня не один проект, а куча разных проектов, для разных девайсов. аналогично и под вендой на работе. там те же самые девайсы, те же библиотеки. и всё собирается без статики. такой же модуль под венду для этой железяки также динамически через вендозные функции грузит точки входа. я на память не вспомню как в венде вызываются загрузка и линковка входов, но всё совершенно аналогично. и .lib там тоже не нужен. Сообщение отредактировал Iron Bug - 22.4.2010, 23:43 |
|
|
BRE |
23.4.2010, 6:29
Сообщение
#22
|
Профессионал Группа: Участник Сообщений: 1112 Регистрация: 6.3.2009 Из: Ростов-на-Дону Пользователь №: 591 Спасибо сказали: 264 раз(а) Репутация: 44 |
Мы говорим про венду! Посмотри внимательно, что какие файлы генерируются вместе с dll. dll нельзя слинковать с exe.
Сообщение отредактировал BRE - 23.4.2010, 6:30 |
|
|
Litkevich Yuriy |
23.4.2010, 8:27
Сообщение
#23
|
разработчик РЭА Группа: Сомодератор Сообщений: 9669 Регистрация: 9.1.2008 Из: Тюмень Пользователь №: 64 Спасибо сказали: 807 раз(а) Репутация: 94 |
|
|
|
BRE |
23.4.2010, 8:57
Сообщение
#24
|
Профессионал Группа: Участник Сообщений: 1112 Регистрация: 6.3.2009 Из: Ростов-на-Дону Пользователь №: 591 Спасибо сказали: 264 раз(а) Репутация: 44 |
ты имеешь в виду статически? Назовем это динамической линковкой. Например, так линкуются QtCore, QtGui, ... Мы не пишем код, который загружает эти библиотеки и настраивает адреса функций. Все это делает загрузчик, и если одной из dll не будет найдено, то еще до входа в main мы получим сообщение от загрузчика, что данная программа не может быть выполнена. В линукс линкер может работать напрямую с so-файлами, в венде же вместе с dll, генерируется небольшой файл lib (.a), который линкер использует при компоновке. Другой путь использовать dll, это загрузка его руками в своем коде, резольвинг необходимых функций и их использование. Для этого способа, этот файл lib (.a) не нужен, и программа будет запущенна даже если его нет (загрузчик про него ничего не знает и соответственно искать не будет). Это вариант для плагинов. |
|
|
Tonal |
23.4.2010, 9:02
Сообщение
#25
|
Активный участник Группа: Участник Сообщений: 452 Регистрация: 6.12.2007 Из: Новосибирск Пользователь №: 34 Спасибо сказали: 69 раз(а) Репутация: 17 |
В винде не все линкеры умеют пользоваться символами напрямую из dll-ки.
Например MSVC не умел - сейчас не знаю. Старый mingw не умел - сейчас научили. Кроме того он понимает импортные либки от MSVC. Багланд - не помню, вроде умеет. Причём обычно библиотеки импорта (т. е. либки, которые для линковки с dll-ками) действительно содержат только перечень экспортируемых символов, что делает их довольно бессмысленными и легко конвертируемыми между разными форматами. Но несколько раз мне встречались импортные либки, которые содержали ещё что-то, т. е. конвертировать их не удавалось... |
|
|
Iron Bug |
23.4.2010, 11:56
Сообщение
#26
|
Профессионал Группа: Модератор Сообщений: 1611 Регистрация: 6.2.2009 Из: Yekaterinburg Пользователь №: 533 Спасибо сказали: 219 раз(а) Репутация: 12 |
Мы говорим про венду! Посмотри внимательно, что какие файлы генерируются вместе с dll. dll нельзя слинковать с exe. ..ять! я уже три раза сказала, что разницы нет. под вендой и линём это совершенно одинаковые схемы. это не линковка, а динамическая загрузка. разные вещи. я десять лет пишу такие проги, а ты мне тут говоришь, что нельзя каждый день я загружаю десятки разных сторонних библиотек для железа и всё нормально. а ты сейчас доказываешь мне, что все десять лет у меня ничего не работало. точно так же - LoadLibrary и вперёд с песнями. и не нужно там ничего больше, кроме загрузки и линковки входов. а как ваша QT устроена - этого я не знаю и это частные проблемы этой библиотеки. скорее всего, и её можно также грузить. просто для упрощения придумали автозагрузку и какую-нибудь инициализацию в виде статически линкующегося к коду куска. вот кусок из работающего проекта, который знать не знает про lib'ы, линкует только стандартные библиотеки и прекрасно живёт, подключаясь к Ftd2xx.dll: Раскрывающийся текст
совершенно та же фигня. только dlopen заменён на LoadLibrary, а dlsym на GetProcAddress. ну выгрузка библиотеки в обоих примерах пропущена, но она такая же аналогичная. Сообщение отредактировал Iron Bug - 23.4.2010, 11:59 |
|
|
BRE |
23.4.2010, 12:21
Сообщение
#27
|
Профессионал Группа: Участник Сообщений: 1112 Регистрация: 6.3.2009 Из: Ростов-на-Дону Пользователь №: 591 Спасибо сказали: 264 раз(а) Репутация: 44 |
Iron Bug, ты все динамические библиотеки загружаешь руками с помощью LoadLibrary и получаешь адреса их функций? Или все таки есть такие, которые "кто-то" загружает за тебя (например msvcrt.dll)? А как происходит процесс линковки таких библиотек?
Раньше все, сейчас (как сообщих Tonal) некоторые, линкеры использовали для этого специальную библиотеку импорта... Ну вроде все это уже несколько раз описано выше, не буду повторяться. То, что ты не замечаешь как происходит этот процесс заслуга компилятора. Кстати, каким пользуешься? |
|
|
Iron Bug |
23.4.2010, 13:52
Сообщение
#28
|
Профессионал Группа: Модератор Сообщений: 1611 Регистрация: 6.2.2009 Из: Yekaterinburg Пользователь №: 533 Спасибо сказали: 219 раз(а) Репутация: 12 |
Iron Bug, ты все динамические библиотеки загружаешь руками с помощью LoadLibrary и получаешь адреса их функций? Или все таки есть такие, которые "кто-то" загружает за тебя (например msvcrt.dll)? А как происходит процесс линковки таких библиотек? msvcrt загружает только основной модуль. он прикрепляет к юзерскому коду заголовок для загрузчика и прописывает основную точку входа(но и это можно сделать вручную, если нужно). остальные загрузки по ходу работы - см. приведённый код. динамическая загрузка вызовом LoadLibrary(она вызывается из Kernel32.dll), по которому в системе происходит загрузка библиотеки в память и вызов внутреннего метода библиотеки init (под вендой название точно не помню, но если сам пишешь dll, которой нужна инициализация - то его надо писать вручную, а если нет - то компилятор по типу собираемого модуля dll сам его прилепит, сгенерировав по умолчанию). после вызова этой функции и линковки точек входа библиотека готова к работе. и неважно, каким компилятором она собрала. если имена точек входа указаны без декораций(а для этого прописывается файл экспорта при сборке библиотеки), то это работает. и даже если пересобрать библиотеку, добавить что-то, то ничего не изменится, пока указанные имена входов и их параметры остались теми же. производители аппаратуры так и делают, чтобы расширять свои библиотеки для новых версий. потому что иначе после каждого апдейта зависимый код пришлось бы перекомпилять из-за линковки по номерам входов. а так, один раз написал, отправил юзеру и пускай он себе обновляет дрова - для модуля ничего не изменится, пока интерфейс совместим. Сообщение отредактировал Iron Bug - 23.4.2010, 13:56 |
|
|
BRE |
23.4.2010, 14:07
Сообщение
#29
|
Профессионал Группа: Участник Сообщений: 1112 Регистрация: 6.3.2009 Из: Ростов-на-Дону Пользователь №: 591 Спасибо сказали: 264 раз(а) Репутация: 44 |
и неважно, каким компилятором она собрала. если имена точек входа указаны без декораций(а для этого прописывается файл экспорта при сборке библиотеки), то это работает. и даже если пересобрать библиотеку, добавить что-то, то ничего не изменится, пока указанные имена входов и их параметры остались теми же. производители аппаратуры так и делают, чтобы расширять свои библиотеки для новых версий. потому что иначе после каждого апдейта зависимый код пришлось бы перекомпилять из-за линковки по номерам входов. а так, один раз написал, отправил юзеру и пускай он себе обновляет дрова - для модуля ничего не изменится, пока интерфейс совместим. Да это все понятно, никто и не говорит обратного. Это базовые понятия про разделяемые библиотеки... Вот ключевой момент: msvcrt загружает только основной модуль. он прикрепляет к юзерскому коду заголовок для загрузчика и прописывает основную точку входа(но и это можно сделать вручную, если нужно). А кто прикрепляет к юзерскому коду заголовок (а точнее таблицу импорта)? И откуда эта таблица берется? А делает это линкеры, и по крайней, мере большей их части нужна для этого библиотека импорта. При старте процесса, еще до передачи управления в функцию _main, загрузчик загружает dll используя LoadLibrary, резолвит нужные функции и уже в памяти настраивает эти таблицы импорта для процесса. |
|
|
Iron Bug |
23.4.2010, 14:29
Сообщение
#30
|
Профессионал Группа: Модератор Сообщений: 1611 Регистрация: 6.2.2009 Из: Yekaterinburg Пользователь №: 533 Спасибо сказали: 219 раз(а) Репутация: 12 |
А кто прикрепляет к юзерскому коду заголовок (а точнее таблицу импорта)? И откуда эта таблица берется? см. код. когда ты линкуешь метод, вызывая GetProcAddress - система просматривает внутреннюю таблицу экспорта dll и, если находит метод с запрашиваемым именем, то подгружает его. имя это ты можешь выбирать вообще динамически. то есть, ты можешь написать программу для выполнения любого метода любой библиотеки, задавая их через юзерский интерфейс. и никакие lib'ы и статическая информация тут не нужны. в этом случае на этапе компиляции и линковки никаких предположений об адресе функции не делается вообще. я знаю, что именно ты путаешь с динамической загрузкой. есть т.н. динамическая линковка. но это линковка по номерам входов. загрузка библиотеки происходит при загрузке основного модуля (msvcrt генерит автоматический код) и в модуле буквально прописываются связи типа "вызов метода номер 2 из библиотеки такой-то". и вот именно для этого и нужны эти самые таблицы импорта. но это не универсальный метод, в том смысле, что при существенных изменениях в библиотеке номера входов могут меняться и тогда кердык всем зависящим от этих номеров приложениям. при этом при смещении номеров происходит вызов не той функции (причём система не проверяет этого) и программа чаще всего просто падает с access voilation. мелкософт обозвали это явление hell dll и начали городить огород с системой хранения версий в весьма дурацком стиле. а в линюксе для этого изначально были методы (приписывание версии к названию .so библиотеки). кроме этого, есть ещё гарантированно работающая статическая линковка, понятное дело. так что таблицы экспорта - это полумера и она работает в весьма ограниченном диапазоне, хотя и куда легче в реализации, потому что компилятор сам всё делает за программиста. Сообщение отредактировал Iron Bug - 23.4.2010, 14:29 |
|
|
Текстовая версия | Сейчас: 23.11.2024, 3:08 |