crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )


  Ответ в Использование сторонних библиотек
Введите ваше имя
Подтвердите код

Введите в поле код из 6 символов, отображенных в виде изображения. Если вы не можете прочитать код с изображения, нажмите на изображение для генерации нового кода.
 

Опции сообщения
 Включить смайлы?
Иконки сообщения
(Опционально)
                                
                                
  [ Без иконки ]
 


Последние 10 сообщений [ в обратном порядке ]
Tonal Дата 26.4.2010, 7:48
 
Цитата(Iron Bug @ 23.4.2010, 21:57) *
ну тут я просто неточно выразилась. на самом деле, линкер тащит прототип загрузчика из msvcrt и прилепляет его к модулю. а в kernel32 хранится та самая функция, которая загружает динамически библиотеку при вызове LoadLibrary и выполняет динамическую линковку точек входа при выполнении программы.

И опять ты не точно выразилась. :)
msvcrt - это Microsoft C Runtime Libraryю там сидят функции рантайма типа fopen и abort.
А к модулю прицепляется стартовая функция, которая потом вызывает main, или, если модуль собирается в dll-ку, то DllEntryPoint.
Эти стартовые функции свои для каждого компилятора и живут в статических библиотеках.

Цитата(Iron Bug @ 23.4.2010, 21:57) *
я не буду спорить. если хочется зависимости от версии драйвера - делайте как хотите. линкуйте через таблицы импорта. дело ваше. я пояснила, в чём вред такого метода. по-моему, написать пару лишних строк кода и отделаться от перекомпиляции приложения под каждую новую dll от производителя дров - не такая уж плохая идея.

Динамическая линковка возможна как по ординалам, так и по именам.
По именам - по умолчанию, если есть и то и другое.
Т. е. перелинковывать приложение при изменении dll-ки требуется только в том случае, если изменились имена и/или сигнатуры.
Но в этом случае тебе всё равно придётся не только перелинковывать, но корректировать текст вызова и перекомпилять приложение.

Фича динамической линковки в том, что если при старте все указанные dll-ки подгружаются и их импорты разрешаются (резольвятся).
И при обломе приложение не стартует.
Явный минус в том, что на это тратится время и память на старте и dll-ка постоянно висит в памяти, даже в случае, когда она нужна только какой-нибудь редкой и экзотической функции.
Когда это становится критичным, например с плагинами, применяют динамическую загрузку.
Да, в винде есть ещё механизм отложенной загрузки - когда dll-ка подгружается системой не при старте а при первом обращении.

Перечитай Джеффри Рихтер-а "Windows для профессионалов" - там очень подробно описано про динамическую линковку. :)
Litkevich Yuriy Дата 23.4.2010, 20:48
  Тему разделил: Сборка библиотеки под ОС Symbian
Iron Bug Дата 23.4.2010, 17:57
  я вообще-то изначально отвечала на исходный вопрос.
Цитата(azure @ 22.4.2010, 14:52) *
Имеется девайс (pci-карта gpib) с драйверами и .dll + .h с функциями работы с устройством. dll идут под MS Visual C++ и Borland C++ Builder. Можно ли использовать эти .dll без использования вышеуказанных компиляторов? Конкретно интересует gcc/mingw? Если можно, то как?

так как были даны неверные ответы про необходимость lib'ов, я ответила, что да, можно. и привела примеры. у меня интелловский компилятор вполне нормально общается с любыми dll под венду, при этом для работы требуются только заголовочники и сама dll.
Цитата(BRE @ 23.4.2010, 17:46) *
Ни msvcrt.dll, ни kernel32.dll, ни какая другая dll ничего генерить уже не может, генерть может линкер, основываясь на этих самых библиотеках импорта или новые линкеры, которые по сути сами формируют таблицу импорта без генерации этих библиотек.

ну тут я просто неточно выразилась. на самом деле, линкер тащит прототип загрузчика из msvcrt и прилепляет его к модулю. а в kernel32 хранится та самая функция, которая загружает динамически библиотеку при вызове LoadLibrary и выполняет динамическую линковку точек входа при выполнении программы.

я не буду спорить. если хочется зависимости от версии драйвера - делайте как хотите. линкуйте через таблицы импорта. дело ваше. я пояснила, в чём вред такого метода. по-моему, написать пару лишних строк кода и отделаться от перекомпиляции приложения под каждую новую dll от производителя дров - не такая уж плохая идея.
BRE Дата 23.4.2010, 14:46
 
Цитата(Iron Bug @ 23.4.2010, 15:29) *
я знаю, что именно ты путаешь с динамической загрузкой. есть т.н. динамическая линковка.

Я путаю? Перечитай мои посты, по-моему это ты путаешь. ;)
Я тут про динамическую линковку и распинаюсь, а ты мне какие-то базовые понятия про разделяемые библиотеки пишешь. :)

Цитата(Iron Bug @ 23.4.2010, 15:29) *
но это линковка по номерам входов. загрузка библиотеки происходит при загрузке основного модуля (msvcrt генерит автоматический код)

Ни msvcrt.dll, ни kernel32.dll, ни какая другая dll ничего генерить уже не может, генерть может линкер, основываясь на этих самых библиотеках импорта или новые линкеры, которые по сути сами формируют таблицу импорта без генерации этих библиотек.

Цитата(Iron Bug @ 23.4.2010, 15:29) *
но это не универсальный метод, в том смысле, что при существенных изменениях в библиотеке номера входов могут меняться и тогда кердык всем зависящим от этих номеров приложениям.

Мы говорим не о плюсах/минусах, а о том как это происходит и почему/зачем вместе с dll генерируется файл .lib (.a).

Фух. :)
Iron Bug Дата 23.4.2010, 14:29
 
Цитата(BRE @ 23.4.2010, 17:07) *
А кто прикрепляет к юзерскому коду заголовок (а точнее таблицу импорта)? И откуда эта таблица берется?

см. код. когда ты линкуешь метод, вызывая GetProcAddress - система просматривает внутреннюю таблицу экспорта dll и, если находит метод с запрашиваемым именем, то подгружает его. имя это ты можешь выбирать вообще динамически. то есть, ты можешь написать программу для выполнения любого метода любой библиотеки, задавая их через юзерский интерфейс. и никакие lib'ы и статическая информация тут не нужны. в этом случае на этапе компиляции и линковки никаких предположений об адресе функции не делается вообще.
я знаю, что именно ты путаешь с динамической загрузкой. есть т.н. динамическая линковка. но это линковка по номерам входов. загрузка библиотеки происходит при загрузке основного модуля (msvcrt генерит автоматический код) и в модуле буквально прописываются связи типа "вызов метода номер 2 из библиотеки такой-то". и вот именно для этого и нужны эти самые таблицы импорта. но это не универсальный метод, в том смысле, что при существенных изменениях в библиотеке номера входов могут меняться и тогда кердык всем зависящим от этих номеров приложениям. при этом при смещении номеров происходит вызов не той функции (причём система не проверяет этого) и программа чаще всего просто падает с access voilation. мелкософт обозвали это явление hell dll и начали городить огород с системой хранения версий в весьма дурацком стиле. а в линюксе для этого изначально были методы (приписывание версии к названию .so библиотеки).
кроме этого, есть ещё гарантированно работающая статическая линковка, понятное дело.

так что таблицы экспорта - это полумера и она работает в весьма ограниченном диапазоне, хотя и куда легче в реализации, потому что компилятор сам всё делает за программиста.
BRE Дата 23.4.2010, 14:07
 
Цитата(Iron Bug @ 23.4.2010, 14:52) *
и неважно, каким компилятором она собрала. если имена точек входа указаны без декораций(а для этого прописывается файл экспорта при сборке библиотеки), то это работает. и даже если пересобрать библиотеку, добавить что-то, то ничего не изменится, пока указанные имена входов и их параметры остались теми же.
производители аппаратуры так и делают, чтобы расширять свои библиотеки для новых версий. потому что иначе после каждого апдейта зависимый код пришлось бы перекомпилять из-за линковки по номерам входов. а так, один раз написал, отправил юзеру и пускай он себе обновляет дрова - для модуля ничего не изменится, пока интерфейс совместим.

Да это все понятно, никто и не говорит обратного. Это базовые понятия про разделяемые библиотеки...

Вот ключевой момент:
Цитата(Iron Bug @ 23.4.2010, 14:52) *
msvcrt загружает только основной модуль. он прикрепляет к юзерскому коду заголовок для загрузчика и прописывает основную точку входа(но и это можно сделать вручную, если нужно).

А кто прикрепляет к юзерскому коду заголовок (а точнее таблицу импорта)? И откуда эта таблица берется? :)
А делает это линкеры, и по крайней, мере большей их части нужна для этого библиотека импорта.

При старте процесса, еще до передачи управления в функцию _main, загрузчик загружает dll используя LoadLibrary, резолвит нужные функции и уже в памяти настраивает эти таблицы импорта для процесса.
Iron Bug Дата 23.4.2010, 13:52
 
Цитата(BRE @ 23.4.2010, 15:21) *
Iron Bug, ты все динамические библиотеки загружаешь руками с помощью LoadLibrary и получаешь адреса их функций? Или все таки есть такие, которые "кто-то" загружает за тебя (например msvcrt.dll)? А как происходит процесс линковки таких библиотек?

