На просторах интернета уже имеются всевозможные туториалы, описывающие пошагово процесс создания deb-пакета. Однако у меня возникла потребность собрать пакет из проекта с разделяемыми библиотеками, и я решил поделиться тут своим опытом
В качестве тренировки возьмем простенький проект на Си, в котором производится сборка приложения и двух разделяемых библиотек
Описание проекта, для которого будет создаваться deb-пакет
Назовем проект poop. Он будет имитировать авторизацию в каком-нибудь сервисе, а именно проверять наличие паролей для двух пользователей и не совпадают ли они.
Начальная структура проекта
-> /poop |-> Makefile |-> /src |-> input_check.h |-> input_check.c |-> login.c |-> login.h |-> input_check.c
Исходники
input_check.h
#ifndef INPUT_CHECK_H #define INPUT_CHECK_H int check_input(int argc); #endif
input_check.c
#include <stdio.h> int check_input(int argc) { int ret = argc; switch (ret) { case 1: printf("[%s] The poop app. " "Tap TAB to make app dumb\npoop [random string]\n", __FUNCTION__); ret = 0; break; case 2: break; default: printf("[%s] WTF?!\npoop [random string]\n", __FUNCTION__); ret = -1; break; } return ret; }
login.h
#ifndef LOGIN_H #define LOGIN_H int check_login(const char* login_to_check); #endif
login.c
#include <stdio.h> #include <string.h> #define TYPE_1 "user_1" #define TYPE_2 "user_2" int check_login(const char* login_to_check) { int ret = 0; if(login_to_check != NULL) { if ((strcmp(login_to_check, TYPE_1) == 0) || (strcmp(login_to_check, TYPE_2) == 0)) { printf("%s\n", login_to_check); } else { printf("[%s]: Логин не определен\n", __FUNCTION__); ret = -2; } } else { printf("[%s] Пусто!\n", __FUNCTION__); ret = -3; } return ret; }
main.c
#include <stdio.h> #include "input_check.h" #include "login.h" int main(int argc, char **argv) { int ret = check_input(argc); if (0 < ret) ret = check_login(argv[1]); return ret; }
Makefile
# target to create first shared library libpoopl0gin.so: src/login.c gcc src/login.c -o libpoopl0gin.so -shared -fPIC # target to create second shared library libpoopinputch3ck.so: src/input_check.c gcc src/input_check.c -o libpoopinputch3ck.so -shared -fPIC main.o: src/main.c gcc -c src/main.c all: libpoopl0gin.so libpoopinputch3ck.so main.o gcc main.o -I/src libpoopl0gin.so libpoopinputch3ck.so -o poop.out clean: rm -rf *.so rm -rf *.o*
Сборка производится командой make all
Подготовка проекта и сборка пакета
Разделим всю работу по созданию пакета на несколько этапов:
0. Обзор зависимостей;
1. Создание манифеста;
2. Перемещение файлов;
3. Создание скрипта установки;
4. Сборка и проверка пакета.
Прежде чем приступить установим некоторые необходимые пакеты:
sudo apt install dpkg-dev devscripts equivs
А вот теперь уже приступим

