Создание общей библиотеки Linux

Определение

Библиотека  —  это коллекция реализаций поведения, написанная на определенном языке и обладающая продуманным интерфейсом, с помощью которого это поведение активируется. К примеру, разработчики, желающие написать высокоуровневую программу, могут вместо повторяющейся реализации системных вызовов использовать для их создания библиотеку. Кроме того, это поведение предоставляется для повторного использования многими независимыми программами (Wikipedia).

Зачем

В мире открытого программного обеспечения Linux является, пожалуй, лидирующей системой. Согласно английской Wikipedia, примерно на 80% серверов интернета установлена та или иная форма Linux/Unix. Сегодня поддержка этой ОС закладывается в основу большого числа проектов. Участие в создании или расширение имеющихся опенсорсных продуктов является наиболее эффективным способом быстрой разработки программ.

В этой статье мы рассмотрим основы разработки библиотеки Linux на С++, подготовив вас к переходу в мир открытого ПО.

Как

Для начала потребуется выбрать дистрибутив и либо установить его непосредственно на ПК, либо использовать через виртуальную машину. В этом руководстве я буду использовать Ubuntu Linux 22.04. В качестве редактора кода я выбрал VS Code, который можно найти в приложении Snap Store, предлагающем удобный способ скачивания и установки наиболее популярного ПО. А ведь еще недавно единственным способом установки программ в Ubuntu был ввод команд из терминала.

И хотя установка ПО через терминал несколько медлительна, сам по себе этот инструмент является незаменимым помощником для разработчиков. Использование терминала в сочетании с горячими клавишами позволяет делать все быстрее, не отводя рук от клавиатуры.

Создание проекта в VS Code

Для быстрого запуска терминала нажмите ⊞ Win или ⌘ Cmd на клавиатуре Mac и введите terminal, нажмите Enter. После открытия терминала нужно создать каталог для проекта по следующему пути:

mkdir ~/Desktop/linux-shared-library

Теперь используем терминал для открытия созданного проекта в VS Code. Здесь можно задействовать сокращенную команду !$, чтобы автоматически подставить часть ~/Desktop/linux-shared-library из команды выше и передать ее в редактор кода. Вот как это делается:

code !$

Теперь у вас должно открыться окно VS Code, и можно приступать.

В VS Code имеется встроенный терминал для упрощения доступа. Этот терминал можно автоматически активировать нажатием Ctrl + ~.

Пишем main

Откройте терминал VS Code и создайте файл:

code main.cpp

Запишите в него следующий код:

// Позволяет ссылаться на встроенные функции ввода/вывода          // стандартной библиотеки.
#include <stdio.h>

// Реализация функции: int (возвращаемый тип), main (имя // функции), void (тип параметра)
int main(void)
{
// Используем стандартную библиотеку для вывода в окно терминала.
puts("Hello Earth!");

// Выходим с кодом возврата 0, обозначающим успех.
return 0;
}

Это программа, которая будет потреблять библиотеку.

Далее мы скомпилируем и выполним только что написанный код с помощью компилятора gcc, поставляемого вместе с дистрибутивом Ubuntu. Устанавливается он так:

gcc main.cpp

Вышеприведенная команда сгенерирует файл a.out, который при выполнении командой ./a.out в терминале VS Code будет выводить “Hello Earth!”:

Компилирование и выполнение программы

Вы только что скомпилировали и выполнили программу С++! Далее мы разберем, как писать код, которым можно будет делиться с миром.

Написание общей библиотеки

Создайте через терминал VS Code новый файл:

code mars.cpp

В этот файл внесите следующий код:

// Позволяет ссылаться на встроенные функции ввода/вывода          // стандартной библиотеки.
#include <stdio.h>

// Определение функции: void (возвращаемый тип), foo (имя функции), // void (тип параметра).
void mars(void)
{
// Используем стандартную библиотеку для вывода в окно терминала
puts("Hello Mars!");
}

Это уже код нашей библиотеки.

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

code mars.h

Добавьте в него следующий код:

// Определяем макрос препроцессора, чтобы mars.h включался только  // раз.
#ifndef mars_h__
#define mars_h__

// Экспортируем функцию mars в библиотеку, делая доступной для // других проектов.
extern void mars(void);

#endif // mars_h__

Далее нужно скомпилировать код библиотеки, чтобы ее могла использовать программа main.cpp. Это делается в два шага: сначала компилируем код в mars.cpp в виде позиционно-независимого кода, чтобы его можно было добавить в общую библиотеку:

gcc -c -fpic -o mars.o mars.cpp

В результате будет создан объектный файл mars.o. Этот файл мы используем для создания библиотеки:

gcc -shared -o libmars.so mars.o

Теперь можно использовать его в программе main. cpp.

Интегрирование библиотеки

Добавим в main.cpp следующее:

// Позволяет ссылаться на встроенные функции ввода/вывода           // стандартной библиотеки.
#include <stdio.h>
+#include "mars.h"

// Реализация функции: int (возвращаемый тип), main (имя функции), // void (тип параметра).
int main(void)
{
// Используем стандартную библиотеку для вывода в терминал.
puts("Hello Earth!");

+ // Вызываем функцию в общей библиотеке.
+ mars();

// Выходим с кодом возврата 0, означающим успех.
return 0;
}

Здесь мы описали процесс использования функции mars из общей библиотеки.

Теперь скомпилируем программу main и свяжем ее с библиотекой mars. Компилятор gcc предполагает, что имена файлов общих библиотек должны начинаться с lib, поэтому нужно указать, что мы хотим провести линковку с libmars.so. Делается это так:

gcc main.cpp -lmars

Еще нужно сказать gcc, где искать libmars.so. Попробуем снова, но уже с аргументом -L, указывающим расположение библиотеки. О том, что файл доступен в данном каталоге, можно сообщить gcc так:

gcc -L./ main.cpp -lmars

Запускаем скомпилированную программу:

./a.out

Она не может загрузить созданную нами библиотеку. Просто мы не указали, откуда общие библиотеки нужно загружать. Делается это с помощью -Wl,-rpath:

gcc -L./ -Wl,-rpath=./ main.cpp -lmars

Вот и все! Запускайте скомпилированную программу и убедитесь, чтобы вывод совпал со следующим:

Полный вывод в результате компиляции и выполнения общей библиотеки

Если вы вдруг захотите перейти на следующий уровень создания общих библиотек, то подумайте о написании такой для Unreal Engine.

Читайте также:

Читайте нас в TelegramVK и Дзен


Перевод статьи Bobby Galli: How to Build a Linux Shared Library

Предыдущая статьяПочему точные модели не всегда полезны
Следующая статьяПрощай, Python! Здравствуй, C#!