How to build a binary deb package: a detailed HowTo

    Today I will tell you on an abstract example how to correctly create a * .deb package for Ubuntu / Debian. Package we will do binary. Packages compiling binaries from source codes are not considered here: having mastered the knowledge set forth below, you can understand the essence and act by analogy with ready-made examples :)

    In the article there will be no unnecessary fuss “manually”: the package format has evolved into a fairly simple, and most importantly - 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 don’t want to go into a powerful Linux software installation system, I recommend visiting the CheckInstall program website : it automatically creates a deb package from the “make install” command;) And we, along with the curious ones,

    Sources


    Nadirgan information from many places, but here are two main:

    The article sets out in detail the basics of creating packages that are sufficient to get quite powerful application installation control. More advanced features are omitted, but direct links to documentation for those interested are offered.
    The article is not a copy or translation of any documentation: it is a collection of knowledge lying in the form of notes, and now designed as 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?

    Yes, CheckInstall can create a working package, but it does not support all the goodies deb packages are capable of :) :) Namely:
    • Scripts that run before, after, and instead of installing the package :)
    • Automatic configuration file management: the package will not allow overwriting old configs with new ones without demand
    • Working with templates: the ability to ask the user questions during installation (!!!)
    • Modify other package files


    What is required

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

    What will 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 in the right place :)

    Folder preparation

    In your home directory (or wherever is convenient) create a folder in which to lay all the files of the future package: mkdir ~/supersh. Next, we will call its package root .
    In the root of the package, create the “DEBIAN” folder (in capital letters, this is important!). This folder contains information that controls the generation of the package, and is not copied to disk when installing the package.
    Also, the package root folder contains the future “disk root”: when installing the package, all files (except the “debian” folder) are unpacked to the / root. therefore, our script should lie in this way, relative to the root of the package: "usr / bin / super.sh"
    White on black: As a result, we have:
    mkdir -p ~/supersh/DEBIAN # управляющая папка
    mkdir -p ~/supersh/usr/bin # путь к скрипту
    cp super.sh ~/supersh/usr/bin/ # копируем наш скрипт в нужное место


    supersh/DEBIAN/
    supersh/usr/
    supersh/usr/bin/
    supersh/usr/bin/super.sh


    Create Package: DEBIAN / *


    As I said, the DEBIAN folder contains the files used during installation. Here I will describe (with examples) each file.
    To create a full-fledged package, the control file “control” is enough, all the rest are used either to attach text information (changelog, license), or to control advanced installation capabilities of applications.
    From the files described below in the DEBIAN / * folder, select the necessary ones and fill out according to the instructions :)
    In our example, only the required DEBIAN / control is really used .

    DEBIAN / control: Basic Information

    control is the central file of the package that describes all the basic properties. A file is a text file consisting of the “Attribute: Value” pairs. Comments can be used: the "#" character at the beginning of the line (the feature was added in dpkg> = 1.10.11, you should not rely on comments :).
    The table shows all the fields defined for the control file. Mandatory fields are marked in bold : without them, the package will not be considered correctly composed.
    AttributeDescriptionExamples
    - basic -
    Package:Package Name: [a-zA-Z0-9-] - only Latin, numbers, and hyphens. The name is used during installation: apt-get installPackage: supersh
    Version:The version of the package (and the program inside). Used to determine whether to update.
    The format adopted is as follows: <версия_программы>-<версия_пакета>.
    I recommend always indicating the version of the package: when the structure of the package changes, the number increases by one.
    Valid characters are quite free: you can use the date and letters. See examples in your repository today :)
    Version: 1.0-1
    Version: 2009.12.12-1
    ProvidesThe name of the application (possibly virtual) registered in the system as a result of installing this package.
    It is rarely used: mainly, if you need to change the name of a package, or if more than one package offers the same functionality. For example, the Apache and nginx packages provide the httpd daemon feature: Provides: httpd
    you must have encountered an error 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 acceptedимя
    Maintainer: o_O Tync
    ArchitectureThe processor architecture for which the package is intended.
    Allowed values: i386, amd64, all, source
    allused for scripts: they are portable, right? :)
    sourceused for compiled packages with source
    Architecture: all
    SectionDefines the task for which the application is usually used (application group).
    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
    DescriptionPackage description.
    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 dot is used to insert \ n.
    Description: Short.
    ␣Long
    ␣goes here.
    ␣.
    ␣New line.
    - relationships and dependencies -
    DependsA comma-separated list of packages that are required to install this package.
    After the package name, you can specify the version restriction in parentheses using the operators: <<, =, >>, <=,> =. If the operator is not specified ->> is used
    Depends: dpkg, libz (>= 1.2.3), jpeg (= 6b), png (< 2.0)
    Pre-dependsA list of packages that are required during the installation of this package.
    These dependencies may be required for package installation scripts: for example, flash-installer requires wget.
    You can use version restrictions (see Depends).
    Pre-Depends: wget (>= 1.0)
    ConflictsA list 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
    ReplacesList of packages whose files are modified by this package.
    It is required in case of creating a “patch package” that changes something: otherwise, an error occurs during installation when replacing files of another package. For example, I have such a package patches UT2004 and removes the sound of a guided rocket launcher :)
    Replaces: ut2004
    RecommendsList of packages recommended for installation.
    These packages are optional, but are usually used together with the current one.
    Recommends: superplatform
    SuggestestsList of packages offered for installation.
    These packages are optional, but the program works even better with them :) In theory, the package manager should offer to install them.
    Suggests: supersh-modules
    Build-depends(Architecture: source only)
    A list of packages required to compile the sources.
    Same as Depends, but logically separate.
    Build-Depends: cmake
    - extra -
    Installed-SizePackage file size in kilobytes.
    Just a number, 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 deleted at all!).
    Priority: optional
    EssentialsIf you set this attribute to yes, the package cannot be removed.Esssential: yes
    OriginString: where did the programs in the package come from. Usually the author’s website URL, mail or name is used.Origin: brain
    X-sourceFull link to the * .tar.gz source archiveX-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
    Description: Super Shell Script
    ␣A super example script.
    ␣.
    ␣It does nothing :)


    DEBIAN / copyright: © / license

    The text of the license. The file is optional, but it is better to emphasize your authorship;)

    DEBIAN / changelog: change history

    Changelog in a special format: used by 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 Sun, 13 Dec 2009 00:11:46 +0300


    DEBIAN / rules: compilation rules

    Used to control the compilation of the package: this is when Architeture: source:)
    See the official documentation

    DEBIAN / conffiles: list of configuration files

    Usually packages contain blanks for configuration files, for example, hosted in / etc. Obviously, if the config in the package is updated, the user will lose his edited config. This problem can be easily solved using folders of the “config.d” type, the contents of which are included in the main config, replacing the duplicate options.
    The “DEBIAN / conffiles” file 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, then the user receives a warning about the conflict of versions of the configs, and can choose: delete, replace, or make merge.
    Each Linuxoid digging in configs surely faced this situation :) And legs grow from here.
    On each line there should be a complete absolute path to each config. For instance:
    /etc/supersh/init.conf
    /etc/supersh/actions.conf


    DEBIAN / dirs: list of folders to create

    “A list of absolute paths to folders that the program requires, but for some reason are not created.” Reads the official documentation. In practice, all folders are listed here, one way or another used by the program: where the binaries are and which are used by the program.
    One per line. For example: It is convenient to use to create several empty folders.
    /var/log/supersh
    /var/lib/supersh



    DEBIAN / menu: creating menu items

    A tricky file for creating menu items. It never worked for me :) One gets the feeling that its contents are used either in unusual window managers, or in some console menu ... or it was used earlier and was forgotten :)
    Example: TODO: find out why. This is written in , frankly, I did not delve :)
    ?package(supersh):needs="text" section="Applications/Programming" title="Super Shell Script" command="/usr/bin/super.sh"
    man5 menufile

    UPD: The correct way to add a menu item

    The file / DEBIAN / menu creates it is unknown what and it is not clear where: the elements of the graphic menu are still not created. Therefore, we will do it right :)
    We /usr/share/applicationssee a bunch of *.desktopfiles: these are the menu items. They are text files with syntax like an ini file. We open, study, do the same and put the resulting *.desktopfile in usr/share/applications/. The icon for it should be in usr/share/pixmaps.
    After that, you need to add the execution of the menu update command to the postinst script update-menus: Working with package installation scripts will be discussed later. Thanks Condorious for the tip :)
    if [ "$1" = "configure" ] && [ -x "`which update-menus 2>/dev/null`" ] ; then
    update-menus
    fi




    DEBIAN / md5sums: file checksums

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

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

    The function is useful if you maintain from dozens of packages, and keeping track of all updates is difficult.
    The file contains instructions for the uscan and uupdate programs. Using this opportunity, you can monitor the site from where the source code for the package was received, and provide quality control of the distribution as a whole.
    Example: And another example for uscan (1): Better read the official documentation , such powerful things are not often required by mere mortals :)
    # Site Directory Pattern Version Script
    ftp.obsession.se /gentoo gentoo-(.*)\.tar\.gz debian uupdate


    version=3
    madwimax.googlecode.com/files/madwimax-(.*)\.tar\.gz



    DEBIAN / cron.d: installing cron jobs

    The file contains a crontab piece 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 on the Internet, you can find

    Scripting


    We came to the most interesting: embedding scripts in deb packages. Scripts allow you to control the installation, reinstallation, and removal of a package by performing actions that cannot be done by simply copying files to the correct places. This can be downloading additional files (as flash-installer does), changing existing ones, and also displaying interactive (GUI or ncurses) dialogs that allow the user to configure the package for themselves: for example, mysql asks which password to set for root.
    All scripts are run as root (and what else :). They also receive arguments (which it is not necessary to process) that specify at what stage the installation is. Read more about it here .

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

    In total, you can create up to four scripts in one package:
    ScriptAppointment
    DEBIAN / preinstPerformed 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 use. The package is also interactively configured here: this is done using dh_input and the DEBIAN / templates file
    DEBIAN / prermIt is executed immediately before the package is uninstalled: usually this script cleans the installation paths of the package so that nothing is left behind :)
    DEBIAN / postrmIt is executed immediately after the package is removed: it cleans up the remains

    Please note that errors that occur in these scripts are not logged in any way : nothing more interesting than the script return code is 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 an error log (which is not available) to get the reason :) I
    recommend using the following disc at the beginning of each script: it will save all errors that occur in syslog. WARNING: the disc has not yet been tested extensively, check again! I came across the impossibility of debugging recently :)
    #!/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



    DEBIAN / templates: dialog templates

    As already mentioned, in the DEBIAN / config script you can ask the user questions: enter a line, select one of the options, put a check mark ... This is done by the “library” of bash functions of the debhelper package debconf, which is capable of besides a lot of useful things. I don’t consider them here :)
    The DEBIAN / templates file contains data used to display dialog boxes (GUI or ncurses). The file contains blocks separated by an empty string. Each block defines the resources used in one particular dialog box.
    The header for all types of dialogs is standard: Template - a unique (within the same package) identifier for the template. If in a script you need to call a specific dialog, this name is used.
    Template: supersh/template-name
    Type: string
    Default: Default-value
    Description: Dialog-title
    ␣Dialog-text


    Type - type of template. The following types are defined: string, password, boolean, select, multiselect, text, note, error.
    Default-value - 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 title of the “window,” 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 script”, “Mount point”, ...

    A typeTemplate Description
    stringText prompt
    passwordPassword prompt.
    There is no Default value for this type of template for obvious reasons :)
    booleanCheckmark :) Has a string value of “true” or “false”
    selectThe ability to choose one of several options.
    Options are offered in the optional template attribute:
    Choices: yes, no, maybe
    multiselectThe ability to select multiple options with check marks.
    Options are offered in the optional template attribute:
    Choices: sex, drugs, rock-n-roll
    textDisplays the text: some not very 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!


    The basics of using debconf and debhelper

    These are just workable drafts. You can read about the templates and working with them in the original here: man 7 debconf-devel:)
    To use the templates in your DEBIAN / config configuration script, you must first enable the debhelper: functions
    . /usr/share/debconf/confmodule. Also, this file must be included in the postinst script: otherwise the DEBIAN / config script will not execute at all!
    These features are available in the debconf package, remember 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 here: note that the priority of the medium dialog is passed to the db_input function. For debconf, you can set the minimum priority: dialogs with a priority below which are not displayed, but the default value (Default template) is taken! To prevent this from happening EXACTLY, we use critical priority :) In addition, when installing from the GUI, the output threshold for questions is higher, and many of them are not displayed at all.
    Possible priorities: low - default is always used, medium - default is usually quite suitable, high - default is undesirable, critical - user attention is vital.
    || trueused to prevent the script from dying due to the "-e" key passed to bash.
    В этом скрипте тоже рекомендуется использовать ту болванку для отлова ошибок, иначе с распространяемым пакетом могут возникнуть проблемы при отладке :)
    Все тонкости использования debconf (функции, способы, параметры, коды ошибок) описаны в достаточно многословном мане: man debconf-devel.

    И последнее: при удалении пакета командой purge — debconf должен также вычистить из своей базы сведения о пакете. Например, он сохраняет выбор пользователя при запросах db_input.
    Чтобы вычистить эти данные, нужно в postinst-скрипт добавить следующее:
    if [ "$1" == "purge" ] && [ -e /usr/share/debconf/confmodule ] ; then
    . /usr/share/debconf/confmodule
    db_purge
    fi


    Собираем пакет! :)


    Hurrah! All the necessary files are created, are on the right daddies. Now it's time to build the package :)
    The first thing to do is to recursively expose all the files in the root of the user package and the root: root group (or others, if necessary). This is necessary because the package files are packaged in a tar.gz archive which saves both file permissions and the owner. Therefore, you must perform: However, this is not necessary. There is an excellent fakeroot command which, when creating an archive, will replace the owner of the file with root. In our example, the script should have a feasibility bit. Then we go back to the folder so that the root folder of the package is visible, and the package is created with a light kick itself:
    $ sudo chown -R root:root .



    $ fakeroot dpkg-deb --build supersh
    The created package must be renamed so that it matches the naming order of * .deb packages: <package name> _ <version> _ <architecture> .deb
    $ mv supersh.deb supersh_1.0-1_all.deb
    That's it, the package is ready!

    Automatic package check

    There is a lintian utility that allows you to check the package and identify typical errors in its structure. It 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 will be several of them, 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 own repository”. The idea will be easy to develop, reading the relevant documentation :)
    First, install the assistant:
    $ sudo apt-get install reprepro

    Description of the future repository

    Repository Center - its description. The main thing in it is the list of repository components. We will create the “soft” and “games” components.
    Select a folder for the future repository. All actions are performed from its root.
    We create a conf / distributions file with the following content: In our business of creating a simple repository, all fields do not play a fundamental role, and are used only for visual definition of “what is what” :)
    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



    Create Repository

    The repository is described! Now we will generate a blank based on the description. The commands are executed at the root of the repository: And add the finished repository to /etc/apt/sources.list: This repository can also be shared using a web server.
    $ reprepro export
    $ reprepro createsymlinks


    deb file:///path/to/repo/ karmic soft games


    Manage packages in the repository

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

    Finish


    This article discusses materials for creating deb packages. The emphasis is on moments for which the network does not have a sufficiently clear description. I hope that my attempt to state it simply and clearly did not fail :)
    Homework :)) are quite well-documented things that are easy to find in man's and articles:
    • Creation of source packages compiling source codes: the example of Zabbix was perfectly described by hahor browser mahoro in his article
    • Debconf, debhelper in configuration scripts: read mana by debconf-devel and debhelper. They also allow you to create a package skeleton with the dh_make command.
    • Advanced ways to create documentation in packages: files DEBIAN / docs, DEBIAN / manpage. *
    • Creating init scripts
    • Cron job management
    • Repository signing with gpg key


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

    Cheers! :)

    PS There are probably inaccuracies and errors in the article. Let's comb her together! :)

    Also popular now: