Связывание и размер файла - PullRequest
1 голос
/ 20 сентября 2009

Я начинающий, и вот как я понимаю линковку: статическая линковка копирует только тот код, который фактически используется в исполняемый файл. Динамическое связывание использует .dll, которые могут содержать много кода, который никогда не используется приложением. Пожалуйста, поправьте меня, если я не прав :)

Теперь вот мой вопрос. Я использую библиотеку с открытым исходным кодом в своем приложении, но я буду реализовывать только часть ее функциональности. Чтобы получить окончательный размер моих исполняемых + библиотек как можно меньше, я должен использовать статические или динамические ссылки? Как я могу убедиться, что ненужный код не скопирован?

Спасибо!

Ответы [ 4 ]

4 голосов
/ 20 сентября 2009

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

Однако, поскольку вы, вероятно, будете писать как exe, так и dll (и), вы можете выбрать, что будет экспортироваться, и, следовательно, включать только минимально необходимое.

РЕДАКТИРОВАТЬ : в защите от чтения я отметил, что на самом деле вы рассматриваете возможность использования библиотеки с открытым исходным кодом, поэтому приведенное выше утверждение требует некоторой квалификации.

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

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

В целом, выбор использования динамического линкования или нет, не столь критичен . Эта проблема больше была проблемой в прошлом, с более медленным процессором (следовательно, более длительным временем сборки) и другими ограничениями, касающимися памяти, жесткого диска, а также пропускной способности распределения (с дискетами! И тому подобным ...).

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

  • библиотека DLL является сторонней общедоступной библиотекой DLL (то есть, которую конечные пользователи могут обновлять независимо от вашего собственного цикла обновления)
  • Некоторые части приложения, как правило, не используются, и базовая логика может быть «уложена» в DLL, что приводит к уменьшению общего объема времени выполнения (когда пользователи не используют базовые специализированные / расширенные функции). .
  • программа является частью набора программ, некоторые из которых имеют достаточно общих возможностей, которыми можно поделиться.
  • желательно иметь несколько версий приложения. Например, вы можете реализовать базовую / бесплатную / ограниченную версию приложения и полнофункциональную. Предполагая, что программе удастся вызвать любую версию функций с одним и тем же API, отдельные варианты поведения могут быть инкапсулированы только в DLL, что позволяет платящим пользователям просто загрузить «Premium DLL» и просто заменить другую (без установки). требуется).
  • программное обеспечение является бета-версией, и ожидается, что конечный пользователь (и) отправит несколько ревизий. (как и выше, подкачка dll вместо переустановки - это хорошо).
  • разные части приложения написаны на разных языках. В этом случае часто можно использовать статическое связывание (вынуждая компиляторы согласовывать соглашения о вызовах и тому подобное), но подход DLL также может облегчить это сотрудничество.
  • Программное обеспечение производится разными программистами / командами. DLL обеспечивает неявное разграничение обязанностей.

Может быть еще несколько случаев, но, опять же, если нет какой-то существующей потребности в DLL, статическое связывание так же хорошо.

2 голосов
/ 20 сентября 2009

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

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

* Мне не известны какие-либо компоновщики, которые делают связывают каждую функцию в библиотеке - большие компоновщики (MS, GNU), безусловно, будут связывать минимальное необходимое количество, но это не значит, что там не существует каких-то дерьмовых компоновщиков, которые бы связывали все, независимо от того, используется ли он.

1 голос
/ 20 сентября 2009

Чтобы усложнить ситуацию, есть еще варианты.

Сначала вы можете использовать смесь статических и динамических связей. Нормально динамически связываться с libc и libm вашей целевой системы (базовые библиотеки C и math). Для большинства целевых платформ вы можете гарантировать, что они будут присутствовать в любой функциональной системе. Если их там нет, то ваше приложение не запустится ... но практически ничего другого не будет работать. Не будет никакой оболочки или скриптового движка для запуска вашей программы.

Оттуда это зависит. Например, в программировании на UNIX / Linux с использованием «curses» обычно бы динамически связывались библиотеки curses или ncurses . Тем не менее, были некоторые версии curses, в которых были дополнительные библиотеки, предлагающие абстракции более высокого уровня (например, «pads»). Лучше всего статически связать только эти дополнительные биты с вашим исполняемым файлом, чтобы вы навязали пользователям на одну зависимость меньше.

Другой формой динамического связывания является динамическое связывание во время выполнения (через dlopen () и связанные с ним функции). В этом случае вы выборочно открываете и связываетесь с различными библиотеками в зависимости от ваших собственных параметров конфигурации, обработки команд и так далее. Вы видите это в таких вещах, как веб-сервер Apache (он пытается загрузить модуль mod_rewrite , только если файл конфигурации содержит ссылки на него) и в Perl и Python (загрузка общих объектов .so ...). .с помощью DynaLoader начальной загрузки и встроенных команд импорта соответственно).

(Очевидно, что зависимости становятся интереснее, когда у вас Apache загружает что-то вроде mod_perl или mod_python , который, в свою очередь, выполняет код, который вызывает другие dlopen () операции ... некоторые из которых могут загружать библиотеки XML и т. д.).

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

Если вы хотите узнать больше о создании собственных пользовательских сценариев компоновщика, то лучше всего начать с этого: Использование ld: GNU Linker .

0 голосов
/ 20 сентября 2009

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

Динамические ссылки оставляют вашу программу в более или менее исходном состоянии и подключаются к системным библиотекам во время выполнения.

Чтобы минимизировать окончательный размер исполняемого файла, используйте динамическое связывание.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...