📜 ⬆️ ⬇️

How to build a binary deb package: detailed HowTo

Today I will tell on an abstract example how to properly create a * .deb package for Ubuntu / Debian. We will make the binary package. Packages that compile binaries from source codes are not considered here: after you have mastered the knowledge outlined below, you can understand the essence and use similar examples in the future using ready-made examples :)

The article will not have any unnecessary fuss "manually": the package format has evolved into a fairly simple, and most importantly, a logical structure, and everything is done literally on the knee, using a couple of specialized utilities.

As a bonus, at the end of the article there will be an example of quickly creating your own local repository: installing packages from the repository allows you to automatically track dependencies, and of course! - install everything with one console command on several machines :)
')
For those who do not want to go into the powerful software installation system in Linux, I recommend visiting the CheckInstall program site : it automatically creates a deb-package from the “make install” command;) And we, along with the curious, -

Sources


Information is trusted from many places, but here are two main ones:

The article details the basics of creating packages that are sufficient to obtain sufficiently powerful application installation management. More advanced features are omitted, but direct links to documentation for those interested are suggested.
The article is not a copy or a translation of any documentation: it is a collection of knowledge, lying in the form of notes, and now decorated in the form of an article. For clarity, there are examples everywhere, explanations on the fingers, convenient features I found and some typical mistakes that can be made out of ignorance.

Training



Why is this all about?

Yes, CheckInstall can create a work package, but it does not support all the goodies that deb packages are capable of :) Namely:


What is required

Of course, tar, gz, ar archivers will be enough to create a full-fledged package, but you can eliminate the extra fuss, and use the tools created to make life easier :)
We put:
$ sudo apt-get install dpkg debconf debhelper lintian

What do we do

For example, a certain script /usr/bin/super.sh will be considered. It doesn't matter what's inside, the main thing is how it will appear on the right place :)

Folder preparation

In the home directory (or where convenient) create a folder in which all files of the future package will be located: mkdir ~/supersh . Further we will call its package root .
At the root of the package create a folder "DEBIAN" (in capital letters, this is important!). This folder contains package generation control information, and is not copied to disk when the package is installed.
Also, the root folder of the package contains the future “root of the disk”: when installing the package, all files (except the “debian” folder) are unpacked into the root /. Therefore, our script should follow this path relative to the package root: “usr / bin / super.sh”
White on black:
mkdir -p ~/supersh/DEBIAN #
mkdir -p ~/supersh/usr/bin #
cp super.sh ~/supersh/usr/bin/ #

As a result, we have:
supersh/DEBIAN/
supersh/usr/
supersh/usr/bin/
supersh/usr/bin/super.sh


Build Package: DEBIAN / *


As I said, the DEBIAN folder contains files used during installation. Here I will describe (with examples) each file.
To create a full-fledged package, the control file “control” is sufficient; all the others are used either to attach textual information (changelog, license), or to manage advanced application installation features.
From the files described below in the folder DEBIAN / * we select the necessary ones and fill in according to the instructions :)
In our example, only mandatory DEBIAN / control is really used.

DEBIAN / control: Basic Information

