На просторах интернета уже имеются всевозможные туториалы, описывающие пошагово процесс создания 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 уже готовый настроенный проект.
Буду рад ответить на вопросы и предложения.
Полезные ссылки и материалы по теме: