В чем разница между статической и динамической библиотекой
Что проверяют
Понимаете ли вы, что происходит между компилятором, линкером и загрузчиком ОС, а не только помните «статическая больше, динамическая меньше». Следом обычно спрашивают про ABI или про то, как программа находит .so при запуске.
Как отвечать
Разведите два момента связывания:
- статическая библиотека (
.aв Linux,.libв MSVC): архив объектных файлов. Линкер при сборке берёт из него только нужные объектники и вшивает в исполняемый файл. Внешних зависимостей при запуске нет, но исправление бага в библиотеке требует пересборки всех программ с ней; - динамическая библиотека (
.so,.dll,.dylib): отдельный файл, который при запуске подгружает динамический загрузчик (ld-linux.soв Linux). Символы разрешаются при старте или лениво, при первом вызове через PLT/GOT. Код в памяти разделяется между процессами, обновить библиотеку можно заменой файла, если не сломан ABI.
Дальше конкретика, которая отличает практика:
- поиск библиотек:
RPATH/RUNPATH,LD_LIBRARY_PATH,ldconfig. Зависимости смотрят черезldd, экспортируемые символы черезnm -D; - явная загрузка:
dlopen/dlsymилиLoadLibrary/GetProcAddressдля плагинов; - ABI в C++: смена компилятора, стандартной библиотеки или раскладки класса ломает совместимость, поэтому наружу часто выставляют C-интерфейс через
extern "C"или прячут поля за pimpl; - видимость символов:
-fvisibility=hiddenи явный экспорт уменьшают таблицу символов и ускоряют загрузку.
Итог: статика удобна для самодостаточных утилит и контейнеров, динамика нужна для плагинов, общих системных библиотек и лицензий вроде LGPL.
Где спотыкаются
Говорят, что при статической линковке в бинарник попадает «вся библиотека целиком». Линкер берёт только объектные файлы, на которые есть ссылки.
Считают замену .so всегда безопасной. Если поменялся ABI, например в класс из заголовка добавилось поле, программа упадёт или тихо испортит память без ошибки при запуске.
Путают порядок библиотек в команде линковки. GNU ld обрабатывает статические библиотеки слева направо, и -lfoo перед объектником, который её использует, даёт «undefined reference».