control is the central package file that describes all the basic properties. The file is a text file consisting of “Attribute: Value” pairs. You can use comments: the "#" symbol at the beginning of the line (the feature was added in the dpkg version> = 1.10.11, you should not hope for comments :).
The table shows all the fields defined for the control file. Required fields are in bold : without them, the package will not be considered as composed correctly.
AttributeDescriptionExamples
- basic -
Package:Package Name: [a-zA-Z0-9-] - only Latin, numbers, and hyphen. The name is used during installation: apt-get install <package>Package: supersh
Version:Version of the package (and the program inside). Used to determine whether to update.
The format is as follows: <_>-<_> .
I recommend to always indicate the version of the package: when changing the structure of the package, the figure is increased by one.
Valid characters are quite voluntary: you can use the date and letters. See examples in your repository today :)
Version: 1.0-1<br>Version: 2009.12.12-1
ProvidesThe application name (possibly virtual) registered in the system as a result of the installation of this package.
Rarely used: mainly if you need to change the name of the package, or if more than one package offers the same functionality. For example, the Apache and nginx packages provide the httpd: Provides: httpd daemon feature
You probably encountered an error when trying to install: "is a virtual package". This is it :)
Provides: supersh
MaintainerThe name and mail of the package maintainer: the person who “debianized” the application.
The format is arbitrary, but the <e-mail> accepted <e-mail>
Maintainer: o_O Tync <oo-tync.habrahabr.ru>
ArchitectureThe processor architecture for which the package is intended.
Valid values: i386, amd64, all, source
all used for scripts: they are portable, right? :)
source used for compiled source packages.
Architecture: all
SectionSpecifies the task for which the application is typically used (group of applications).
Possible values: admin, base, comm, contrib, devel, doc, editors, electronics, embedded, games, gnome, graphics, hamradio, interpreters, kde, libs, libdevel, mail, math, misc, net, news, non-free , oldlibs, otherosfs, perl, python, science, shells, sound, tex, text, utils, web, x11
Section: misc
DescriptionDescription of the package.
The description consists of two parts: a short description (70 characters) on the same line, and a long description on subsequent lines, starting with a space .
In the extended description, all line breaks are ignored. A single point is used to insert \ n.
Description: Short.<br>␣Long <br>␣goes here.<br>␣.<br>␣New line.
- connections and dependencies -
DependsA comma-separated list of packages that are required to install this package.
After the package name, you can indicate the limit on the version in parentheses using the operators: <<, =, >>, <=,> =. If the operator is not specified, it is used> =
Depends: dpkg, libz (>= 1.2.3), jpeg (= 6b), png (< 2.0)
Pre-dependsList of packages that are required during the installation of this package.
These dependencies may be required for package installation scripts: for example, the flash-installer package requires wget
Version restrictions can be used (see Depends).
Pre-Depends: wget (>= 1.0)
ConflictsList of packages that cannot be installed at the same time.
Installation will fail if at least one of the listed packages is already installed.
Conflicts: crapscript
ReplacesThe list of packages whose files are modified by this package.
Required if you create a “patch package” that changes something: otherwise, when replacing files of someone else's package, an error will occur during installation. For example, I have such a package of patch UT2004 and removes the sound of the proposed rocket launcher :)
Replaces: ut2004
RecommendsList of recommended packages for installation
These packages are optional, but are usually used with current
Recommends: superplatform
SuggestsList of packages offered for installation.
These packages are not required, but with them the program works even better :) In theory, the package manager should offer to install them.
Suggests: supersh-modules
Build-depends(For Architecture: source only)
List of packages required to compile the source.
Same as Depends, but logically separated.
Build-Depends: cmake
- extra -
Installed-SizeThe size of the package files in kilobytes.
Just a figure, rounded to the nearest integer. Used by the package manager to determine the total required disk space.
Installed-Size: 3
PriorityPackage priority: how important is it in the system?
Possible values: extra, optional, standard, important, required (such packages are not removed at all!).
Priority: optional
EsssentialIf you set this attribute to “yes”, the package cannot be deleted.Esssential: yes
OriginLine: from where the programs are received in the package. Usually the author’s site URL, mail or name is used.Origin: brain
X-sourceFull link to * .tar.gz archive with sourcesX-Source: ...*.tgz

Yes, these are the solid features of the control file :)
And in our example, it looks like this:
Package: supersh
Version: 1.0-1
Section: misc
Architecture: all
Depends: bash, sed (>= 3.02-8)
Maintainer: o_O Tync <oo-tync.habrahabr.ru>
Description: Super Shell Script
␣A super example script.
␣.
␣It does nothing :)


DEBIAN / copyright: Š / license

The text of the license. The file is not required, but it is better to underline your authorship;)

DEBIAN / changelog: change history

Changelog in a special format: use dpkg to get the version number, revision, distribution and importance of the package. It is better to look in the official documentation ;) and I will only give an example:
supersh (1.0-1) stable; urgency=medium

* Testing.

-- o_O Tync <oo-tync.habrahabr.ru> Sun, 13 Dec 2009 00:11:46 +0300


DEBIAN / rules: compilation rules

Used to manage package compilation: this is when Architeture: source :)
See the official documentation.

DEBIAN / conffiles: list of configuration files

