4 ответов:
бывают ситуации, когда библиотека только для заголовка является единственным вариантом, например, при работе с шаблонами.
наличие библиотеки только для заголовка также означает, что вам не нужно беспокоиться о разных платформах, где может использоваться библиотека. Когда вы отделяете реализацию, вы обычно делаете это, чтобы скрыть детали реализации и распределить библиотеку как комбинацию заголовков и библиотек (
lib,dllили.soфайлы). Они, конечно, должны быть скомпилированы для все различные операционные системы/версии вы предлагаете поддержку.вы также можете распространять файлы реализации, но это будет означать дополнительный шаг для пользователя - компиляция вашей библиотеки перед ее использованием.
конечно, это относится и к случае основы. Например, библиотеки только для заголовков иногда увеличивают
код размер &времени компиляции.
преимущества библиотеки только для заголовков:
- упрощает процесс сборки. Вам не нужно создавать библиотеку, и вам не нужно указывать скомпилированную библиотеку во время шага ссылки сборки. Если у вас есть скомпилированная библиотека, вы, вероятно, захотите построить несколько ее версий: одна скомпилирована с включенной отладкой, другая с включенной оптимизацией и, возможно, еще одна лишена символов. А может быть, даже больше для мультиплатформенной система.
недостатки библиотеки только для заголовков:
большие объектные файлы. Каждый встроенный метод из библиотеки, который используется в некотором исходном файле, также получит слабый символ, определение вне строки в скомпилированном объектном файле для этого исходного файла. Это замедляет компилятор, а также замедляет компоновщик. Компилятор должен генерировать все это раздувание, а затем компоновщик должен отфильтровать его.
больше времени компиляции. В в дополнение к проблеме раздувания, упомянутой выше, компиляция займет больше времени, потому что заголовки по своей сути больше с библиотекой только для заголовков, чем скомпилированная библиотека. Эти большие заголовки должны быть проанализированы для каждого исходного файла, которая использует библиотеку. Другим фактором является то, что эти заголовочные файлы в библиотеке только для заголовков должны
#includeзаголовки, необходимые для встроенных определений, а также заголовки, которые были бы необходимы, если бы библиотека была построена как скомпилированная библиотека.более запутанная компиляция. Вы получаете намного больше зависимостей с библиотекой только для заголовка из-за этих дополнительных
#includeS требуется с библиотекой только для заголовка. Измените реализацию некоторой ключевой функции в библиотеке, и вам может потребоваться перекомпилировать весь проект. Внесите это изменение в исходный файл для скомпилированной библиотеки, и все, что вам нужно сделать, это перекомпилировать этот исходный файл библиотеки, обновить скомпилированную библиотеку с помощью этого нового .o файл, и повторно свяжите приложение.труднее для человека читать. Даже с лучшей документацией, пользователи библиотеки часто приходится прибегать к чтению заголовков для библиотеки. Заголовки в библиотеке только для заголовков заполняются деталями реализации, которые мешают пониманию интерфейса. В скомпилированной Библиотеке вы видите только интерфейс и краткий комментарий о том, что делает реализация, и это обычно все, что вам нужно. Это действительно все, что вы должны хотеть. Вам не нужно знать детали реализации, чтобы знать, как использовать библиотеку.
Я знаю, что это старый поток, но никто не упоминал интерфейсы ABI или конкретные проблемы компилятора. Так я думал, я хотел бы.
Это в основном основано на концепции того, что вы либо пишете библиотеку с заголовком Для распространения среди людей, либо повторно используете себя, имея все в заголовке. Если вы думаете о повторном использовании заголовка и исходных файлов и перекомпиляции их в каждом проекте, то это на самом деле не применяется.
в основном, если вы компилируете свой код C++ и создайте библиотеку с одним компилятором, затем пользователь попытается использовать эту библиотеку с другим компилятором или другой версией того же компилятора, тогда вы можете получить ошибки компоновщика или странное поведение во время выполнения из-за двоичной несовместимости.
например, поставщики компиляторов часто меняют свою реализацию STL между версиями. Если у вас есть функция в библиотеке, которая принимает std:: vector, то она ожидает, что байты в этом классе будут расположены так, как они были расположены, когда библиотека была скомпилирована. Если в новой версии компилятора поставщик улучшил эффективность std:: vector, то код пользователя видит новый класс, который может иметь другую структуру, и передает эту новую структуру в вашу библиотеку. Все идет под гору оттуда... Вот почему рекомендуется не передавать объекты STL через границы библиотеки. То же самое относится к типам времени выполнения C (CRT).
говоря о CRT, вашей библиотеке и исходном коде пользователя как правило, должны быть связаны с одной и той же ЭЛТ. В Visual Studio Если вы создаете свою библиотеку с помощью многопоточной ЭЛТ, но пользователь связывается с многопоточной отладочной ЭЛТ, то у вас будут проблемы со связью, потому что ваша библиотека может не найти нужные ей символы. Я не могу вспомнить, какая это была функция, но для Visual Studio 2015 Microsoft сделала одну функцию CRT встроенной. Внезапно это было в заголовке не библиотека CRT, поэтому библиотеки, которые ожидали найти его во время ссылки, больше не могли делать и это породило ошибки связи. В результате эти библиотеки нуждались в перекомпиляции с Visual Studio 2015.
вы также можете получить ошибки связи или странное поведение, если вы используете API Windows, но вы строите с различными настройками Unicode для пользователя библиотеки. Это связано с тем, что API Windows имеет функции, которые используют строки Unicode или ASCII и макросы/определяет, какие автоматически используют правильные типы на основе параметров Unicode проекта. Если вы передадите строку через библиотеку граница, которая является неправильным типом, то вещи ломаются во время выполнения. Или вы можете обнаружить, что программа не связывает в первую очередь.
эти вещи также верны для передачи объектов / типов через границы библиотеки из других сторонних библиотек (например, собственный вектор или матрица GSL). Если сторонняя библиотека изменит свой заголовок между вами, компилирующей вашу библиотеку, и вашим пользователем, компилирующим их код, тогда все будет сломано.
в основном, чтобы быть в безопасности только то, что вы можете переход через границы библиотеки встроены в типы и простые старые данные (POD). В идеале любой POD должен быть в структурах, которые определены в ваших собственных заголовках и не полагаются на какие-либо сторонние заголовки.
Если вы предоставляете только библиотеку заголовков, то весь код компилируется с теми же настройками компилятора и против тех же заголовков, поэтому многие из этих проблем уходят (при условии, что версия третьих частично библиотек, которые вы и ваш пользователь используете, совместимы с API).
есть негативы, которые были упомянуты выше, такие как увеличение времени компиляции. Кроме того, вы можете управлять бизнесом, поэтому вы не можете передать все детали реализации исходного кода всем своим пользователям в случае, если один из них украдет его.
основное "преимущество" заключается в том, что он требует от вас доставки исходного кода, поэтому вы получите отчеты об ошибках на машинах и с компиляторами, которые у вас есть никогда не слышал. Когда библиотека полностью состоит из шаблонов, у вас нет большой выбор, но когда у вас есть выбор, заголовок только обычно плохой инженерный выбор. (С другой стороны, конечно, заголовок означает только то, что вам не нужно документировать какую-либо процедуру интеграции.)
Comments