Почему динамические библиотеки могут ссылаться на другие библиотеки, а статические - нет? - PullRequest
0 голосов
/ 24 января 2019

Рассмотрим следующую структуру кода:

main.cpp -> depends on libone.a -> depends on libtwo.a

Предположим, что в main.cpp используются только функции из libone.a.Так что реально программист, пишущий main.cpp, действительно заботится только о libone.a.На данный момент они даже не знают, что libone.a зависит от libtwo.a.

Они пытаются скомпилировать свой код следующим образом и получить ошибки компоновщика:

g++ -o main main.cpp -lone

enter image description here - Ошибка!Неопределенные символы!

Это становится проблемой, поскольку, поскольку libone.a зависит от libtwo.a, любой, кто использует libone.a, должен знать об этой зависимости ... Как вы можете себе представить, эта проблема может возникнуть сНАМНОГО больше зависимостей, чем одна библиотека, и может быстро стать связующим кошмаром.


Попытка 1 при решении этой проблемы:

Первой мыслью, решившей эту проблему, было: «Это просто,я просто свяжу libone.a с libtwo.a при компиляции libone.a!

Оказывается, все не так просто, как я надеялся ... При компиляции libone.a нет способаlink libtwo.a. Статические библиотеки не ссылаются ни на что при компиляции, вместо этого все зависимости должны быть связаны при компиляции библиотек в исполняемый файл.

Например, чтобы компилировать main.cpp, чтозависит от статической библиотеки, которая, в свою очередь, зависит от другой статической библиотеки, вы должны связать обе библиотеки. ВСЕГДА.

g++ -o main main.cpp -lone -ltwo


Попытка 2 при решении этой проблемы:

еще один тОн пытался скомпилировать libone в виде динамической библиотеки, которая ссылается на libtwo.a.

Как ни странно, это сработало!После компиляции и компоновки libone.so основная программа должна заботиться только о libone.so и больше не должна знать о libtwo.a.

g++ -o main main.cpp -lone

Success!


После выполнения этого упражнения одна часть все еще отсутствует.Я просто не могу понять причину, по которой статические библиотеки не могут ссылаться в других библиотеках, а динамические могут.На самом деле, динамическая библиотека libone.so не будет компилироваться, пока я не свяжу libtwo.a.Это нормально, хотя, как автор libone.so, я бы знал о его зависимости от libtwo.a - Автор main.cpp, однако, не знал бы.И реально им не нужно знать.

Итак, до реального вопроса ... Почему динамические библиотеки могут ссылаться на другие библиотеки, подобные этим, а статические - нет?Кажется, это очевидное преимущество динамических библиотек перед статическими, но я нигде не упоминал об этом!

Ответы [ 2 ]

0 голосов
/ 25 января 2019

Поскольку ваш вопрос относится к файлам gcc и .so / .a, я предполагаю, что вы используете какой-то вариант Unix, который использует файлы ELF для объектного кода.

После прохождения этогоУпражнение в одной части все еще отсутствует.Я просто не могу понять причину, по которой статические библиотеки не могут ссылаться в других библиотеках, но динамические могут.

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

Фактически динамическая библиотека libone.so не будеткомпилировать, пока я не связал libtwo.a.Это нормально, потому что, как автор libone.so, я бы знал о его зависимости от libtwo.a - однако автор main.cpp не знал бы об этом.И реально они не должны знать.

libone.so, вероятно, компилируется нормально, но не будет связываться без libtwo из-за неразрешенных символов .Поскольку компоновщик должен разрешать все достижимые символы при связывании общей библиотеки, он потерпит неудачу, если не сможет их найти.Поскольку libone.so использует символы в libtwo, компоновщик должен знать о libtwo.a, чтобы найти их.Когда вы связываете статическую библиотеку в разделяемую библиотеку, символы разрешаются путем копирования определений непосредственно в выходной файл совместно используемых объектов, поэтому на данный момент пользователи libone.so не могут быть осведомлены об использовании libtwo, посколькуего символы находятся только в libone.so.

Другой вариант - связать общие библиотеки с другими общими библиотеками.Если вы связываете libtwo.so с libone.so (обратите внимание на суффикс .so), то компоновщик разрешает символы, необходимые для libone, добавляя специальный раздел к выходному файлу общего объекта, который говорит, что ему нужно libtwo.so во время выполнения,Позже, когда ОС загружает libone.so, она знает, что ей также нужно загрузить libtwo.so.И, если ваше приложение использует только libone напрямую, это все, что вам нужно сообщить компоновщику во время сборки, так как он скомпоновает в libone, увидит, что ему нужно libtwo, и рекурсивно разрешит, пока все не будет хорошо.

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

0 голосов
/ 24 января 2019

Статическая библиотека - это просто архив объектных файлов, понятия зависимости нет, потому что она никогда не была связана.

Совместно используемые библиотеки связаны между собой, решая символы, и поэтому могут иметь зависимости.

...