msvcrt загружает только основной модуль. он прикрепляет к юзерскому коду заголовок для загрузчика и прописывает основную точку входа(но и это можно сделать вручную, если нужно). остальные загрузки по ходу работы - см. приведённый код. динамическая загрузка вызовом LoadLibrary(она вызывается из Kernel32.dll), по которому в системе происходит загрузка библиотеки в память и вызов внутреннего метода библиотеки init (под вендой название точно не помню, но если сам пишешь dll, которой нужна инициализация - то его надо писать вручную, а если нет - то компилятор по типу собираемого модуля dll сам его прилепит, сгенерировав по умолчанию). после вызова этой функции и линковки точек входа библиотека готова к работе. и неважно, каким компилятором она собрала. если имена точек входа указаны без декораций(а для этого прописывается файл экспорта при сборке библиотеки), то это работает. и даже если пересобрать библиотеку, добавить что-то, то ничего не изменится, пока указанные имена входов и их параметры остались теми же.
производители аппаратуры так и делают, чтобы расширять свои библиотеки для новых версий. потому что иначе после каждого апдейта зависимый код пришлось бы перекомпилять из-за линковки по номерам входов. а так, один раз написал, отправил юзеру и пускай он себе обновляет дрова - для модуля ничего не изменится, пока интерфейс совместим.
BRE Дата 23.4.2010, 12:21
  Iron Bug, ты все динамические библиотеки загружаешь руками с помощью LoadLibrary и получаешь адреса их функций? Или все таки есть такие, которые "кто-то" загружает за тебя (например msvcrt.dll)? А как происходит процесс линковки таких библиотек?

Раньше все, сейчас (как сообщих Tonal) некоторые, линкеры использовали для этого специальную библиотеку импорта... Ну вроде все это уже несколько раз описано выше, не буду повторяться. :)
То, что ты не замечаешь как происходит этот процесс заслуга компилятора. Кстати, каким пользуешься?
Iron Bug Дата 23.4.2010, 11:56
 
Цитата(BRE @ 23.4.2010, 9:29) *
Мы говорим про венду! Посмотри внимательно, что какие файлы генерируются вместе с dll. dll нельзя слинковать с exe.

..ять! я уже три раза сказала, что разницы нет. под вендой и линём это совершенно одинаковые схемы. это не линковка, а динамическая загрузка. разные вещи.
я десять лет пишу такие проги, а ты мне тут говоришь, что нельзя :) каждый день я загружаю десятки разных сторонних библиотек для железа и всё нормально. а ты сейчас доказываешь мне, что все десять лет у меня ничего не работало.
точно так же - LoadLibrary и вперёд с песнями. и не нужно там ничего больше, кроме загрузки и линковки входов.
а как ваша QT устроена - этого я не знаю и это частные проблемы этой библиотеки. скорее всего, и её можно также грузить. просто для упрощения придумали автозагрузку и какую-нибудь инициализацию в виде статически линкующегося к коду куска.
вот кусок из работающего проекта, который знать не знает про lib'ы, линкует только стандартные библиотеки и прекрасно живёт, подключаясь к Ftd2xx.dll:
Раскрывающийся текст
class cFtdiDrv
{
.................
    HMODULE     fthmodule;

    FT_STATUS   ftLoadDLL(void);  

    typedef FT_STATUS (WINAPI *PtrToOpen)(PVOID, FT_HANDLE *);  // определение типа функции (точки входа)
    PtrToOpen pFtOpen; // указатель на функцию для подключения входа

    FT_STATUS ftOpen(PVOID); // обёртка для вызова прилинкованного указателя
................
}

FT_STATUS  cFtdiDrv::ftLoadDLL()
{
    fthmodule = LoadLibrary("Ftd2xx.dll");                          // загрузка Dll по имени
    if(fthmodule == NULL)
    {
         return FT_INVALID_HANDLE;
    }

    pFtOpen = (PtrToOpen)GetProcAddress(fthmodule, "FT_Open");    // подключение указателя к входу библиотеки по имени функции
    if (pFtOpen == NULL)
    {
        return FT_INVALID_HANDLE;
    }
.....
}

FT_STATUS cFtdiDrv::ftOpen(PVOID pvDevice)
{
    if (!pFtOpen)
    {
        return FT_INVALID_HANDLE;
    }
    return (*pFtOpen)(pvDevice, &ftHandle ); // вызов прилинкованной функции через указатель
}

совершенно та же фигня. только dlopen заменён на LoadLibrary, а dlsym на GetProcAddress. ну выгрузка библиотеки в обоих примерах пропущена, но она такая же аналогичная.
Tonal Дата 23.4.2010, 9:02
  В винде не все линкеры умеют пользоваться символами напрямую из dll-ки.

Например MSVC не умел - сейчас не знаю.
Старый mingw не умел - сейчас научили. Кроме того он понимает импортные либки от MSVC.
Багланд - не помню, вроде умеет. :)

Причём обычно библиотеки импорта (т. е. либки, которые для линковки с dll-ками) действительно содержат только перечень экспортируемых символов, что делает их довольно бессмысленными и легко конвертируемыми между разными форматами. :)
Но несколько раз мне встречались импортные либки, которые содержали ещё что-то, т. е. конвертировать их не удавалось...
Просмотр темы полностью (откроется в новом окне)
RSS Текстовая версия Сейчас: 28.3.2024, 19:43