Почему компоновщик С++ требует файлы библиотеки во время сборки, хотя я динамически связываю?
У меня есть исполняемый файл С++, и я динамически связываюсь с несколькими библиотеками (Boost, Xerces-c и custom libs).
Я понимаю, почему мне потребуются файлы .lib/.a, если я захочу статически связать эти библиотеки (соответствующий вопрос SO здесь). Однако зачем мне предоставлять соответствующие файлы библиотеки .lib/.so при связывании моего исполняемого файла, если я динамически связываюсь с этими внешними библиотеками?
Ответы
Ответ 1
Компилятор не знает о динамической компоновке, он просто знает, что существует функция через свой прототип. Линкером нужны файлы lib для разрешения символа. Библиотека для DLL содержит дополнительную информацию, такую как DLL, в которой работают функции и как они экспортируются (по имени, по порядку и т.д.). Файлы lib для DLL содержат гораздо меньше информации, чем файлы lib, содержащие полный объектный код - libcmmt.lib на моей системе - 19,2 МБ, но msvcrt.lib - всего лишь 2,6 МБ.
Обратите внимание, что этой модели компиляции/ссылки сейчас почти 40 лет, и она предшествует динамической компоновке на большинстве платформ. Если бы это было спроектировано сегодня, динамическая компоновка была бы гражданином первого класса (например, в .NET, каждая сборка имеет богатые метаданные, описывающие именно то, что она экспортирует, поэтому вам не нужны отдельные заголовки и библиотеки).
Ответ 2
Раймонд Чен написал пару записей в блогах об этом для Windows. Начните с Классическая модель для компоновки, а затем выполните Почему есть ли у нас библиотеки импорта?.
В итоге история определила компилятор как компонент, который знает о подробной информации о типе, тогда как компоновщик знает только имена символов. Таким образом, компоновщик заканчивает создание .DLL без информации о типе, и поэтому для программ, которые хотят связать с ним, нужны метаданные, чтобы рассказать о том, как экспортируются функции и какие типы параметров они берут и возвращают.
У причины .DLLs нет всей информации, необходимой для связи с ними напрямую, является историческим, а не техническим ограничением.
Ответ 3
С одной стороны, компоновщик вставляет версии библиотек, которые существуют во время ссылки, так что у вас есть шанс, что ваша программа будет работать, если версии библиотек будут обновлены. В системе могут существовать несколько версий разделяемых библиотек.
Ответ 4
У линкера есть задача проверить, что все ваши символы undefined учитываются как со статическим содержимым, так и с динамическим контентом.
По умолчанию, он настаивает на том, чтобы присутствовали все ваши символы.
Однако это только значение по умолчанию. Смотрите -z и --allow-shlib- undefined и друзей.
Ответ 5
Возможно, это динамическое связывание выполняется через библиотеки импорта (перед определением функция имеет __declspec (dllimport)).
Если это так, как компилятор ожидает, что функция __imp_symbol объявлена, и эта функция отвечает за переадресацию вызова в нужную библиотеку, динамически загруженную.
Эти функции генерируются при связывании символов с ключевым словом __declspec (dllimport)
Ответ 6
Вот очень упрощенное описание, которое может помочь. Статическая привязка ставит весь код, необходимый для запуска вашей программы в исполняемый файл, чтобы все было найдено. Динамическое связывание означает, что некоторые из требуемого кода не попадают в исполняемый файл и будут найдены во время выполнения. Где я его найду? Есть ли функция x()? Как сделать вызов функции x()? Это то, что библиотека сообщает компоновщику, когда вы динамически связываете.