Создание deb-пакета для самых маленьких. Из простого проекта с разделяемыми библиотеками

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

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 
#include   

#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 
#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 
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/ivan/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 .../ivan/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 уже готовый настроенный проект.

Так выглядит deb-пакет по мнению Kandinsky

Так выглядит deb-пакет по мнению Kandinsky

Буду рад ответить на вопросы и предложения.

Полезные ссылки и материалы по теме
https://losst.pro/sozdanie-deb-paketov
https://www.dmosk.ru/instruktions.php? object=build-deb#files

© Habrahabr.ru