Как создать библиотеку?

Скажем, у меня есть файлы 10 *.hpp и *.cpp, которые мне нужны для компиляции кода. Я знаю, что мне понадобятся те же самые файлы для разных кодов. Могу ли я создать "пакет" с теми файлами, которые позволили бы мне просто написать

#include<mypackage>

вместо

#include"file1.hpp"
#include"file2.hpp"
...
#include"file10.hpp"

Мне тогда не нужно было бы писать make файл каждый раз, когда мне нужен этот "пакет".

Чтобы быть более точным, я использую linux.

Ответ 1

Коллекция источников CPP (файлы H и файлы CPP) может быть скомпилирована в "библиотеку", которая затем может быть использована в других программах и библиотеках. Специфика того, как это сделать, зависит от платформы и инструментальной привязки, поэтому я оставляю это для вас, чтобы узнать подробности. Однако я предоставлю пару ссылок, которые вы можете прочитать:

Создание общей и статической библиотеки с помощью gnu-компилятора [gcc]

Пошаговое руководство: создание и использование библиотеки динамических ссылок (С++)

Библиотеки могут быть разделены на два типа: библиотеки исходного кода и двоичные библиотеки. Могут быть также гибриды этих двух типов - библиотека может быть как исходной, так и двоичной библиотекой. Библиотеки исходного кода просто таковы: коллекция кода, распространяемая как только исходный код; обычно заголовочные файлы. Большинство библиотек Boost этого типа. Бинарные библиотеки скомпилированы в пакет, который можно загружать с помощью клиентской программы.

Даже в случае двоичных библиотек (и, очевидно, в случае исходных библиотек) пользователю должен быть предоставлен файл заголовка (или несколько файлов заголовков). Это говорит компилятору клиентской программы о том, какие функции и т.д. Искать в библиотеке. То, что часто делают авторы библиотек, - это один главный файл заголовка, состоящий из объявлений обо всем, что экспортируется библиотекой, и клиент будет #include этот заголовок. Позже, в случае двоичных библиотек, клиентская программа "привяжет" к библиотеке, и это разрешит все имена, упомянутые в заголовке, на исполняемые адреса.

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

Общим способом решения этой проблемы является предоставление отдельных файлов заголовков для коррелированных частей вашей библиотеки. Если вы думаете обо всем Boost одной библиотеке, то примером является Boost. Boost - это огромная библиотека, но если все, что вам нужно, это регулярное выражение, вы можете только #include заголовок, связанный с регулярным выражением, чтобы получить эту функциональность. Вам не нужно включать все Boost, если все, что вам нужно, это материал регулярных выражений.

Под Windows и Linux двоичные библиотеки могут быть подразделены на два типа: динамические и статические. В случае статических библиотек код библиотеки фактически "импортируется" (из-за отсутствия лучшего термина) в исполняемый файл клиентской программы. Статическая библиотека распределяется вами, но это требуется только клиенту на этапе компиляции. Это удобно, если вы не хотите, чтобы ваш клиент должен был распространять дополнительные файлы с помощью своей программы. Это также помогает избежать Adendancy Hell. С другой стороны, динамическая библиотека не "импортируется" непосредственно в клиентскую программу, а динамически загружается клиентской программой при ее выполнении. Это уменьшает размер клиентской программы и потенциально след диска в случаях, когда несколько программ используют одну и ту же динамическую библиотеку, но бинарный файл библиотеки должен быть распространен и установлен с клиентской программой.

Ответ 2

Предполагая, что ваши файлы "file1.hpp" и "file2.hpp" и т.д. тесно связаны и (почти) всегда используются вместе, то создание одной "mypacakge.h", которая содержит включения других компонентов, является хорошей идеей (это сам по себе не превращает его в библиотеку - это совсем другой процесс).

Если они НЕ тесно связаны и/или используются вместе, тогда у вас не должно быть такого "мега-включения", потому что он просто затаскивает кучу вещей, которые не нужны.

Чтобы сделать библиотеку, необходимо создать код один раз и либо создать файл .lib, либо общий библиотечный файл (DLL или .so). Точные шаги для этого зависят от того, какую систему вы используете, и это слишком сложно для меня объяснить здесь.

Изменить: пояснить далее: вся библиотека С++ - это фактически один файл библиотеки или файл общей библиотеки [наряду с несколькими заголовками, которые содержат часть кода и декларации, необходимые для использования кода в библиотеке]. Но вы включаете <iostream> и <vector> отдельно - было бы довольно ужасно включать ВСЕ из всех разных заголовков библиотеки С++ в один <allcpplibrary>, даже если бы это было гораздо меньше, чем печатать. Он разделен на разделы, которые делают одну вещь в заголовочном файле. Таким образом, вы получаете "полный" набор из одного файла заголовка, но не слишком много других вещей, которые вам действительно не нужны.

Ответ 3

Если клиенту нужны все десять заголовков, чтобы фактически использовать ваш "пакет" (библиотека), этот довольно плохой дизайн интерфейса.

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

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

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

То, что я не понимаю, это вмешательство Makefiles в это. Зависимости заголовков должны автоматически решаться с помощью вашей системы Makefile/build, т.е. Здесь не имеет значения, как ваши файлы заголовков выкладываются.

Ответ 4

Да и нет.

Вы можете написать заголовок include-all, так что #include "myLib.h" достаточно, потому что вы включаете все эти заголовки через один заголовок. Однако это не означает, что единственного включения достаточно, чтобы содержимое файлов размером 10 дюймов .cpp было связано с вашим проектом автоматически. Вам придется скомпилировать их в библиотеку и связать эту единую библиотеку (а не все объектные файлы) с проектами, использующими "myLib.h". Библиотечные двоичные файлы являются статическими и динамическими библиотеками, файлы обычно называются .lib и .dll (windows) и .a и .so (linux) для статических и динамических библиотек соответственно.

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

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

Ответ 5

В Linux:

g++ FLAGS -shared -Wl, -soname, libLIBNAME.so.1 -o libLIBNAME.VERSION OBJECT_FILES

где

FLAGS: типичные флаги (например, -g, -Wall, -Wextra и т.д.)

LIBNAME: имя вашей библиотеки

OBJECT_FILES: файлы объектов, возникающие в результате компиляции файлов cpp

ВЕРСИЯ: версия вашей библиотеки