Usually packages contain clumps of configuration files, for example, placed in / etc. Obviously, if the config in the package is updated, the user will lose his edited config. This problem is easily solved by using folders of the “config.d” type, the contents of which are included in the main config, replacing the recurring options.
The file "DEBIAN / conffiles" allows you to solve the problem differently: it contains a list of configuration files (one per line). If in the current version of the package one of these files is updated, the user receives a warning about the conflict of versions of configs, and can choose: delete, replace, or make a merge.
Every linuxid who has been digging into configs probably came across this situation :) And his legs are growing from here.
On each line there should be a full absolute path to each config. For example:
/etc/supersh/init.conf
/etc/supersh/actions.conf


DEBIAN / dirs: a list of folders to create

“The list of absolute paths to folders that are required by the program, but for some reason are not created.” Says the official documentation. In practice, all the folders used by the program are listed here: where the binaries lie and which are used by the program.
One per line. For example:
/var/log/supersh
/var/lib/supersh

Convenient to use to create multiple empty folders.

DEBIAN / menu: creating menu items

Tricky file to create menu items. It did not work for me :) It seems that its contents are used either in unusual window managers, or in some kind of console menu ... or it was used before and was forgotten :)
Example:
?package(supersh):needs="text" section="Applications/Programming" title="Super Shell Script" command="/usr/bin/super.sh"
TODO: find out why. This is written in the man5 menufile , to be honest, I did not penetrate :)

UPD: The correct way to add a menu item

The file / DEBIAN / menu creates an unknown and it’s not clear where: the graphic menu items are still not created. Therefore, we will do right :)
In /usr/share/applications we see a bunch of *.desktop files: these are menu items. They are text files with syntax like an ini file. We open, learn, do the same and put the resulting *.desktop file into usr/share/applications/ . The icon for it should be in usr/share/pixmaps .
After that, in the postinst script you need to add the execution of the update menu command:
if [ "$1" = "configure" ] && [ -x "`which update-menus 2>/dev/null`" ] ; then
update-menus
fi

The work with package installation scripts will be discussed below.
Thanks to Condorious for the tip :)

DEBIAN / md5sums: file checksums

Used to verify the integrity of the package. Important file.
It is filled like this (cwd = package root):
$ md5deep -r usr > DEBIAN/md5sums

DEBIAN / watch: monitoring the site where the program was downloaded from

The function is useful if you are a maintenite from several dozen packages, and it is difficult to keep track of all the updates.
The file contains instructions for uscan and uupdate. Using this feature, you can monitor the site from which the source package was obtained, and ensure quality control of the distribution in general.
Example:
# Site Directory Pattern Version Script
ftp.obsession.se /gentoo gentoo-(.*)\.tar\.gz debian uupdate

And another example for uscan (1):
version=3
madwimax.googlecode.com/files/madwimax-(.*)\.tar\.gz

Better read the official documentation , such powerful things are infrequently required by mere mortals :)

DEBIAN / cron.d: install cron jobs

The file contains a piece of crontab for installation. An example explains everything:
#
# Launches super.sh periodically
#
0 4 * * * root [ -x /usr/bin/super.sh ] && usr/bin/super.sh


DEBIAN / inid.d: init-script

The contents of the init-script are written to this file. About writing init scripts in the internet can be found

Scripting


We come to the most interesting part: embedding scripts in deb packages. Scripts allow you to manage the installation, reinstallation and removal of a package by performing actions that cannot be done by simply copying files to the right places. This may be downloading additional files (as flash-installer does), modifying existing ones, and also displaying interactive (GUI or ncurses) dialogs that allow the user to configure the package for himself: for example, mysql asks which password to set to root.
All scripts are executed from the root user (and how else :). They also receive arguments (which are optional to process), specifying at what stage the installation is located. Read more about it here .

DEBIAN / (preinst | postinst | prerm | postrm): installation scripts

In total, you can create up to four scripts in one package:
ScriptPurpose
DEBIAN / preinstRuns before installing the package: it can prepare something for a successful installation.
DEBIAN / postinstIt is executed immediately after installing the package: it configures the installed package so that it is ready for operation. It also runs the interactive configuration of the package: this is done using dh_input and the DEBIAN / templates file
DEBIAN / prermIt is executed immediately before removing the package: usually this script cleans up the installation paths of the package so that nothing extra is left over :)
DEBIAN / postrmRuns immediately after removing a package: cleans up leftovers

Please note that errors that occur in these scripts are not logged in any way : nothing more interesting than the script's return code is not saved anywhere, and logging must be done manually! Users of one of my packages failed to install on Linux Mint, and it was not even possible to ask them for a log of errors (which is not present) in order to find out the reason :)
I recommend using the following disc at the beginning of each script: it will save any errors that occur in the syslog.
#!/bin/bash
set -e # fail on any error
set -u # treat unset variables as errors

# ======[ Trap Errors ]======#
set -E # let shell functions inherit ERR trap

# Trap non-normal exit signals:
# 1/HUP, 2/INT, 3/QUIT, 15/TERM, ERR
trap err_handler 1 2 3 15 ERR
function err_handler {
local exit_status=${1:-$?}
logger -s -p "syslog.err" -t "ootync.deb" "supersh.deb script '$0' error code $exit_status (line $BASH_LINENO: '$BASH_COMMAND')"
exit $exit_status
}

... ...

exit 0

WARNING: the disc has not been tested extensively yet, check it out once more! I came across the impossibility of debugging recently :)

DEBIAN / templates: templates for dialogs

As already mentioned, in the DEBIAN / config script, you can ask the user questions: enter a line, select one of the options, tick, ... This is the “library” bash of the debhelper functions of the debconf package, which also knows a lot of useful things. I don’t consider them here :)
The DEBIAN / templates file contains the data used when displaying dialog boxes (GUI or ncurses). The file contains blocks separated by an empty line. Each block defines the resources used in one particular dialog box.
The cap for all types of dialog is standard:
Template: supersh/template-name
Type: string
Default: Default-value
Description: Dialog-title
␣Dialog-text

Template - unique (within one package) template identifier. If a script needs to call a specific dialog, this is the name that is used.
Type - the type of template. The following types are defined: string, password, boolean, select, multiselect, text, note, error.
Default-value is the default value: the user can simply accept it.
Description - as in the control file, consists of two fields: a short description, and a long text. The first is the “window” title, the second is a more detailed description of what is required of the user. It is recommended not to use words like “enter”, but immediately the essence: “Greeting the script”, “Mount point”, ...

Type ofTemplate Description
stringInvitation to enter a text string
passwordPassword prompt
There is no Default value for this template type for obvious reasons :)
booleanTick ​​:) Has a string value of "true" or "false"
selectAbility to select one of several options.
Options are offered in an additional attribute of the template:
Choices: yes, no, maybe
multiselectAbility to select multiple options tick.
Options are offered in an additional attribute of the template:
Choices: sex, drugs, rock-n-roll
textDisplays text: some not-so-important information.
noteDisplays text: important information
errorDisplays the text: very important information, critical.

For text, note, error templates there is also no Default value, since they only display information :)
Let's play with the following template:
Template: supersh/greeting
Type: string
Description: Welcome message
␣The message you wish the script to welcome you with.
Default: Greetings, my master!


Basics of using debconf and debhelper

These are only workable sketches. In the original, read about templates and working with them here: man 7 debconf-devel :)
To use templates in your DEBIAN / config configuration script, you must first enable the debhelper functions:
. /usr/share/debconf/confmodule . /usr/share/debconf/confmodule . Also, this file must be included in the postinst script: otherwise the DEBIAN / config script will not run at all!
These features are available in the debconf package; don't forget to enable it depending!
Primitive use case. DEBIAN / config file
#!/bin/bash -e

# debconf
. /usr/share/debconf/confmodule

case "$1" in
configure|reconfigure)
#
db_input medium "supersh/greeting" || true #
db_go || true #
#
db_get "supersh/greeting" # $RET
greeting="$RET"
echo "$greeting" > /etc/supersh/greeting.txt
;;
*)
echo "config called with unknown argument \`$1'" >&2
exit 1
;;
esac
#
db_input medium "supersh/greeting" || true #
db_go || true #