0. Обзор зависимостей
Наши собранные библиотеки имеют собственные зависимости, поэтому их нужно посмотреть. Делается это командой objdump:
~/poop$ objdump -p ./libpoopl0gin.so | grep NEEDED NEEDED libc.so.6 ~/poop$ objdump -p ./libpoopinputch3ck.so | grep NEEDED NEEDED libc.so.6 # В нашем случае программе необходима только libc. # Смотрим, в каком пакете она находится: ~/poop$ dpkg -S libc.so.6 libc6:amd64: /lib/x86_64-linux-gnu/libc.so.6
1. Создание манифеста
Создаем папку:
~/poop$ mkdir -p package/DEBIAN
Затем файл манифеста
~/poop$ vi package/DEBIAN/control
И наполняем следующим содержимым:
Package: poop Version: 1.0 Section: uncrown Priority: optional Depends: libc6 Architecture: amd64 Essential: no Installed-Size: 16 # значение из результата команды du -k ./poop.out Maintainer: doob.poop <peep@doob.poop> Description: Check random login from random user
Это минимальный набор параметров в файле манифеста. Вот их значение:
Package - имя пакета;
Version - версия программы в пакете, будет использована при обновлении пакета;
Section - категория пакета, позволяет определить зачем он нужен;
Priority - важность пакета, для новых пакетов, которые ни с чем не конфликтуют обычно прописывают optional, кроме того доступны значения required, important или standard;
Depends - от каких пакетов зависит ваш пакет, он не может быть установлен, пока не установлены эти пакеты;
Recommends - необязательные пакеты, но тем не менее они обычно устанавливаются по умолчанию в apt;
Conflicts - пакет не будет установлен, пока в системе присутствуют перечисленные здесь пакеты;
Architecture - архитектура системы, в которой можно установить этот пакет, доступные значения: i386, amd64, all, последнее означает, что архитектура не имеет значения;
Installed-Size - общий размер программы после установки;
Maintainer - указывает кто собрал этот пакет и кто отвечает за его поддержку;
Description - краткое описание пакета.
2. Перемещение файлов
Создаем папку usr/bin и поместить туда исполняемый файл программы:
~/poop$ mkdir -p package/usr/bin ~/poop$ cp ./poop.out package/usr/bin
Создаем папку usr/lib для наших разделяемых библиотек
~/poop$ mkdir -p package/usr/lib ~/poop$ cp ./libpoop* package/usr/lib
3. Создание скрипта установки
Несмотря на то, что система установки пакетов очень мощная и позволяет делать многое, некоторые вещи всё же сделать нельзя. Для решения этой проблемы была предусмотрена возможность выполнять скрипты перед установкой пакета и после. Аналогично это работает для удаления пакета - перед и после. Эти скрипты называются preinst, postinst, prerm и postrm. Каждый файл просто содержит набор скриптов, которые надо выполнить. Например:
~/poop$ vi package/DEBIAN/postinst #!/bin/bash echo "Hello from poop installed"
Разработчики Debian не рекомендуют использовать эти скрипты без крайней надобности, поскольку они дают вам полный контроль над системой пользователя и вы можете случайно что-то повредить. Обычно эти скрипты используются для того чтобы задавать пользователям вопросы и на основе этого генерировать конфигурационные файлы.
4. Сборка и проверка пакета
Осталось собрать настроенный пакет:
~/poop$ dpkg-deb --build ./package
После завершения сборки устанавливаем его с помощью apt:
~/poop$ sudo apt install ~/package.deb Reading package lists... Done Building dependency tree... Done Reading state information... Done Note, selecting 'poop' instead of './package.deb' The following NEW packages will be installed: poop 0 upgraded, 1 newly installed, 0 to remove and 8 not upgraded. Need to get 0 B/4 454 B of archives. After this operation, 16,4 kB of additional disk space will be used. Get:1 /home/user/Projects/poop/package.deb poop amd64 1.0 [4 454 B] Selecting previously unselected package poop. (Reading database ... 281406 files and directories currently installed.) Preparing to unpack .../user/Projects/poop/package.deb ... Unpacking poop (1.0) ... Setting up poop (1.0) ... Hello from poop installed
Теперь проект можно запустить:
~/poop$ poop.out user [check_login]: Логин не определен
Конечная структура проекта
-> /poop |-> Makefile |-> /src |-> input_check.h |-> input_check.c |-> login.c |-> login.h |-> input_check.c |-> /package |-> /DEBIAN |-> /usr |-> /bin |-> poop.out |-> /lib |-> libpoopinputch3ck.so |-> libpoopl0gin.so
Как видно из структуры выше, добавилась папка package, в которой находятся все поддиректории и файлы, необходимые для успешной сборки deb-пакета простенького проекта
Для простоты проверки всего вышего сказанного, можно клонировать с Github уже готовый настроенный проект.

Буду рад ответить на вопросы и предложения.
Полезные ссылки и материалы по теме:
