Подтвердить что ты не робот

Общие библиотеки: метод Windows vs Linux

У меня есть быстрый вопрос об общих библиотеках Windows (DLL) и общих библиотеках Linux (SO).

Почему при создании Windows DLL требуется, чтобы клиентская программа также ссылалась на статическую библиотеку (файл .lib), но приложения, созданные в Linux, не требуют связывания с такой статической библиотекой.

Имеет ли это какое-либо отношение к переносу кода и тому подобное? Спасибо.

4b9b3361

Ответ 1

На самом деле не с перестановкой кода, это совершенно другая проблема. Речь идет о различии в архитектуре:

  • В Windows, DLL похожа на исполняемые файлы (EXE). Основное различие между EXE и DLL заключается в том, что EXE имеет точку входа (главная/функция WinMain), и поэтому ее можно использовать для запуска процесса, в то время как библиотеки DLL могут быть загружены только в уже существующий процесс. Но см. (1)

  • В Linux работа .so похожа на статическую библиотеку (.a). Основное отличие состоит в том, что файл .so может быть связан с запущенной программой, а файл .a может быть связан только при компиляции программы.

Следствием этого подхода является то, что в linux один и тот же файл может использоваться для создания и запуска программы. Но в Windows вам нужна соответствующая библиотека (LIB), чтобы связать программу. На самом деле lib, который соответствует DLL, обычно имеет не что иное, как имена функций, чтобы удовлетворить компоновщик, и заглушки для перемещения. Но см. (2)

(1) Ну, библиотеки DLL тоже имеют точку входа, но она не используется в качестве основной функции, как какой-то способ инициализации/финализации.

(2) Некоторые линкеры достаточно умны, чтобы в некоторых простых случаях могли ссылаться на DLL, используя самую DLL, без необходимости в дополнительном файле LIB. Я думаю, что, по крайней мере, это может сделать линкер MinGW.

Ответ 2

Почему при создании Windows DLL требуется, чтобы клиентская программа также ссылалась на статическую библиотеку (файл .lib), но приложения, созданные в Linux, не требуют связывания с такой статической библиотекой.

Это историческое дизайнерское решение, принятое Microsoft, чтобы компоновщик мог добавлять ссылки DLL в исполняемый файл, не имея конкретной версии DLL, присутствующей во время ссылки. Причиной этого было то, что всегда были разные версии Windows, с разными версиями DLL. Также в то время Microsoft сотрудничала с IBM в OS/2, и план заключался в том, что программы Windows могут быть выполнены и на OS/2. Ну, Microsoft решила "backstab" OS/2, скопировав собственную профессиональную ОС на основе ядра NT. Но это означало, что для разработки вы хотели, чтобы разработчики могли ссылаться на системные DLL, не имея всех разных вариантов DLL. Вместо этого для создания как DLL, так и исполняемых файлов (оба находятся в формате PE) вместо этого используется "шаблон" динамической привязки, которые являются этими конкретными файлами .lib, которые вообще не являются библиотеками, а просто символическими и порядковыми таблицами (это малоизвестный факт, но PE-двоичные символы могут быть загружены не только строковым идентификатором, но и целым числом, так называемым порядковым номером).

Побочным эффектом ординалов является то, что они позволяют скрыть человекочитаемые символы, чтобы вы могли использовать DLL только в том случае, если знали связь с порядковым номером ← →.

В Unix традиция заключалась в том, что "вы создаете ее в системе, в которой собираетесь ее запускать", или "у вас есть все целевые системные файлы на месте". Таким образом, никогда не было стимулов, поэтому отдельные библиотеки и информации о связях. Технически то же самое будет работать и для DLL. PE могут экспортировать таблицу символов и перемещений, какие DLL файлы делать, а компоновщик может захватить всю требуемую им информацию, просто отлично.

Если вы должны были скрывать символы с общими объектами Unix, вы обычно делаете это, используя один struct со всеми указателями функций в нем и экспортируете только глобальный постоянный экземпляр этой структуры по имени, который содержит много явно не указанных указателей. Однако вы могли бы сделать то же самое с DLL файлами Windows.

TL; DR: Причина этого не техническая, а решение о маркетинге и распределении.

Ответ 3

В Windows клиентская программа не нуждается в связывании со статической библиотекой для доступа к функциям в DLL. Динамическое связывание может происходить полностью во время выполнения без клиентской программы, даже осознавая существование DLL во время ее компиляции.

Например, если вы хотите вызвать имя функции "foo" в DLL с именем "bar.dll", вы можете написать такой код:

HINSTANCE hinst = LoadLibrary("bar.dll");
FARPROC foo = GetProcAddress(hinst, "foo");
foo();

И "foo" и "bar.dll" могли бы легко быть значениями, которые были установлены только во время выполнения, скажем, через файл конфигурации или какой-либо другой пользовательский ввод.

Цель статической библиотеки - автоматизировать этот процесс динамической загрузки, создав заглушки, которые кажутся регулярными функциями в отношении клиентской программы, но связаны с DLL во время выполнения. Обычно эта привязка происходит во время загрузки клиентского процесса, но также могут генерироваться библиотеки, которые будут загружаться и связываться по требованию, поэтому DLL не будет загружаться в память до тех пор, пока она не понадобится. Это статическая библиотека, которая определяет, когда происходит соединение.

По большей части, компилятор может автоматически генерировать эти библиотеки, поэтому технически они не нужны при простое подключение к функциям DLL. Однако единственным исключением из этого (что я знаю) является ссылка на общие переменные.

В DLL Windows вы можете создать общий сегмент данных с переменными, к которым можно получить доступ любым процессом, который загрузил эту DLL. Информация о размере и типах этих переменных хранится в связанной статической библиотеке и не может быть определена только из библиотеки DLL. Чтобы получить доступ к этим переменным, клиентская программа должна ссылаться на статическую библиотеку для этой DLL.

Насколько мне известно, Linux Shared Libraries не поддерживают такую ​​концепцию.

Обновление

Следует также упомянуть, что в Windows можно создать DLL, где точки входа функции экспортируются только порядковым номером (числом), а не именем. Это можно рассматривать как форму скрытия данных и обычно используется, когда разработчик хочет, чтобы некоторые функции оставались частными.

Кто-то, у кого есть доступ к статической библиотеке, сможет вызвать эти функции по имени, поскольку в библиотеке будут данные, связывающие имя функции с соответствующим порядковым номером. Любой, у кого была только DLL, пришлось бы вручную ссылаться на функции по порядку или создавать свою собственную статическую библиотеку с созданными именами.