#
db_get "supersh/greeting" # $RET
greeting="$RET"
echo "$greeting" > /etc/supersh/greeting.txt

There is already an unpleasant ambush: note that the dialogue priority of the medium is transferred to the db_input function. For debconf, you can set a minimum priority: dialogs with a priority below which are not displayed, but the default value (template default) is taken! To prevent this EXACTLY from happening - we use the priority of critical :) In addition, when installing from the GUI, the threshold for displaying questions is higher, and many of them are not displayed at all.
Possible priorities: low - always use default, medium - default is usually quite suitable, high - default is undesirable, critical - user's attention is vital.
|| true || true used to prevent the script from dying due to the "-e" key sent by bash.
In this script, it is also recommended to use that disc for catching errors, otherwise debugging problems may occur with the distributed package :)
All the subtleties of using debconf (functions, methods, parameters, error codes) are described in a rather verbose manner: man debconf-devel .

One last thing: when removing a package with the purge command, debconf should also clear the package information from its database. For example, it saves user selection when db_input requests.
To clear this data, add the following to the postinst script:
if [ "$1" == "purge" ] && [ -e /usr/share/debconf/confmodule ] ; then
. /usr/share/debconf/confmodule
db_purge
fi


Putting the package! :)


Hooray! All the necessary files are created, are on the right daddy. Now it's time to pack :)
The first thing to do is to recursively set all the files in the root of the user's package and the root group: root (or others if necessary). It is necessary then that the package files are packed into a tar.gz archive which preserves both the rights of access to the files and the owner. Because you need to perform:
$ sudo chown -R root:root .
However, this is not necessary. There is a great fakeroot command that, when creating an archive, will replace the owner of files with root.
In our example, the script should have a doable bit.
Then we go back to the folder so that the root folder of the package can be seen, and the package is created with a light kick by itself:
$ fakeroot dpkg-deb --build supersh
The created package must be renamed to correspond to the naming order of * .deb packages: <package name> _ <version> _ <architecture> .deb
$ mv supersh.deb supersh_1.0-1_all.deb
Everything, the package is ready!

Automatic package check

There is a lintian utility that allows you to check a package and identify common errors in its structure. This is done like this:
$ lintian supersh_1.0-1_all.deb

Package installation

$ sudo dpkg -i supersh_1.0-1_all.deb

Create your own package repository


Now we have our own package. When there are several, and even more so with dependencies, it turns out that it is much more convenient to quickly raise your own local micro-repository, and include it in the list of package manager sources :) Here I will describe the quick HowTo “how to create your repository”. The idea will be easy to develop by reading the relevant documentation :)
First install the assistant:
$ sudo apt-get install reprepro

Description of the future repository

Center repository - its description. The main thing in it is the list of repository components. We will create soft and games components.
Select a folder for the future repository. All actions are made from its root.
Create a conf / distributions file with the following content:
Description: my local repository
Origin: Ubuntu
Suite: testing
AlsoAcceptFor: unstable experimental
Codename: karmic
Version: 5.0
Architectures: i386 amd64 source
Components: soft games
UDebComponents: soft games

In our business of creating a simple repository, all fields do not play a fundamental role, and are used only for the visual definition of "what is what" :)

Creating a repository

The repository is described! Now we will generate a blank based on the description. Commands are executed in the repository root:
$ reprepro export
$ reprepro createsymlinks

And add the ready repository to /etc/apt/sources.list:
deb file:///path/to/repo/ karmic soft games
This repository can also be shared using a web server.

Package Management in the repository

Put in the root of the repository * .deb files to add, and add them to the soft component of the karmic distribution:
reprepro -C soft includedeb karmic *.deb
Now packages are available from the package manager :)
Removing packages:
reprepro -C soft remove karmic supersh

The finish


The article describes the materials for creating deb packages.Emphasis is placed on moments for which the network does not have a sufficiently clear description. I hope that my attempt to explain simply and clearly did not fail :)
Homework :)) - quite well documented things that are easy to find in man's and articles:


UPD: @ ICD2 tells you that there is a GUI program for creating packages: GiftWrap .

Cheers! :)

PS The article probably contains inaccuracies and errors. Let's comb it together! :)

Source: https://habr.com/ru/post/78094/


All Articles