Chapter 14. More Examples

# Chapter 14. More Examples

There is an old Latin saying: “fabricando fit faber” (“practice makes perfect”).

It is highly recommended to practice and experiment with all the steps of Debian packaging with simple packages. This chapter provides you with many upstream cases for your practice.

This should also serve as introductory examples for many programming topics.

- Programming in the POSIX shell, Python3, and C.
- Method to create a desktop GUI program launcher with icon graphics.
- Conversion of a command from CLI to GUI.
- Conversion of a program to use gettext for internationalization and localization: POSIX shell and C sources.
- Overview of many build systems: Makefile, Python, Autotools, and CMake.

Please note that Debian takes a few things seriously:

- Free software (a.k.a. Libre software)
- Stability and security of OS

- Universal OS realized via:

  - free choice for upstream sources,
  - free choice of CPU architectures, and
  - free choice of UI languages.

The typical packaging example presented in “Chapter 5, Simple packaging” is the prerequisite for this chapter.

Some details are intentionally left vague in the following sections. Please try to read the pertinent documentation and practice yourself to find them out.

| Tip
The best source of a packaging example is the current Debian archive itself. Please use the “Debian Code Search” service to find pertinent examples.

## 14.1. Cherry-pick templates

Here is an example of creating a simple Debian package from a zero-content source in an empty directory.

This is a good way to obtain all the template files without cluttering the upstream source tree you are working on.

Let’s assume this empty directory to be debhello-0.1.

    [base_dir] $ mkdir debhello-0.1
    [base_dir] $ tree
    .
    └── debhello-0.1

    2 directories, 0 files

Let’s generate the maximum amount of template files.

Let’s also use the “-p debhello -t -x3 -u 0.1 -r 1” options to create the missing upstream tarball with optional -x3, and -t options.

    [base_dir] $ cd debhello-0.1
    [debhello-0.1] $ debmake -p debhello -x3 -t -T -u 0.1 -r 1
    I: debmake (version: 5.1.4)
     ...

Let’s inspect generated template files.

    [debhello-0.1] $ cd ..
    [base_dir] $ tree
    .
    ├── debhello-0.1
    │   └── debian
    │       ├── README.Debian
    │       ├── README.source
    │       ├── bug-control.ex
    │       ├── bug-presubj.ex
    │       ├── bug-script.ex
    │       ├── changelog
    │       ├── clean
    │       ├── conffiles.ex
    │       ├── control
    │       ├── copyright
    │       ├── cron.d.ex
    │       ├── cron.daily.ex
    │       ├── cron.hourly.ex
    │       ├── cron.monthly.ex
    │       ├── cron.weekly.ex
    │       ├── default.ex
    │       ├── dirs
    │       ├── doc-base.ex
    │       ├── docs
    │       ├── emacsen-install.ex
    │       ├── emacsen-remove.ex
    │       ├── emacsen-startup.ex
    │       ├── examples
    │       ├── gbp.conf
    │       ├── info.ex
    │       ├── install
    │       ├── links
    │       ├── lintian-overrides.ex
    │       ├── maintscript.ex
    │       ├── manpage.1.ex
    │       ├── manpage.asciidoc.ex
    │       ├── manpage.md.ex
    │       ├── manpage.sgml.ex
    │       ├── manpage.xml.ex
    │       ├── manpages
    │       ├── patches
    │       │   └── series
    │       ├── postinst.ex
    │       ├── postrm.ex
    │       ├── preinst.ex
    │       ├── prerm.ex
    │       ├── rules
    │       ├── salsa-ci.yml
    │       ├── service.ex
    │       ├── source
    │       │   ├── format
    │       │   ├── lintian-overrides.ex
    │       │   ├── options.ex
    │       │   └── patch-header.ex
    │       ├── tests
    │       │   └── control
    │       ├── tmpfile.ex
    │       ├── upstream
    │       │   └── metadata
    │       └── watch
    ├── debhello-0.1.tar.xz
    └── debhello_0.1.orig.tar.xz -> debhello-0.1.tar.xz

    7 directories, 53 files

Now you can copy any of these generated template files in the debhello-0.1/debian/ directory to your package as needed while renaming them as needed.

## 14.2. No Makefile (shell, CLI)

Here is an example of creating a simple Debian package from a POSIX shell CLI program without its build system.

Let’s assume this upstream tarball to be debhello-0.2.tar.xz.

This type of source has no automated means and files must be installed manually.

For example:

    [base_dir] $ tar --xz -xmf debhello-0.2.tar.xz
    [base_dir] $ cd debhello-0.2
    [debhello-0.2] $ sudo cp scripts/hello /bin/hello
     ...

Let’s get this source as tar file from a remote site and make it the Debian package.

Download debhello-0.2.tar.xz.

    [base_dir] $ wget http://www.example.org/download/debhello-0.2.tar.xz
     ...
    [base_dir] $ tar --xz -xmf debhello-0.2.tar.xz
    [base_dir] $ tree
    .
    ├── debhello-0.2
    │   ├── README.md
    │   ├── data
    │   │   ├── hello.desktop
    │   │   └── hello.png
    │   ├── man
    │   │   └── hello.1
    │   └── scripts
    │       └── hello
    └── debhello-0.2.tar.xz

    5 directories, 6 files

Here, the POSIX shell script hello is a very simple one.

hello (v=0.2).

    [base_dir] $ cat debhello-0.2/scripts/hello
    #!/bin/sh -e
    echo "Hello from the shell!"
    echo ""
    echo -n "Type Enter to exit this program: "
    read X

Here, hello.desktop supports the “Desktop Entry Specification”.

hello.desktop (v=0.2).

    [base_dir] $ cat debhello-0.2/data/hello.desktop
    [Desktop Entry]
    Name=Hello
    Name[fr]=Bonjour
    Comment=Greetings
    Comment[fr]=Salutations
    Type=Application
    Keywords=hello
    Exec=hello
    Terminal=true
    Icon=hello.png
    Categories=Utility;

Here, hello.png is the icon graphics file.

Let’s package this with the debmake command. Here, the -b':sh' option is used to specify that the generated binary package is a shell script.

    [base_dir] $ cd debhello-0.2
    [debhello-0.2] $ debmake -b':sh' -x1
    I: debmake (version: 5.1.4)
    I: Copyright © 2014-2026 Osamu Aoki <osamu@debian.org>
    I: [debhello-0.2] $ cd ..
    I: Non-native Debian package pkg="debhello", ver="0.2", rev="1" method="dir_d...
    I: already in the package-version form: "debhello-0.2"
    I: [base_dir] $ ln -sf debhello-0.2.tar.xz debhello_0.2.orig.tar.xz
    I: [base_dir] $ cd debhello-0.2
    I: parsing option -b ":sh"
    I: binary package=debhello Type=script / Arch=all M-A=foreign
    I: build_type = Unknown
    I: ext_type = 1                       1 files
    I: ext_type = desktop                 1 files
    I: ext_type = md                      1 files
    I: creating debian/* files with "-x 1" option
    I: [debhello-0.2] $ licensecheck --recursive --copyright --deb-machine  . > d...
    I: creating debian/copyright by licensecheck.
    I: creating debian/control from control.py
    I: creating debian/control by control.py
    I: creating debian/changelog from extra0_changelog
    I: creating debian/rules from extra0_rules
    I: creating debian/source/format from extra0source_format
     ...

Let’s inspect notable template files generated.

The source tree after the basic debmake execution. (v=0.2).

    [debhello-0.2] $ cd ..
    [base_dir] $ tree
    .
    ├── debhello-0.2
    │   ├── README.md
    │   ├── data
    │   │   ├── hello.desktop
    │   │   └── hello.png
    │   ├── debian
    │   │   ├── README.Debian
    │   │   ├── README.source
    │   │   ├── changelog
    │   │   ├── clean
    │   │   ├── control
    │   │   ├── copyright
    │   │   ├── dirs
    │   │   ├── docs
    │   │   ├── examples
    │   │   ├── gbp.conf
    │   │   ├── install
    │   │   ├── links
    │   │   ├── manpages
    │   │   ├── patches
    │   │   │   └── series
    │   │   ├── rules
    │   │   ├── salsa-ci.yml
    │   │   ├── source
    │   │   │   └── format
    │   │   ├── tests
    │   │   │   └── control
    │   │   ├── upstream
    │   │   │   └── metadata
    │   │   └── watch
    │   ├── man
    │   │   └── hello.1
    │   └── scripts
    │       └── hello
    ├── debhello-0.2.tar.xz
    └── debhello_0.2.orig.tar.xz -> debhello-0.2.tar.xz

    10 directories, 27 files

debian/rules (template file, v=0.2):

    [base_dir] $ cd debhello-0.2
    [debhello-0.2] $ cat debian/rules
    #!/usr/bin/make -f
    # You must remove unused comment lines for the released package.
    # See debhelper(7) (un-comment to enable)
    # This is an autogenerated template for debian/rules.
    #
    # Output every command that modifies files on the build system.
    #export DH_VERBOSE = 1
    #
    # Copy some variable definitions from pkg-info.mk and vendor.mk
    # under /usr/share/dpkg/ to here if they are useful.
    #
    # These are rarely used code. (START)
    #
    # The following include for *.mk magically sets miscellaneous
    # variables while honoring existing values of pertinent
    # environment variables:
    #
    # Architecture-related variables such as DEB_TARGET_MULTIARCH:
    #include /usr/share/dpkg/architecture.mk
    # Vendor-related variables such as DEB_VENDOR:
    #include /usr/share/dpkg/vendor.mk
    # Package-related variables such as DEB_DISTRIBUTION
    #include /usr/share/dpkg/pkg-info.mk
    #
    # You may alternatively set them susing a simple script such as:
    # DEB_VENDOR ?= $(shell dpkg-vendor --query  Vendor)
    #
    # These are rarely used code. (END)
    #

    ### main packaging script based on post dh7 syntax
    %:
            dh $@

    # debmake generated override targets

This is essentially the standard debian/rules file with the dh command. Since this is the script package, this template debian/rules file has no build flag related contents.

debian/control (template file, v=0.2):

    [debhello-0.2] $ cat debian/control
    Source: debhello
    Section: unknown
    Priority: optional
    Maintainer: "Osamu Aoki" <osamu@debian.org>
    Build-Depends:
     debhelper-compat (= 13),
    Standards-Version: 4.7.3
    Homepage: <insert the upstream URL, if relevant>
    Rules-Requires-Root: no
    #Vcs-Git: https://salsa.debian.org/debian/debhello.git
    #Vcs-Browser: https://salsa.debian.org/debian/<project_site>

    Package: debhello
    Section: unknown
    Architecture: all
    Multi-Arch: foreign
    Depends:
     ${misc:Depends},
    Description: auto-generated package by debmake
     This Debian binary package was auto-generated by the
     debmake(1) command provided by the debmake package.
     .
     ===== This comes from the unmodified template file =====
     .
     Please edit this template file (debian/control) and other package files
     (debian/*) to make them meet all the requirements of the Debian Policy
     before uploading this package to the Debian archive.
     .
     See
      * https://www.debian.org/doc/manuals/developers-reference/best-pkging-pract...
      * https://www.debian.org/doc/manuals/debmake-doc/ch05.en.html#control
     .
     The synopsis description at the top should be about 60 characters and
     written as a phrase.  No extra capital letters or a final period.  No
     articles — "a", "an", or "the".
     .
     The package description for general-purpose applications should be
     written for a less technical user.  This means that we should avoid
     jargon.  GNOME or KDE is fine but GTK+ is probably not.
     .
     Use the canonical forms of words:
      * Use X Window System, X11, or X; not X Windows, X-Windows, or X Window.
      * Use GTK+, not GTK or gtk.
      * Use GNOME, not Gnome.
      * Use PostScript, not Postscript or postscript.

Since this is the shell script package, the debmake command sets “Architecture: all” and “Multi-Arch: foreign”. Also, it sets required substvar parameters as “Depends: ${misc:Depends}”. These are explained in “Chapter 6, Basics for packaging”.

Since this upstream source lacks the upstream Makefile, that functionality needs to be provided by the maintainer. This upstream source contains only a script file and data files and no C source files; the build process can be skipped but the install process needs to be implemented. For this case, this is achieved cleanly by adding the debian/install and debian/manpages files without complicating the debian/rules file.

Let’s make this Debian package better as the maintainer.

debian/rules (maintainer version, v=0.2):

    [base_dir] $ cd debhello-0.2
    [debhello-0.2] $ vim debian/rules
     ... hack, hack, hack, ...
    [debhello-0.2] $ cat debian/rules
    #!/usr/bin/make -f
    export DH_VERBOSE = 1

    %:
            dh $@

debian/control (maintainer version, v=0.2):

    [debhello-0.2] $ vim debian/control
     ... hack, hack, hack, ...
    [debhello-0.2] $ cat debian/control
    Source: debhello
    Section: devel
    Priority: optional
    Maintainer: Osamu Aoki <osamu@debian.org>
    Build-Depends:
     debhelper-compat (= 13),
    Standards-Version: 4.7.3
    Homepage: https://salsa.debian.org/debian/debmake-doc
    Rules-Requires-Root: no

    Package: debhello
    Architecture: all
    Multi-Arch: foreign
    Depends:
     ${misc:Depends},
    Description: Simple packaging example for debmake
     This Debian binary package is an example package.
     (This is an example only)

| Warning
If you leave “Section: unknown” in the template debian/control file unchanged, the lintian error may cause a build failure.

debian/install (maintainer version, v=0.2):

    [debhello-0.2] $ vim debian/install
     ... hack, hack, hack, ...
    [debhello-0.2] $ cat debian/install
    data/hello.desktop usr/share/applications
    data/hello.png usr/share/pixmaps
    scripts/hello usr/bin

debian/manpages (maintainer version, v=0.2):

     $ vim debian/manpages
     ... hack, hack, hack, ...
    [debhello-0.2] $ cat debian/manpages
    man/hello.1

There are several other template files under the debian/ directory. These also need to be updated.

Template files under debian/. (v=0.2):

    [debhello-0.2] $ rm -f debian/clean debian/dirs debian/links
    [debhello-0.2] $ rm -f debian/README.source debian/source/*.ex
    [debhello-0.2] $ rm -rf debian/patches
    [debhello-0.2] $ tree -F debian
    debian/
    ├── README.Debian
    ├── changelog
    ├── control
    ├── copyright
    ├── docs
    ├── examples
    ├── gbp.conf
    ├── install
    ├── manpages
    ├── rules*
    ├── salsa-ci.yml
    ├── source/
    │   └── format
    ├── tests/
    │   └── control
    ├── upstream/
    │   └── metadata
    └── watch

    4 directories, 15 files

You can create a non-native Debian package using the debuild command (or its equivalents) in this source tree. The command output is very verbose and explains what it does as follows.

    [base_dir] $ cd debhello-0.2
    [debhello-0.2] $ debuild
     dpkg-buildpackage -us -uc -ui -i
    dpkg-buildpackage: info: source package debhello
    dpkg-buildpackage: info: source version 0.2-1
    dpkg-buildpackage: info: source distribution unstable
    dpkg-buildpackage: info: source changed by Osamu Aoki <osamu@debian.org>
     dpkg-source -i --before-build .
    dpkg-buildpackage: info: host architecture amd64
     debian/rules clean
    dh clean
       dh_clean
            rm -f debian/debhelper-build-stamp
     ...
     debian/rules binary
    dh binary
       dh_update_autotools_config
       dh_autoreconf
       create-stamp debian/debhelper-build-stamp
       dh_prep
            rm -f -- debian/debhello.substvars
            rm -fr -- debian/.debhelper/generated/debhello/ debian/debhello/ debi...
       dh_auto_install --destdir=debian/debhello/
     ...
    Finished running lintian.

Let’s inspect the result.

The generated files of debhello version 0.2 by the debuild command:

    [debhello-0.2] $ cd ..
    [base_dir] $ tree -FL 1
    ./
    ├── debhello-0.2/
    ├── debhello-0.2.tar.xz
    ├── debhello_0.2-1.debian.tar.xz
    ├── debhello_0.2-1.dsc
    ├── debhello_0.2-1_all.deb
    ├── debhello_0.2-1_amd64.build
    ├── debhello_0.2-1_amd64.buildinfo
    ├── debhello_0.2-1_amd64.changes
    └── debhello_0.2.orig.tar.xz -> debhello-0.2.tar.xz

    2 directories, 8 files

You see all the generated files.

- The debhello_0.2.orig.tar.xz file is a symlink to the upstream tarball.
- The debhello_0.2-1.debian.tar.xz file contains the maintainer generated contents.
- The debhello_0.2-1.dsc file is the meta data file for the Debian source package.
- The debhello_0.2-1_all.deb file is the Debian binary package.
- The debhello_0.2-1_amd64.build file is the build log file.
- The debhello_0.2-1_amd64.buildinfo file is the meta data file generated by dpkg-genbuildinfo(1).
- The debhello_0.2-1_amd64.changes file is the meta data file for the Debian binary package.

The debhello_0.2-1.debian.tar.xz file contains the Debian changes to the upstream source as follows.

The compressed archive contents of debhello_0.2-1.debian.tar.xz:

    [base_dir] $ tar --xz -tf debhello-0.2.tar.xz
    debhello-0.2/
    debhello-0.2/data/
    debhello-0.2/data/hello.desktop
    debhello-0.2/data/hello.png
    debhello-0.2/man/
    debhello-0.2/man/hello.1
    debhello-0.2/scripts/
    debhello-0.2/scripts/hello
    debhello-0.2/README.md
    [base_dir] $ tar --xz -tf debhello_0.2-1.debian.tar.xz
    debian/
    debian/README.Debian
    debian/changelog
    debian/control
    debian/copyright
    debian/docs
    debian/examples
    debian/gbp.conf
    debian/install
    debian/manpages
    debian/rules
    debian/salsa-ci.yml
    debian/source/
    debian/source/format
    debian/tests/
    debian/tests/control
    debian/upstream/
    debian/upstream/metadata
    debian/watch

The debhello_0.2-1_amd64.deb file contains the files to be installed as follows.

The binary package contents of debhello_0.2-1_all.deb:

    [base_dir] $ dpkg -c debhello_0.2-1_all.deb
    drwxr-xr-x root/root ...  ./
    drwxr-xr-x root/root ...  ./usr/
    drwxr-xr-x root/root ...  ./usr/bin/
    -rwxr-xr-x root/root ...  ./usr/bin/hello
    drwxr-xr-x root/root ...  ./usr/share/
    drwxr-xr-x root/root ...  ./usr/share/applications/
    -rw-r--r-- root/root ...  ./usr/share/applications/hello.desktop
    drwxr-xr-x root/root ...  ./usr/share/doc/
    drwxr-xr-x root/root ...  ./usr/share/doc/debhello/
    -rw-r--r-- root/root ...  ./usr/share/doc/debhello/README.Debian
    -rw-r--r-- root/root ...  ./usr/share/doc/debhello/changelog.Debian.gz
    -rw-r--r-- root/root ...  ./usr/share/doc/debhello/copyright
    drwxr-xr-x root/root ...  ./usr/share/man/
    drwxr-xr-x root/root ...  ./usr/share/man/man1/
    -rw-r--r-- root/root ...  ./usr/share/man/man1/hello.1.gz
    drwxr-xr-x root/root ...  ./usr/share/pixmaps/
    -rw-r--r-- root/root ...  ./usr/share/pixmaps/hello.png

Here is the generated dependency list of debhello_0.2-1_all.deb.

The generated dependency list of debhello_0.2-1_all.deb:

    [debhello-0.2] $ dpkg -f debhello_0.2-1_all.deb pre-depends \
                depends recommends conflicts breaks

(No extra dependency packages required since this is a POSIX shell program.)

| Note
If you wish to replace upstream provided PNG file data/hello.png with maintainer provided one debian/hello.png, editing debian/install isn’t enough. When you add debian/hello.png, you need to add a line “include-binaries” to debian/source/options since PNG is a binary file. See dpkg-source(1).

/tep200.slog/ vim:set filetype=asciidoc:

## 14.3. Makefile (shell, CLI)

Here is an example of creating a simple Debian package from a POSIX shell CLI program using the Makefile as its build system.

Let’s assume its upstream tarball to be debhello-1.0.tar.xz.

This type of source is meant to be installed as a non-system file as:

    [base_dir] $ tar --xz -xmf debhello-1.0.tar.xz
    [base_dir] $ cd debhello-1.0
    [debhello-1.0] $ make install

Debian packaging requires changing this “make install” process to install files to the target system image location instead of the normal location under /usr/local.

Let’s get the source and make the Debian package.

Download debhello-1.0.tar.xz.

    [base_dir] $ wget http://www.example.org/download/debhello-1.0.tar.xz
     ...
    [base_dir] $ tar --xz -xmf debhello-1.0.tar.xz
    [base_dir] $ tree
    .
    ├── debhello-1.0
    │   ├── Makefile
    │   ├── README.md
    │   ├── data
    │   │   ├── hello.desktop
    │   │   └── hello.png
    │   ├── man
    │   │   └── hello.1
    │   └── scripts
    │       └── hello
    └── debhello-1.0.tar.xz

    5 directories, 7 files

Here, the Makefile uses $(DESTDIR) and $(prefix) properly. All other files are the same as in “Section 14.2, “No Makefile (shell, CLI)”” and most of the packaging activities are the same.

Makefile (v=1.0).

    [base_dir] $ cat debhello-1.0/Makefile
    prefix = /usr/local

    all:
            : # do nothing

    install:
            install -D scripts/hello \
                    $(DESTDIR)$(prefix)/bin/hello
            install -m 644 -D data/hello.desktop \
                    $(DESTDIR)$(prefix)/share/applications/hello.desktop
            install -m 644 -D data/hello.png \
                    $(DESTDIR)$(prefix)/share/pixmaps/hello.png
            install -m 644 -D man/hello.1 \
                    $(DESTDIR)$(prefix)/share/man/man1/hello.1

    clean:
            : # do nothing

    distclean: clean

    uninstall:
            -rm -f $(DESTDIR)$(prefix)/bin/hello
            -rm -f $(DESTDIR)$(prefix)/share/applications/hello.desktop
            -rm -f $(DESTDIR)$(prefix)/share/pixmaps/hello.png
            -rm -f $(DESTDIR)$(prefix)/share/man/man1/hello.1

    .PHONY: all install clean distclean uninstall

Let’s package this with the debmake command. Here, the -b':sh' option is used to specify that the generated binary package is a shell script.

    [base_dir] $ cd debhello-1.0
    [debhello-1.0] $ debmake -b':sh' -x1
    I: debmake (version: 5.1.4)
    I: Copyright © 2014-2026 Osamu Aoki <osamu@debian.org>
    I: [debhello-1.0] $ cd ..
    I: Non-native Debian package pkg="debhello", ver="1.0", rev="1" method="dir_d...
    I: already in the package-version form: "debhello-1.0"
    I: [base_dir] $ ln -sf debhello-1.0.tar.xz debhello_1.0.orig.tar.xz
    I: [base_dir] $ cd debhello-1.0
    I: parsing option -b ":sh"
    I: binary package=debhello Type=script / Arch=all M-A=foreign
    I: build_type = make
    I: ext_type = 1                       1 files
    I: ext_type = desktop                 1 files
    I: ext_type = md                      1 files
    I: creating debian/* files with "-x 1" option
    I: [debhello-1.0] $ licensecheck --recursive --copyright --deb-machine  . > d...
    I: creating debian/copyright by licensecheck.
    I: creating debian/control from control.py
    I: creating debian/control by control.py
    I: creating debian/changelog from extra0_changelog
    I: creating debian/rules from extra0_rules
    I: creating debian/source/format from extra0source_format
     ...

Let’s inspect the notable template files generated.

debian/rules (template file, v=1.0):

    [base_dir] $ cd debhello-1.0
    [debhello-1.0] $ cat debian/rules
    #!/usr/bin/make -f
    # You must remove unused comment lines for the released package.
    # See debhelper(7) (un-comment to enable)
    # This is an autogenerated template for debian/rules.
    #
    # Output every command that modifies files on the build system.
    #export DH_VERBOSE = 1
    #
    # Copy some variable definitions from pkg-info.mk and vendor.mk
    # under /usr/share/dpkg/ to here if they are useful.
    #
    # These are rarely used code. (START)
    #
    # The following include for *.mk magically sets miscellaneous
    # variables while honoring existing values of pertinent
    # environment variables:
    #
    # Architecture-related variables such as DEB_TARGET_MULTIARCH:
    #include /usr/share/dpkg/architecture.mk
    # Vendor-related variables such as DEB_VENDOR:
    #include /usr/share/dpkg/vendor.mk
    # Package-related variables such as DEB_DISTRIBUTION
    #include /usr/share/dpkg/pkg-info.mk
    #
    # You may alternatively set them susing a simple script such as:
    # DEB_VENDOR ?= $(shell dpkg-vendor --query  Vendor)
    #
    # These are rarely used code. (END)
    #

    ### main packaging script based on post dh7 syntax
    %:
            dh $@

    # debmake generated override targets
    # Use "make prefix=/usr" (override prefix=/usr/local in Makefile)
    #override_dh_auto_install:
    #       dh_auto_install -- prefix=/usr

    # Do not install python .pyc .pyo if they exist
    #override_dh_install:
    #       dh_install --list-missing -X.pyc -X.pyo

Let’s make this Debian package better as the maintainer.

debian/rules (maintainer version, v=1.0):

    [base_dir] $ cd debhello-1.0
    [debhello-1.0] $ vim debian/rules
     ... hack, hack, hack, ...
    [debhello-1.0] $ cat debian/rules
    #!/usr/bin/make -f
    export DH_VERBOSE = 1

    %:
            dh $@

    override_dh_auto_install:
            dh_auto_install -- prefix=/usr

Since this upstream source has the proper upstream Makefile, there is no need to create debian/install and debian/manpages files.

The debian/control file is exactly the same as the one in “Section 14.2, “No Makefile (shell, CLI)””.

There are several other template files under the debian/ directory. These also need to be updated.

Template files under debian/. (v=1.0):

    [debhello-1.0] $ rm -f debian/clean debian/dirs debian/install debian/links
    [debhello-1.0] $ rm -f debian/README.source debian/source/*.ex
    [debhello-1.0] $ rm -rf debian/patches
    [debhello-1.0] $ tree -F debian
    debian/
    ├── README.Debian
    ├── changelog
    ├── control
    ├── copyright
    ├── docs
    ├── examples
    ├── gbp.conf
    ├── manpages
    ├── rules*
    ├── salsa-ci.yml
    ├── source/
    │   └── format
    ├── tests/
    │   └── control
    ├── upstream/
    │   └── metadata
    └── watch

    4 directories, 14 files

The rest of the packaging activities are practically the same as the ones in “Section 14.2, “No Makefile (shell, CLI)””.

## 14.4. pyproject.toml (Python3, CLI)

Here is an example of creating a simple Debian package from a Python3 CLI program using pyproject.toml.

Let’s get the source and make the Debian package.

Download debhello-1.1.tar.xz.

    [base_dir] $ wget http://www.example.org/download/debhello-1.1.tar.xz
     ...
    [base_dir] $ tar --xz -xmf debhello-1.1.tar.xz
    [base_dir] $ tree
    .
    ├── debhello-1.1
    │   ├── LICENSE
    │   ├── MANIFEST.in
    │   ├── README.md
    │   ├── data
    │   │   ├── hello.desktop
    │   │   └── hello.png
    │   ├── manpages
    │   │   └── hello.1
    │   ├── pyproject.toml
    │   └── src
    │       └── debhello
    │           ├── __init__.py
    │           └── main.py
    └── debhello-1.1.tar.xz

    6 directories, 10 files

Here, the content of this debhello source tree as follows.

pyproject.toml (v=1.1) —PEP 517 configuration.

    [base_dir] $ cat debhello-1.1/pyproject.toml
    [build-system]
    requires = ["setuptools >= 61.0"]  # REQUIRED if [build-system] table is used...
    build-backend = "setuptools.build_meta"  # If not defined, then legacy behavi...

    [project]
    name = "debhello"
    version = "1.1.0"
    description = "Hello Python (CLI)"
    readme = {file = "README.md", content-type = "text/markdown"}
    requires-python = ">=3.12"
    license = "MIT"
    keywords = ["debhello"]
    authors = [
      {name = "Osamu Aoki", email = "osamu@debian.org" },
    ]
    maintainers = [
      {name = "Osamu Aoki", email = "osamu@debian.org" },
    ]
    classifiers = [
      "Development Status :: 5 - Production/Stable",
      "Intended Audience :: Developers",
            "Topic :: System :: Archiving :: Packaging",
      "Programming Language :: Python :: 3",
      "Programming Language :: Python :: 3.12",
      "Programming Language :: Python :: 3 :: Only",
      # Others
      "Operating System :: POSIX :: Linux",
      "Natural Language :: English",
    ]
    [project.urls]
    "Homepage" = "https://salsa.debian.org/debian/debmake"
    "Bug Reports" = "https://salsa.debian.org/debian/debmake/issues"
    "Source" = "https://salsa.debian.org/debian/debmake"
    [project.scripts]
    hello = "debhello.main:main"
    [tool.setuptools]
    package-dir = {"" = "src"}
    packages = ["debhello"]
    include-package-data = true

MANIFEST.in (v=1.1) — for tar-ball.

    [base_dir] $ cat debhello-1.1/MANIFEST.in
    include data/*
    include manpages/*

src/debhello/__init__.py (v=1.1).

    [base_dir] $ cat debhello-1.1/src/debhello/__init__.py
    """
    debhello program (CLI)
    """

src/debhello/main.py (v=1.1) — command entry point.

    [base_dir] $ cat debhello-1.1/src/debhello/main.py
    """
    debhello program
    """

    import sys

    __version__ = '1.1.0'

    def main():  # needed for console script
        print(' ========== Hello Python3 ==========')
        print('argv = {}'.format(sys.argv))
        print('version = {}'.format(debhello.__version__))
        return

    if __name__ == "__main__":
        sys.exit(main())

Let’s package this with the debmake command. Here, the -b':py3' option is used to specify the generated binary package containing Python3 script and module files.

    [base_dir] $ cd debhello-1.1
    [debhello-1.1] $ debmake -b':py3' -x1
    I: debmake (version: 5.1.4)
    I: Copyright © 2014-2026 Osamu Aoki <osamu@debian.org>
    I: [debhello-1.1] $ cd ..
    I: Non-native Debian package pkg="debhello", ver="1.1", rev="1" method="dir_d...
    I: already in the package-version form: "debhello-1.1"
    I: [base_dir] $ ln -sf debhello-1.1.tar.xz debhello_1.1.orig.tar.xz
    I: [base_dir] $ cd debhello-1.1
    I: parsing option -b ":py3"
    I: binary package=debhello Type=python3 / Arch=all M-A=foreign
    W: setuptools build system.
    I: build_type = Python (pyproject.toml: PEP-518, PEP-621, PEP-660)
    I: ext_type = python3                 2 files
    I: ext_type = 1                       1 files
    I: ext_type = desktop                 1 files
    I: creating debian/* files with "-x 1" option
    I: [debhello-1.1] $ licensecheck --recursive --copyright --deb-machine  . > d...
    I: creating debian/copyright by licensecheck.
    I: creating debian/control from control.py
    I: creating debian/control by control.py
    I: creating debian/changelog from extra0_changelog
    I: creating debian/rules from extra0_rules
     ...

Let’s inspect the notable template files generated.

debian/rules (template file, v=1.1):

    [base_dir] $ cd debhello-1.1
    [debhello-1.1] $ cat debian/rules
    #!/usr/bin/make -f
    # You must remove unused comment lines for the released package.
    # See debhelper(7) (un-comment to enable)
    # This is an autogenerated template for debian/rules.
    #
    # Output every command that modifies files on the build system.
    #export DH_VERBOSE = 1
    #
    # Copy some variable definitions from pkg-info.mk and vendor.mk
    # under /usr/share/dpkg/ to here if they are useful.
    #
    # These are rarely used code. (START)
    #
    # The following include for *.mk magically sets miscellaneous
    # variables while honoring existing values of pertinent
    # environment variables:
    #
    # Architecture-related variables such as DEB_TARGET_MULTIARCH:
    #include /usr/share/dpkg/architecture.mk
    # Vendor-related variables such as DEB_VENDOR:
    #include /usr/share/dpkg/vendor.mk
    # Package-related variables such as DEB_DISTRIBUTION
    #include /usr/share/dpkg/pkg-info.mk
    #
    # You may alternatively set them susing a simple script such as:
    # DEB_VENDOR ?= $(shell dpkg-vendor --query  Vendor)
    #
    # These are rarely used code. (END)
    #

    ### main packaging script based on post dh7 syntax
    %:
            dh $@ --with python3 --buildsystem=pybuild

    # debmake generated override targets
    # Too complicated to provide examples here.
    #
    # Check situation of Python on Debian
    #     https://wiki.debian.org/Python
    #
    #     https://wiki.debian.org/Python/TransitionToDHPython2
    #     https://wiki.debian.org/Python/Pybuild
    #     https://wiki.debian.org/Python/LibraryStyleGuide
    #
    # If a module package doesn't use distutils or setuptools but uses flit
    # you need flit plugin.  See pybuild(1).
    #
    # Pure PEP-517 based build with "python3 -m build ..." is supported.
    #
    # To update the upstream source to support python3, see
    #     https://wiki.python.org/moin/Python2orPython3
    #     https://wiki.python.org/moin/PortingToPy3k/BilingualQuickRef

This is essentially the standard debian/rules file with the dh command.

The use of the “--with python3” option invokes dh_python3 to calculate Python dependencies, add maintainer scripts to byte compiled files, etc. See dh_python3(1).

The use of the “--buildsystem=pybuild” option invokes various build systems for requested Python versions in order to build modules and extensions. See pybuild(1).

debian/control (template file, v=1.1):

    [debhello-1.1] $ cat debian/control
    Source: debhello
    Section: unknown
    Priority: optional
    Maintainer: "Osamu Aoki" <osamu@debian.org>
    Build-Depends:
     debhelper-compat (= 13),
     dh-python,
     pybuild-plugin-pyproject,
     python3-all,
     python3-setuptools,
    Standards-Version: 4.7.3
    Homepage: <insert the upstream URL, if relevant>
    Rules-Requires-Root: no
    #Vcs-Git: https://salsa.debian.org/debian/debhello.git
    #Vcs-Browser: https://salsa.debian.org/debian/<project_site>

    Package: debhello
    Section: unknown
    Architecture: all
    Multi-Arch: foreign
    Depends:
     ${misc:Depends},
     ${python3:Depends},
    Description: auto-generated package by debmake
     This Debian binary package was auto-generated by the
     debmake(1) command provided by the debmake package.
     .
     ===== This comes from the unmodified template file =====
     .
     Please edit this template file (debian/control) and other package files
     (debian/*) to make them meet all the requirements of the Debian Policy
     before uploading this package to the Debian archive.
     .
     See
      * https://www.debian.org/doc/manuals/developers-reference/best-pkging-pract...
      * https://www.debian.org/doc/manuals/debmake-doc/ch05.en.html#control
     .
     The synopsis description at the top should be about 60 characters and
     written as a phrase.  No extra capital letters or a final period.  No
     articles — "a", "an", or "the".
     .
     The package description for general-purpose applications should be
     written for a less technical user.  This means that we should avoid
     jargon.  GNOME or KDE is fine but GTK+ is probably not.
     .
     Use the canonical forms of words:
      * Use X Window System, X11, or X; not X Windows, X-Windows, or X Window.
      * Use GTK+, not GTK or gtk.
      * Use GNOME, not Gnome.
      * Use PostScript, not Postscript or postscript.

Since this is the Python3 package, the debmake command sets “Architecture: all” and “Multi-Arch: foreign”. Also, it sets required substvar parameters as “Depends: ${python3:Depends}, ${misc:Depends}”. These are explained in “Chapter 6, Basics for packaging”.

Let’s make this Debian package better as the maintainer.

debian/rules (maintainer version, v=1.1):

    [base_dir] $ cd debhello-1.1
    [debhello-1.1] $ vim debian/rules
     ... hack, hack, hack, ...
    [debhello-1.1] $ cat debian/rules
    #!/usr/bin/make -f
    export PYBUILD_NAME=debhello
    export PYBUILD_VERBOSE=1
    export DH_VERBOSE=1

    %:
            dh $@ --with python3 --buildsystem=pybuild

debian/control (maintainer version, v=1.1):

    [debhello-1.1] $ vim debian/control
     ... hack, hack, hack, ...
    [debhello-1.1] $ cat debian/control
    Source: debhello
    Section: devel
    Priority: optional
    Maintainer: Osamu Aoki <osamu@debian.org>
    Build-Depends:
     debhelper-compat (= 13),
     pybuild-plugin-pyproject,
     python3-all,
    Standards-Version: 4.7.3
    Rules-Requires-Root: no
    Vcs-Browser: https://salsa.debian.org/debian/debmake-doc
    Vcs-Git: https://salsa.debian.org/debian/debmake-doc.git
    Homepage: https://salsa.debian.org/debian/debmake-doc

    Package: debhello
    Architecture: all
    Depends:
     ${misc:Depends},
     ${python3:Depends},
    Description: Simple packaging example for debmake
     This is an example package to demonstrate Debian packaging using
     the debmake command.
     .
     The generated Debian package uses the dh command offered by the
     debhelper package and the dpkg source format `3.0 (quilt)'.

There are several other template files under the debian/ directory. These also need to be updated.

This debhello command comes with the upstream-provided manpage and desktop file but the upstream pyproject.toml doesn’t install them. So you need to update debian/install and debian/manpages as follows:

debian/install (maintainer version, v=1.1):

    [debhello-1.1] $ vim debian/copyright
     ... hack, hack, hack, ...
    [debhello-1.1] $ cat debian/copyright
    Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
    Upstream-Name: debhello
    Upstream-Contact: Osamu Aoki <osamu@debian.org>
    Source: https://salsa.debian.org/debian/debmake-doc

    Files:     *
    Copyright: 2015-2024 Osamu Aoki <osamu@debian.org>
    License:   Expat
     Permission is hereby granted, free of charge, to any person obtaining a
     copy of this software and associated documentation files (the "Software"),
     to deal in the Software without restriction, including without limitation
     the rights to use, copy, modify, merge, publish, distribute, sublicense,
     and/or sell copies of the Software, and to permit persons to whom the
     Software is furnished to do so, subject to the following conditions:
     .
     The above copyright notice and this permission notice shall be included
     in all copies or substantial portions of the Software.
     .
     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
     CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

debian/manpages (maintainer version, v=1.1):

    [debhello-1.1] $ vim debian/install
     ... hack, hack, hack, ...
    [debhello-1.1] $ cat debian/install
    data/hello.desktop usr/share/applications
    data/hello.png usr/share/pixmaps

The rest of the packaging activities are practically the same as the ones in “Section 14.3, “Makefile (shell, CLI)””.

Template files under debian/. (v=1.1):

    [debhello-1.1] $ rm -f debian/clean debian/dirs debian/links
    [debhello-1.1] $ rm -f debian/README.source debian/source/*.ex
    [debhello-1.1] $ rm -rf debian/patches
    [debhello-1.1] $ tree -F debian
    debian/
    ├── README.Debian
    ├── changelog
    ├── control
    ├── copyright
    ├── docs
    ├── examples
    ├── gbp.conf
    ├── install
    ├── manpages
    ├── rules*
    ├── salsa-ci.yml
    ├── source/
    │   └── format
    ├── tests/
    │   └── control
    ├── upstream/
    │   └── metadata
    └── watch

    4 directories, 15 files

Here is the generated dependency list of debhello_1.1-1_all.deb.

The generated dependency list of debhello_1.1-1_all.deb:

    [debhello-1.1] $ dpkg -f debhello_1.1-1_all.deb pre-depends \
                depends recommends conflicts breaks
    Depends: python3:any

## 14.5. Makefile (shell, GUI)

Here is an example of creating a simple Debian package from a POSIX shell GUI program using the Makefile as its build system.

This upstream is based on “Section 14.3, “Makefile (shell, CLI)”” with enhanced GUI support.

Let’s assume its upstream tarball to be debhello-1.2.tar.xz.

Let’s get the source and make the Debian package.

Download debhello-1.2.tar.xz.

    [base_dir] $ wget http://www.example.org/download/debhello-1.2.tar.xz
     ...
    [base_dir] $ tar --xz -xmf debhello-1.2.tar.xz
    [base_dir] $ tree
    .
    ├── debhello-1.2
    │   ├── Makefile
    │   ├── README.md
    │   ├── data
    │   │   ├── hello.desktop
    │   │   └── hello.png
    │   ├── man
    │   │   └── hello.1
    │   └── scripts
    │       └── hello
    └── debhello-1.2.tar.xz

    5 directories, 7 files

Here, the hello has been re-written to use the zenity command to make this a GTK+ GUI program.

hello (v=1.2).

    [base_dir] $ cat debhello-1.2/scripts/hello
    #!/bin/sh -e
    zenity --info --title "hello" --text "Hello from the shell!"

Here, the desktop file is updated to be Terminal=false as a GUI program.

hello.desktop (v=1.2).

    [base_dir] $ cat debhello-1.2/data/hello.desktop
    [Desktop Entry]
    Name=Hello
    Name[fr]=Bonjour
    Comment=Greetings
    Comment[fr]=Salutations
    Type=Application
    Keywords=hello
    Exec=hello
    Terminal=false
    Icon=hello.png
    Categories=Utility;

All other files are the same as in “Section 14.3, “Makefile (shell, CLI)””.

Let’s package this with the debmake command. Here, the “-b':sh'” option is used to specify that the generated binary package is a shell script.

    [base_dir] $ cd debhello-1.2
    [debhello-1.2] $ debmake -b':sh' -x1
    I: debmake (version: 5.1.4)
    I: Copyright © 2014-2026 Osamu Aoki <osamu@debian.org>
    I: [debhello-1.2] $ cd ..
    I: Non-native Debian package pkg="debhello", ver="1.2", rev="1" method="dir_d...
    I: already in the package-version form: "debhello-1.2"
    I: [base_dir] $ ln -sf debhello-1.2.tar.xz debhello_1.2.orig.tar.xz
    I: [base_dir] $ cd debhello-1.2
    I: parsing option -b ":sh"
    I: binary package=debhello Type=script / Arch=all M-A=foreign
    I: build_type = make
    I: ext_type = 1                       1 files
    I: ext_type = desktop                 1 files
    I: ext_type = md                      1 files
    I: creating debian/* files with "-x 1" option
    I: [debhello-1.2] $ licensecheck --recursive --copyright --deb-machine  . > d...
    I: creating debian/copyright by licensecheck.
    I: creating debian/control from control.py
    I: creating debian/control by control.py
    I: creating debian/changelog from extra0_changelog
    I: creating debian/rules from extra0_rules
    I: creating debian/source/format from extra0source_format
     ...

Let’s inspect the notable template files generated.

debian/control (template file, v=1.2):

    [debhello-1.2] $ cat debian/control
    Source: debhello
    Section: unknown
    Priority: optional
    Maintainer: "Osamu Aoki" <osamu@debian.org>
    Build-Depends:
     debhelper-compat (= 13),
    Standards-Version: 4.7.3
    Homepage: <insert the upstream URL, if relevant>
    Rules-Requires-Root: no
    #Vcs-Git: https://salsa.debian.org/debian/debhello.git
    #Vcs-Browser: https://salsa.debian.org/debian/<project_site>

    Package: debhello
    Section: unknown
    Architecture: all
    Multi-Arch: foreign
    Depends:
     ${misc:Depends},
    Description: auto-generated package by debmake
     This Debian binary package was auto-generated by the
     debmake(1) command provided by the debmake package.
     .
     ===== This comes from the unmodified template file =====
     .
     Please edit this template file (debian/control) and other package files
     (debian/*) to make them meet all the requirements of the Debian Policy
     before uploading this package to the Debian archive.
     .
     See
      * https://www.debian.org/doc/manuals/developers-reference/best-pkging-pract...
      * https://www.debian.org/doc/manuals/debmake-doc/ch05.en.html#control
     .
     The synopsis description at the top should be about 60 characters and
     written as a phrase.  No extra capital letters or a final period.  No
     articles — "a", "an", or "the".
     .
     The package description for general-purpose applications should be
     written for a less technical user.  This means that we should avoid
     jargon.  GNOME or KDE is fine but GTK+ is probably not.
     .
     Use the canonical forms of words:
      * Use X Window System, X11, or X; not X Windows, X-Windows, or X Window.
      * Use GTK+, not GTK or gtk.
      * Use GNOME, not Gnome.
      * Use PostScript, not Postscript or postscript.

Let’s make this Debian package better as the maintainer.

debian/control (maintainer version, v=1.2):

    [debhello-1.2] $ vim debian/control
     ... hack, hack, hack, ...
    [debhello-1.2] $ cat debian/control
    Source: debhello
    Section: devel
    Priority: optional
    Maintainer: Osamu Aoki <osamu@debian.org>
    Build-Depends:
     debhelper-compat (= 13),
    Standards-Version: 4.7.3
    Homepage: https://salsa.debian.org/debian/debmake-doc
    Rules-Requires-Root: no

    Package: debhello
    Architecture: all
    Multi-Arch: foreign
    Depends:
     zenity,
     ${misc:Depends},
    Description: Simple packaging example for debmake
     This Debian binary package is an example package.
     (This is an example only)

Please note the manually added zenity dependency.

The debian/rules file is exactly the same as the one in “Section 14.3, “Makefile (shell, CLI)””.

There are several other template files under the debian/ directory. These also need to be updated.

Template files under debian/. (v=1.2):

    [debhello-1.2] $ rm -f debian/clean debian/dirs debian/install debian/links
    [debhello-1.2] $ rm -f debian/README.source debian/source/*.ex
    [debhello-1.2] $ rm -rf debian/patches
    [debhello-1.2] $ tree -F debian
    debian/
    ├── README.Debian
    ├── changelog
    ├── control
    ├── copyright
    ├── docs
    ├── examples
    ├── gbp.conf
    ├── manpages
    ├── rules*
    ├── salsa-ci.yml
    ├── source/
    │   └── format
    ├── tests/
    │   └── control
    ├── upstream/
    │   └── metadata
    └── watch

    4 directories, 14 files

The rest of the packaging activities are practically the same as in “Section 14.3, “Makefile (shell, CLI)””.

Here is the generated dependency list of debhello_1.2-1_all.deb.

The generated dependency list of debhello_1.2-1_all.deb:

    [debhello-1.2] $ dpkg -f debhello_1.2-1_all.deb pre-depends \
                depends recommends conflicts breaks
    Depends: zenity

## 14.6. pyproject.toml (Python3, GUI)

Here is an example of creating a simple Debian package from a Python3 GUI program using pyproject.toml.

Let’s assume this upstream tarball to be debhello-1.3.tar.xz.

Let’s get the source and make the Debian package.

Download debhello-1.3.tar.xz.

    [base_dir] $ wget http://www.example.org/download/debhello-1.3.tar.xz
     ...
    [base_dir] $ tar --xz -xmf debhello-1.3.tar.xz
    [base_dir] $ tree
    .
    ├── debhello-1.3
    │   ├── LICENSE
    │   ├── MANIFEST.in
    │   ├── README.md
    │   ├── data
    │   │   ├── hello.desktop
    │   │   └── hello.png
    │   ├── manpages
    │   │   └── hello.1
    │   ├── pyproject.toml
    │   └── src
    │       └── debhello
    │           ├── __init__.py
    │           └── main.py
    └── debhello-1.3.tar.xz

    6 directories, 10 files

Here, the content of this debhello source tree as follows.

pyproject.toml (v=1.3) —PEP 517 configuration.

    [base_dir] $ cat debhello-1.3/pyproject.toml
    [build-system]
    requires = ["setuptools >= 61.0"]  # REQUIRED if [build-system] table is used...
    build-backend = "setuptools.build_meta"  # If not defined, then legacy behavi...

    [project]
    name = "debhello"
    version = "1.3.0"
    description = "Hello Python (GUI)"
    readme = {file = "README.md", content-type = "text/markdown"}
    requires-python = ">=3.12"
    license = "MIT"
    keywords = ["debhello"]
    authors = [
      {name = "Osamu Aoki", email = "osamu@debian.org" },
    ]
    maintainers = [
      {name = "Osamu Aoki", email = "osamu@debian.org" },
    ]
    classifiers = [
      "Development Status :: 5 - Production/Stable",
      "Intended Audience :: Developers",
            "Topic :: System :: Archiving :: Packaging",
      "Programming Language :: Python :: 3",
      "Programming Language :: Python :: 3.12",
      "Programming Language :: Python :: 3 :: Only",
      # Others
      "Operating System :: POSIX :: Linux",
      "Natural Language :: English",
    ]
    [project.urls]
    "Homepage" = "https://salsa.debian.org/debian/debmake"
    "Bug Reports" = "https://salsa.debian.org/debian/debmake/issues"
    "Source" = "https://salsa.debian.org/debian/debmake"
    [project.scripts]
    hello = "debhello.main:main"
    [tool.setuptools]
    package-dir = {"" = "src"}
    packages = ["debhello"]
    include-package-data = true

MANIFEST.in (v=1.3) — for tar-ball.

    [base_dir] $ cat debhello-1.3/MANIFEST.in
    include data/*
    include manpages/*

src/debhello/__init__.py (v=1.3).

    [base_dir] $ cat debhello-1.3/src/debhello/__init__.py
    """
    debhello program (GUI)
    """

src/debhello/main.py (v=1.3) — command entry point.

    [base_dir] $ cat debhello-1.3/src/debhello/main.py
    #!/usr/bin/python3
    from gi.repository import Gtk

    __version__ = '1.3.0'

    class TopWindow(Gtk.Window):

        def __init__(self):
            Gtk.Window.__init__(self)
            self.title = "Hello World!"
            self.counter = 0
            self.border_width = 10
            self.set_default_size(400, 100)
            self.set_position(Gtk.WindowPosition.CENTER)
            self.button = Gtk.Button(label="Click me!")
            self.button.connect("clicked", self.on_button_clicked)
            self.add(self.button)
            self.connect("delete-event", self.on_window_destroy)

        def on_window_destroy(self, *args):
            Gtk.main_quit(*args)

        def on_button_clicked(self, widget):
            self.counter += 1
            widget.set_label("Hello, World!\nClick count = %i" % self.counter)

    def main():
        window = TopWindow()
        window.show_all()
        Gtk.main()

    if __name__ == '__main__':
        main()

Let’s package this with the debmake command. Here, the -b':py3' option is used to specify that the generated binary package contains Python3 script and module files.

    [base_dir] $ cd debhello-1.3
    [debhello-1.3] $ debmake -b':py3' -x1
    I: debmake (version: 5.1.4)
    I: Copyright © 2014-2026 Osamu Aoki <osamu@debian.org>
    I: [debhello-1.3] $ cd ..
    I: Non-native Debian package pkg="debhello", ver="1.3", rev="1" method="dir_d...
    I: already in the package-version form: "debhello-1.3"
    I: [base_dir] $ ln -sf debhello-1.3.tar.xz debhello_1.3.orig.tar.xz
    I: [base_dir] $ cd debhello-1.3
    I: parsing option -b ":py3"
    I: binary package=debhello Type=python3 / Arch=all M-A=foreign
    W: setuptools build system.
    I: build_type = Python (pyproject.toml: PEP-518, PEP-621, PEP-660)
    I: ext_type = python3                 2 files
    I: ext_type = 1                       1 files
    I: ext_type = desktop                 1 files
    I: creating debian/* files with "-x 1" option
    I: [debhello-1.3] $ licensecheck --recursive --copyright --deb-machine  . > d...
    I: creating debian/copyright by licensecheck.
    I: creating debian/control from control.py
    I: creating debian/control by control.py
    I: creating debian/changelog from extra0_changelog
    I: creating debian/rules from extra0_rules
     ...

The result is practically the same as in “Section 14.4, “pyproject.toml (Python3, CLI)””.

Let’s make this Debian package better as the maintainer.

debian/rules (maintainer version, v=1.3):

    [base_dir] $ cd debhello-1.3
    [debhello-1.3] $ vim debian/rules
     ... hack, hack, hack, ...
    [debhello-1.3] $ cat debian/rules
    #!/usr/bin/make -f
    export PYBUILD_NAME=debhello
    export PYBUILD_VERBOSE=1
    export DH_VERBOSE=1

    %:
            dh $@ --with python3 --buildsystem=pybuild

debian/control (maintainer version, v=1.3):

    [debhello-1.3] $ vim debian/control
     ... hack, hack, hack, ...
    [debhello-1.3] $ cat debian/control
    Source: debhello
    Section: devel
    Priority: optional
    Maintainer: Osamu Aoki <osamu@debian.org>
    Build-Depends:
     debhelper-compat (= 13),
     pybuild-plugin-pyproject,
     python3-all,
    Standards-Version: 4.7.3
    Homepage: https://salsa.debian.org/debian/debmake-doc
    Rules-Requires-Root: no

    Package: debhello
    Architecture: all
    Multi-Arch: foreign
    Depends:
     gir1.2-gtk-3.0,
     python3-gi,
     ${misc:Depends},
     ${python3:Depends},
    Description: Simple packaging example for debmake
     This Debian binary package is an example package.
     (This is an example only)

Please note the manually added python3-gi and gir1.2-gtk-3.0 dependencies.

The rest of the packaging activities are practically the same as in <pyproject>>.

Here is the generated dependency list of debhello_1.3-1_all.deb.

The generated dependency list of debhello_1.3-1_all.deb:

    [debhello-1.3] $ dpkg -f debhello_1.3-1_all.deb pre-depends \
                depends recommends conflicts breaks
    Depends: gir1.2-gtk-3.0, python3-gi, python3:any

## 14.7. Makefile (single-binary package)

Here is an example of creating a simple Debian package from a simple C source program using the Makefile as its build system.

This is an enhanced upstream source example for “Chapter 5, Simple packaging”. This comes with the manpage, the desktop file, and the desktop icon. This also links to an external library libm to be a more practical example.

Let’s assume this upstream tarball to be debhello-1.4.tar.xz.

This type of source is meant to be installed as a non-system file as:

    [base_dir] $ tar --xz -xmf debhello-1.4.tar.xz
    [base_dir] $ cd debhello-1.4
    [debhello-1.4] $ make
    [debhello-1.4] $ make install

Debian packaging requires changing this “make install” process to install files into the target system image location instead of the normal location under /usr/local.

Let’s get the source and make the Debian package.

Download debhello-1.4.tar.xz.

    [base_dir] $ wget http://www.example.org/download/debhello-1.4.tar.xz
     ...
    [base_dir] $ tar --xz -xmf debhello-1.4.tar.xz
    [base_dir] $ tree
    .
    ├── debhello-1.4
    │   ├── LICENSE
    │   ├── Makefile
    │   ├── README.md
    │   ├── data
    │   │   ├── hello.desktop
    │   │   └── hello.png
    │   ├── man
    │   │   └── hello.1
    │   └── src
    │       ├── config.h
    │       └── hello.c
    └── debhello-1.4.tar.xz

    5 directories, 9 files

Here, the contents of this source are as follows.

src/hello.c (v=1.4):

    [base_dir] $ cat debhello-1.4/src/hello.c
    #include "config.h"
    #include <math.h>
    #include <stdio.h>
    int
    main()
    {
            printf("Hello, I am " PACKAGE_AUTHOR "!\n");
            printf("4.0 * atan(1.0) = %10f8\n", 4.0*atan(1.0));
            return 0;
    }

src/config.h (v=1.4):

    [base_dir] $ cat debhello-1.4/Makefile
    prefix = /usr/local

    all: src/hello

    src/hello: src/hello.c
            $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $^ -lm

    install: src/hello
            install -D src/hello \
                    $(DESTDIR)$(prefix)/bin/hello
            install -m 644 -D data/hello.desktop \
                    $(DESTDIR)$(prefix)/share/applications/hello.desktop
            install -m 644 -D data/hello.png \
                    $(DESTDIR)$(prefix)/share/pixmaps/hello.png
            install -m 644 -D man/hello.1 \
                    $(DESTDIR)$(prefix)/share/man/man1/hello.1

    clean:
            -rm -f src/hello

    distclean: clean

    uninstall:
            -rm -f $(DESTDIR)$(prefix)/bin/hello
            -rm -f $(DESTDIR)$(prefix)/share/applications/hello.desktop
            -rm -f $(DESTDIR)$(prefix)/share/pixmaps/hello.png
            -rm -f $(DESTDIR)$(prefix)/share/man/man1/hello.1

    .PHONY: all install clean distclean uninstall

Makefile (v=1.4):

    [base_dir] $ cat debhello-1.4/src/config.h
    #define PACKAGE_AUTHOR "Osamu Aoki"

Please note that this Makefile has the proper install target for the manpage, the desktop file, and the desktop icon.

Let’s package this with the debmake command.

    [base_dir] $ cd debhello-1.4
    [debhello-1.4] $ debmake -x1
    I: debmake (version: 5.1.4)
    I: Copyright © 2014-2026 Osamu Aoki <osamu@debian.org>
    I: [debhello-1.4] $ cd ..
    I: Non-native Debian package pkg="debhello", ver="1.4", rev="1" method="dir_d...
    I: already in the package-version form: "debhello-1.4"
    I: [base_dir] $ ln -sf debhello-1.4.tar.xz debhello_1.4.orig.tar.xz
    I: [base_dir] $ cd debhello-1.4
    I: parsing option -b ""
    I: binary package=debhello Type=bin / Arch=any M-A=foreign
    I: build_type = make
    I: ext_type = c                       2 files
    I: ext_type = 1                       1 files
    I: ext_type = desktop                 1 files
    I: creating debian/* files with "-x 1" option
    I: [debhello-1.4] $ licensecheck --recursive --copyright --deb-machine  . > d...
    I: creating debian/copyright by licensecheck.
    I: creating debian/control from control.py
    I: creating debian/control by control.py
    I: creating debian/changelog from extra0_changelog
    I: creating debian/rules from extra0_rules
    I: creating debian/source/format from extra0source_format
     ...

The result is practically the same as in “Section 5.6, “Step 2: Generate template files with debmake””.

Let’s make this Debian package, which is practically the same as in “Section 5.7, “Step 3: Modification to the template files””, better as the maintainer.

If the DEB_BUILD_MAINT_OPTIONS environment variable is not exported in debian/rules, lintian warns “W: debhello: hardening-no-relro usr/bin/hello” for the linking of libm.

The debian/control file makes it exactly the same as the one in “Section 5.7, “Step 3: Modification to the template files””, since the libm library is always available as a part of libc6 (Priority: required).

There are several other template files under the debian/ directory. These also need to be updated.

Template files under debian/. (v=1.4):

    [debhello-1.4] $ rm -f debian/clean debian/dirs debian/links
    [debhello-1.4] $ rm -f debian/README.source debian/source/*.ex
    [debhello-1.4] $ rm -rf debian/patches
    [debhello-1.4] $ tree -F debian
    debian/
    ├── README.Debian
    ├── changelog
    ├── control
    ├── copyright
    ├── docs
    ├── examples
    ├── gbp.conf
    ├── install
    ├── manpages
    ├── rules*
    ├── salsa-ci.yml
    ├── source/
    │   └── format
    ├── tests/
    │   └── control
    ├── upstream/
    │   └── metadata
    └── watch

    4 directories, 15 files

The rest of the packaging activities are practically the same as the one in “Section 5.8, “Step 4: Building package with debuild””.

Here is the generated dependency list of all binary packages.

The generated dependency list of all binary packages (v=1.4):

    [debhello-1.4] $ dpkg -f debhello-dbgsym_1.4-1_amd64.deb pre-depends \
                depends recommends conflicts breaks
    Depends: debhello (= 1.4-1)
    [debhello-1.4] $ dpkg -f debhello_1.4-1_amd64.deb pre-depends \
                depends recommends conflicts breaks
    Depends: libc6 (>= 2.34)

## 14.8. Makefile.in + configure (single-binary package)

Here is an example of creating a simple Debian package from a simple C source program using Makefile.in and configure as its build system.

This is an enhanced upstream source example for “Section 14.7, “Makefile (single-binary package)””. This also links to an external library, libm, and this source is configurable using arguments to the configure script, which generates the Makefile and src/config.h files.

Let’s assume this upstream tarball to be debhello-1.5.tar.xz.

This type of source is meant to be installed as a non-system file, for example, as:

    [base_dir] $ tar --xz -xmf debhello-1.5.tar.xz
    [base_dir] $ cd debhello-1.5
    [debhello-1.5] $ ./configure --with-math
    [debhello-1.5] $ make
    [debhello-1.5] $ make install

Let’s get the source and make the Debian package.

Download debhello-1.5.tar.xz.

    [base_dir] $ wget http://www.example.org/download/debhello-1.5.tar.xz
     ...
    [base_dir] $ tar --xz -xmf debhello-1.5.tar.xz
    [base_dir] $ tree
    .
    ├── debhello-1.5
    │   ├── LICENSE
    │   ├── Makefile.in
    │   ├── README.md
    │   ├── configure
    │   ├── data
    │   │   ├── hello.desktop
    │   │   └── hello.png
    │   ├── man
    │   │   └── hello.1
    │   └── src
    │       └── hello.c
    └── debhello-1.5.tar.xz

    5 directories, 9 files

Here, the contents of this source are as follows.

src/hello.c (v=1.5):

    [base_dir] $ cat debhello-1.5/src/hello.c
    #include "config.h"
    #ifdef WITH_MATH
    #  include <math.h>
    #endif
    #include <stdio.h>
    int
    main()
    {
            printf("Hello, I am " PACKAGE_AUTHOR "!\n");
    #ifdef WITH_MATH
            printf("4.0 * atan(1.0) = %10f8\n", 4.0*atan(1.0));
    #else
            printf("I can't do MATH!\n");
    #endif
            return 0;
    }

Makefile.in (v=1.5):

    [base_dir] $ cat debhello-1.5/Makefile.in
    prefix = @prefix@

    all: src/hello

    src/hello: src/hello.c
            $(CC) @VERBOSE@ \
                    $(CPPFLAGS) \
                    $(CFLAGS) \
                    $(LDFLAGS) \
                    -o $@ $^ \
                    @LINKLIB@

    install: src/hello
            install -D src/hello \
                    $(DESTDIR)$(prefix)/bin/hello
            install -m 644 -D data/hello.desktop \
                    $(DESTDIR)$(prefix)/share/applications/hello.desktop
            install -m 644 -D data/hello.png \
                    $(DESTDIR)$(prefix)/share/pixmaps/hello.png
            install -m 644 -D man/hello.1 \
                    $(DESTDIR)$(prefix)/share/man/man1/hello.1

    clean:
            -rm -f src/hello

    distclean: clean

    uninstall:
            -rm -f $(DESTDIR)$(prefix)/bin/hello
            -rm -f $(DESTDIR)$(prefix)/share/applications/hello.desktop
            -rm -f $(DESTDIR)$(prefix)/share/pixmaps/hello.png
            -rm -f $(DESTDIR)$(prefix)/share/man/man1/hello.1

    .PHONY: all install clean distclean uninstall

configure (v=1.5):

    [base_dir] $ cat debhello-1.5/configure
    #!/bin/sh -e
    # default values
    PREFIX="/usr/local"
    VERBOSE=""
    WITH_MATH="0"
    LINKLIB=""
    PACKAGE_AUTHOR="John Doe"

    # parse arguments
    while [ "${1}" != "" ]; do
      VAR="${1%=*}" # Drop suffix =*
      VAL="${1#*=}" # Drop prefix *=
      case "${VAR}" in
      --prefix)
        PREFIX="${VAL}"
        ;;
      --verbose|-v)
        VERBOSE="-v"
        ;;
      --with-math)
        WITH_MATH="1"
        LINKLIB="-lm"
        ;;
      --author)
        PACKAGE_AUTHOR="${VAL}"
        ;;
      *)
        echo "W: Unknown argument: ${1}"
      esac
      shift
    done

    # setup configured Makefile and src/config.h
    sed -e "s,@prefix@,${PREFIX}," \
        -e "s,@VERBOSE@,${VERBOSE}," \
        -e "s,@LINKLIB@,${LINKLIB}," \
        <Makefile.in >Makefile
    if [ "${WITH_MATH}" = 1 ]; then
    echo "#define WITH_MATH" >src/config.h
    else
    echo "/* not defined: WITH_MATH */" >src/config.h
    fi
    echo "#define PACKAGE_AUTHOR \"${PACKAGE_AUTHOR}\"" >>src/config.h

Please note that the configure command replaces strings with @…​@ in Makefile.in to produce Makefile and creates src/config.h.

Let’s package this with the debmake command.

    [base_dir] $ cd debhello-1.5
    [debhello-1.5] $ debmake -x1
    I: debmake (version: 5.1.4)
    I: Copyright © 2014-2026 Osamu Aoki <osamu@debian.org>
    I: [debhello-1.5] $ cd ..
    I: Non-native Debian package pkg="debhello", ver="1.5", rev="1" method="dir_d...
    I: already in the package-version form: "debhello-1.5"
    I: [base_dir] $ ln -sf debhello-1.5.tar.xz debhello_1.5.orig.tar.xz
    I: [base_dir] $ cd debhello-1.5
    I: parsing option -b ""
    I: binary package=debhello Type=bin / Arch=any M-A=foreign
    I: build_type = configure
    I: ext_type = c                       1 files
    I: ext_type = 1                       1 files
    I: ext_type = desktop                 1 files
    I: creating debian/* files with "-x 1" option
    I: [debhello-1.5] $ licensecheck --recursive --copyright --deb-machine  . > d...
    I: creating debian/copyright by licensecheck.
    I: creating debian/control from control.py
    I: creating debian/control by control.py
    I: creating debian/changelog from extra0_changelog
    I: creating debian/rules from extra0_rules
    I: creating debian/source/format from extra0source_format
     ...

The result is similar to “Section 5.6, “Step 2: Generate template files with debmake”” but not exactly the same.

Let’s inspect the notable template files generated.

debian/rules (template file, v=1.5):

    [base_dir] $ cd debhello-1.5
    [debhello-1.5] $ cat debian/rules
    #!/usr/bin/make -f
    # You must remove unused comment lines for the released package.
    # See debhelper(7) (un-comment to enable)
    # This is an autogenerated template for debian/rules.
    #
    # Output every command that modifies files on the build system.
    #export DH_VERBOSE = 1
    #
    # Copy some variable definitions from pkg-info.mk and vendor.mk
    # under /usr/share/dpkg/ to here if they are useful.
    #
    # See FEATURE AREAS/ENVIRONMENT in dpkg-buildflags(1)
    # Apply all hardening options
    #export DEB_BUILD_MAINT_OPTIONS = hardening=+all
    # Package maintainers to append CFLAGS
    #export DEB_CFLAGS_MAINT_APPEND  = -Wall -pedantic
    # Package maintainers to append LDFLAGS
    #export DEB_LDFLAGS_MAINT_APPEND = -Wl,-O1
    #
    # With debhelper version 9 or newer, the dh command exports
    # all buildflags.  So there is no need to include the
    # /usr/share/dpkg/buildflags.mk file here if compat is 9 or newer.
    #
    # These are rarely used code. (START)
    #
    # The following include for *.mk magically sets miscellaneous
    # variables while honoring existing values of pertinent
    # environment variables:
    #
    # Architecture-related variables such as DEB_TARGET_MULTIARCH:
    #include /usr/share/dpkg/architecture.mk
    # Vendor-related variables such as DEB_VENDOR:
    #include /usr/share/dpkg/vendor.mk
    # Package-related variables such as DEB_DISTRIBUTION
    #include /usr/share/dpkg/pkg-info.mk
    #
    # You may alternatively set them susing a simple script such as:
    # DEB_VENDOR ?= $(shell dpkg-vendor --query  Vendor)
    #
    # These are rarely used code. (END)
    #

    ### main packaging script based on post dh7 syntax
    %:
            dh $@

    # debmake generated override targets
    # Multiarch package requires library files to be installed to
    # /usr/lib/<triplet>/ .  If the build system does not support
    # $(DEB_HOST_MULTIARCH), you may need to override some targets such as
    # dh_auto_configure or dh_auto_install to use $(DEB_HOST_MULTIARCH) .

Let’s make this Debian package better as the maintainer.

debian/rules (maintainer version, v=1.5):

    [base_dir] $ cd debhello-1.5
    [debhello-1.5] $ vim debian/rules
     ... hack, hack, hack, ...
    [debhello-1.5] $ cat debian/rules
    #!/usr/bin/make -f
    export DH_VERBOSE = 1
    export DEB_BUILD_MAINT_OPTIONS = hardening=+all
    export DEB_CFLAGS_MAINT_APPEND  = -Wall -pedantic
    export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed

    %:
            dh $@

    override_dh_auto_configure:
            dh_auto_configure -- \
                    --with-math \
                    --author="Osamu Aoki"

There are several other template files under the debian/ directory. These also need to be updated.

The rest of the packaging activities are practically the same as the one in “Section 5.8, “Step 4: Building package with debuild””.

## 14.9. Autotools (single-binary package)

Here is an example of creating a simple Debian package from a simple C source program using Autotools = Autoconf and Automake (Makefile.am and configure.ac) as its build system.

This source usually comes with the upstream auto-generated Makefile.in and configure files, too. This source can be packaged using these files as in “Section 14.8, “Makefile.in + configure (single-binary package)”” with the help of the autotools-dev package.

The better alternative is to regenerate these files using the latest Autoconf and Automake packages if the upstream provided Makefile.am and configure.ac are compatible with the latest version. This is advantageous for porting to new CPU architectures, etc. This can be automated by using the “--with autoreconf” option for the dh command.

Let’s assume this upstream tarball to be debhello-1.6.tar.xz.

This type of source is meant to be installed as a non-system file, for example, as:

    [base_dir] $ tar --xz -xmf debhello-1.6.tar.xz
    [base_dir] $ cd debhello-1.6
    [debhello-1.6] $ autoreconf -ivf # optional
    [debhello-1.6] $ ./configure --with-math
    [debhello-1.6] $ make
    [debhello-1.6] $ make install

Let’s get the source and make the Debian package.

Download debhello-1.6.tar.xz.

    [base_dir] $ wget http://www.example.org/download/debhello-1.6.tar.xz
     ...
    [base_dir] $ tar --xz -xmf debhello-1.6.tar.xz
    [base_dir] $ tree
    .
    ├── debhello-1.6
    │   ├── LICENSE
    │   ├── Makefile.am
    │   ├── README.md
    │   ├── configure.ac
    │   ├── data
    │   │   ├── hello.desktop
    │   │   └── hello.png
    │   ├── man
    │   │   ├── Makefile.am
    │   │   └── hello.1
    │   └── src
    │       ├── Makefile.am
    │       └── hello.c
    └── debhello-1.6.tar.xz

    5 directories, 11 files

Here, the contents of this source are as follows.

src/hello.c (v=1.6):

    [base_dir] $ cat debhello-1.6/src/hello.c
    #include "config.h"
    #ifdef WITH_MATH
    #  include <math.h>
    #endif
    #include <stdio.h>
    int
    main()
    {
            printf("Hello, I am " PACKAGE_AUTHOR "!\n");
    #ifdef WITH_MATH
            printf("4.0 * atan(1.0) = %10f8\n", 4.0*atan(1.0));
    #else
            printf("I can't do MATH!\n");
    #endif
            return 0;
    }

Makefile.am (v=1.6):

    [base_dir] $ cat debhello-1.6/Makefile.am
    SUBDIRS = src man
    [base_dir] $ cat debhello-1.6/man/Makefile.am
    dist_man_MANS = hello.1
    [base_dir] $ cat debhello-1.6/src/Makefile.am
    bin_PROGRAMS = hello
    hello_SOURCES = hello.c

configure.ac (v=1.6):

    [base_dir] $ cat debhello-1.6/configure.ac
    #                                               -*- Autoconf -*-
    # Process this file with autoconf to produce a configure script.
    AC_PREREQ([2.69])
    AC_INIT([debhello],[2.1],[foo@example.org])
    AC_CONFIG_SRCDIR([src/hello.c])
    AC_CONFIG_HEADERS([config.h])
    echo "Standard customization chores"
    AC_CONFIG_AUX_DIR([build-aux])
    AM_INIT_AUTOMAKE([foreign])
    # Add #define PACKAGE_AUTHOR ... in config.h with a comment
    AC_DEFINE(PACKAGE_AUTHOR, ["Osamu Aoki"], [Define PACKAGE_AUTHOR])
    echo "Add --with-math option functionality to ./configure"
    AC_ARG_WITH([math],
      [AS_HELP_STRING([--with-math],
        [compile with math library  @<:@default=yes@:>@])],
      [],
      [with_math="yes"]
      )
    echo "==== withval   := \"$withval\""
    echo "==== with_math := \"$with_math\""
    # m4sh if-else construct
    AS_IF([test "x$with_math" != "xno"],[
      echo "==== Check include: math.h"
      AC_CHECK_HEADER(math.h,[],[
        AC_MSG_ERROR([Couldn't find math.h.] )
      ])
      echo "==== Check library: libm"
      AC_SEARCH_LIBS(atan, [m])
      #AC_CHECK_LIB(m, atan)
      echo "==== Build with LIBS := \"$LIBS\""
      AC_DEFINE(WITH_MATH, [1], [Build with the math library])
    ],[
      echo "==== Skip building with math.h."
      AH_TEMPLATE(WITH_MATH, [Build without the math library])
    ])
    # Checks for programs.
    AC_PROG_CC
    AC_CONFIG_FILES([Makefile
                     man/Makefile
                     src/Makefile])
    AC_OUTPUT

| Tip
Without “foreign” strictness level specified in AM_INIT_AUTOMAKE() as above, automake defaults to “gnu” strictness level requiring several files in the top-level directory. See “3.2 Strictness” in the automake document.

Let’s package this with the debmake command.

    [base_dir] $ cd debhello-1.6
    [debhello-1.6] $ debmake -x1
    I: debmake (version: 5.1.4)
    I: Copyright © 2014-2026 Osamu Aoki <osamu@debian.org>
    I: [debhello-1.6] $ cd ..
    I: Non-native Debian package pkg="debhello", ver="1.6", rev="1" method="dir_d...
    I: already in the package-version form: "debhello-1.6"
    I: [base_dir] $ ln -sf debhello-1.6.tar.xz debhello_1.6.orig.tar.xz
    I: [base_dir] $ cd debhello-1.6
    I: parsing option -b ""
    I: binary package=debhello Type=bin / Arch=any M-A=foreign
    I: build_type = Autotools with autoreconf
    I: ext_type = am                      3 files
    I: ext_type = c                       1 files
    I: ext_type = 1                       1 files
    I: creating debian/* files with "-x 1" option
    I: [debhello-1.6] $ licensecheck --recursive --copyright --deb-machine  . > d...
    I: creating debian/copyright by licensecheck.
    I: creating debian/control from control.py
    I: creating debian/control by control.py
    I: creating debian/changelog from extra0_changelog
    I: creating debian/rules from extra0_rules
    I: creating debian/source/format from extra0source_format
     ...

The result is similar to “Section 14.8, “Makefile.in + configure (single-binary package)”” but not exactly the same.

Let’s inspect the notable template files generated.

debian/rules (template file, v=1.6):

    [base_dir] $ cd debhello-1.6
    [debhello-1.6] $ cat debian/rules
    #!/usr/bin/make -f
    # You must remove unused comment lines for the released package.
    # See debhelper(7) (un-comment to enable)
    # This is an autogenerated template for debian/rules.
    #
    # Output every command that modifies files on the build system.
    #export DH_VERBOSE = 1
    #
    # Copy some variable definitions from pkg-info.mk and vendor.mk
    # under /usr/share/dpkg/ to here if they are useful.
    #
    # See FEATURE AREAS/ENVIRONMENT in dpkg-buildflags(1)
    # Apply all hardening options
    #export DEB_BUILD_MAINT_OPTIONS = hardening=+all
    # Package maintainers to append CFLAGS
    #export DEB_CFLAGS_MAINT_APPEND  = -Wall -pedantic
    # Package maintainers to append LDFLAGS
    #export DEB_LDFLAGS_MAINT_APPEND = -Wl,-O1
    #
    # With debhelper version 9 or newer, the dh command exports
    # all buildflags.  So there is no need to include the
    # /usr/share/dpkg/buildflags.mk file here if compat is 9 or newer.
    #
    # These are rarely used code. (START)
    #
    # The following include for *.mk magically sets miscellaneous
    # variables while honoring existing values of pertinent
    # environment variables:
    #
    # Architecture-related variables such as DEB_TARGET_MULTIARCH:
    #include /usr/share/dpkg/architecture.mk
    # Vendor-related variables such as DEB_VENDOR:
    #include /usr/share/dpkg/vendor.mk
    # Package-related variables such as DEB_DISTRIBUTION
    #include /usr/share/dpkg/pkg-info.mk
    #
    # You may alternatively set them susing a simple script such as:
    # DEB_VENDOR ?= $(shell dpkg-vendor --query  Vendor)
    #
    # These are rarely used code. (END)
    #

    ### main packaging script based on post dh7 syntax
    %:
            dh $@ --with autoreconf

    # debmake generated override targets
    # Set options for ./configure
    #CONFIGURE_FLAGS = <options for ./configure>
    #overrride_dh_configure:
    #       dh_configure -- $(CONFIGURE_FLAGS)
    #
    # Do not install libtool archive, python .pyc .pyo
    #override_dh_install:
    #       dh_install --list-missing -X.la -X.pyc -X.pyo

Let’s make this Debian package better as the maintainer.

debian/rules (maintainer version, v=1.6):

    [base_dir] $ cd debhello-1.6
    [debhello-1.6] $ vim debian/rules
     ... hack, hack, hack, ...
    [debhello-1.6] $ cat debian/rules
    #!/usr/bin/make -f
    export DH_VERBOSE = 1
    export DEB_BUILD_MAINT_OPTIONS = hardening=+all
    export DEB_CFLAGS_MAINT_APPEND  = -Wall -pedantic
    export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed

    %:
            dh $@ --with autoreconf

    override_dh_auto_configure:
            dh_auto_configure -- \
                    --with-math

There are several other template files under the debian/ directory. These also need to be updated.

The rest of the packaging activities are practically the same as the one in “Section 5.8, “Step 4: Building package with debuild””.

## 14.10. CMake (single-binary package)

Here is an example of creating a simple Debian package from a simple C source program using CMake (CMakeLists.txt and some files such as config.h.in) as its build system.

The cmake command generates the Makefile file based on the CMakeLists.txt file and its -D option. It also configures the file as specified in its configure_file(…​) by replacing strings with @…​@ and changing the #cmakedefine …​ line.

Let’s assume this upstream tarball to be debhello-1.7.tar.xz.

This type of source is meant to be installed as a non-system file, for example, as:

    [base_dir] $ tar --xz -xmf debhello-1.7.tar.xz
    [base_dir] $ cd debhello-1.7
    [debhello-1.7] $ mkdir obj-x86_64-linux-gnu # for out-of-tree build
    [debhello-1.7] $ cd obj-x86_64-linux-gnu
    [debhello-1.7] $ cmake ..
    [debhello-1.7] $ make
    [debhello-1.7] $ make install

Let’s get the source and make the Debian package.

Download debhello-1.7.tar.xz.

    [base_dir] $ wget http://www.example.org/download/debhello-1.7.tar.xz
     ...
    [base_dir] $ tar --xz -xmf debhello-1.7.tar.xz
    [base_dir] $ tree
    .
    ├── debhello-1.7
    │   ├── CMakeLists.txt
    │   ├── LICENSE
    │   ├── README.md
    │   ├── data
    │   │   ├── hello.desktop
    │   │   └── hello.png
    │   ├── man
    │   │   ├── CMakeLists.txt
    │   │   └── hello.1
    │   └── src
    │       ├── CMakeLists.txt
    │       ├── config.h.in
    │       └── hello.c
    └── debhello-1.7.tar.xz

    5 directories, 11 files

Here, the contents of this source are as follows.

src/hello.c (v=1.7):

    [base_dir] $ cat debhello-1.7/src/hello.c
    #include "config.h"
    #ifdef WITH_MATH
    #  include <math.h>
    #endif
    #include <stdio.h>
    int
    main()
    {
            printf("Hello, I am " PACKAGE_AUTHOR "!\n");
    #ifdef WITH_MATH
            printf("4.0 * atan(1.0) = %10f8\n", 4.0*atan(1.0));
    #else
            printf("I can't do MATH!\n");
    #endif
            return 0;
    }

src/config.h.in (v=1.7):

    [base_dir] $ cat debhello-1.7/src/config.h.in
    /* name of the package author */
    #define PACKAGE_AUTHOR "@PACKAGE_AUTHOR@"
    /* math library support */
    #cmakedefine WITH_MATH

CMakeLists.txt (v=1.7):

    [base_dir] $ cat debhello-1.7/CMakeLists.txt
    cmake_minimum_required(VERSION 3.31)
    project(debhello)
    set(PACKAGE_AUTHOR "Osamu Aoki")
    add_subdirectory(src)
    add_subdirectory(man)
    [base_dir] $ cat debhello-1.7/man/CMakeLists.txt
    install(
      FILES ${CMAKE_CURRENT_SOURCE_DIR}/hello.1
      DESTINATION share/man/man1
    )
    [base_dir] $ cat debhello-1.7/src/CMakeLists.txt
    # Always define HAVE_CONFIG_H
    add_definitions(-DHAVE_CONFIG_H)
    # Interactively define WITH_MATH
    option(WITH_MATH "Build with math support" OFF)
    #variable_watch(WITH_MATH)
    # Generate config.h from config.h.in
    configure_file(
      "${CMAKE_CURRENT_SOURCE_DIR}/config.h.in"
      "${CMAKE_CURRENT_BINARY_DIR}/config.h"
    )
    include_directories("${CMAKE_CURRENT_BINARY_DIR}")
    add_executable(hello hello.c)
    install(TARGETS hello
      RUNTIME DESTINATION bin
    )

Let’s package this with the debmake command.

    [base_dir] $ cd debhello-1.7
    [debhello-1.7] $ debmake -x1
    I: debmake (version: 5.1.4)
    I: Copyright © 2014-2026 Osamu Aoki <osamu@debian.org>
    I: [debhello-1.7] $ cd ..
    I: Non-native Debian package pkg="debhello", ver="1.7", rev="1" method="dir_d...
    I: already in the package-version form: "debhello-1.7"
    I: [base_dir] $ ln -sf debhello-1.7.tar.xz debhello_1.7.orig.tar.xz
    I: [base_dir] $ cd debhello-1.7
    I: parsing option -b ""
    I: binary package=debhello Type=bin / Arch=any M-A=foreign
    I: build_type = Cmake
    I: ext_type = c                       2 files
    I: ext_type = 1                       1 files
    I: ext_type = desktop                 1 files
    I: creating debian/* files with "-x 1" option
    I: [debhello-1.7] $ licensecheck --recursive --copyright --deb-machine  . > d...
    I: creating debian/copyright by licensecheck.
    I: creating debian/control from control.py
    I: creating debian/control by control.py
    I: creating debian/changelog from extra0_changelog
    I: creating debian/rules from extra0_rules
    I: creating debian/source/format from extra0source_format
     ...

The result is similar to “Section 14.8, “Makefile.in + configure (single-binary package)”” but not exactly the same.

Let’s inspect the notable template files generated.

debian/rules (template file, v=1.7):

    [base_dir] $ cd debhello-1.7
    [debhello-1.7] $ cat debian/rules
    #!/usr/bin/make -f
    # You must remove unused comment lines for the released package.
    # See debhelper(7) (un-comment to enable)
    # This is an autogenerated template for debian/rules.
    #
    # Output every command that modifies files on the build system.
    #export DH_VERBOSE = 1
    #
    # Copy some variable definitions from pkg-info.mk and vendor.mk
    # under /usr/share/dpkg/ to here if they are useful.
    #
    # See FEATURE AREAS/ENVIRONMENT in dpkg-buildflags(1)
    # Apply all hardening options
    #export DEB_BUILD_MAINT_OPTIONS = hardening=+all
    # Package maintainers to append CFLAGS
    #export DEB_CFLAGS_MAINT_APPEND  = -Wall -pedantic
    # Package maintainers to append LDFLAGS
    #export DEB_LDFLAGS_MAINT_APPEND = -Wl,-O1
    #
    # With debhelper version 9 or newer, the dh command exports
    # all buildflags.  So there is no need to include the
    # /usr/share/dpkg/buildflags.mk file here if compat is 9 or newer.
    #
    # These are rarely used code. (START)
    #
    # The following include for *.mk magically sets miscellaneous
    # variables while honoring existing values of pertinent
    # environment variables:
    #
    # Architecture-related variables such as DEB_TARGET_MULTIARCH:
    #include /usr/share/dpkg/architecture.mk
    # Vendor-related variables such as DEB_VENDOR:
    #include /usr/share/dpkg/vendor.mk
    # Package-related variables such as DEB_DISTRIBUTION
    #include /usr/share/dpkg/pkg-info.mk
    #
    # You may alternatively set them susing a simple script such as:
    # DEB_VENDOR ?= $(shell dpkg-vendor --query  Vendor)
    #
    # These are rarely used code. (END)
    #

    ### main packaging script based on post dh7 syntax
    %:
            dh $@

    # debmake generated override targets
    #override_dh_auto_configure:
    #       dh_auto_configure -- \
    #             -DCMAKE_LIBRARY_ARCHITECTURE="$(DEB_TARGET_MULTIARCH)"
    #
    # You may need to patch CMakeLists.txt to set the library install path to be:...
    #-install(TARGETS <sharedlibname> LIBRARY DESTINATION lib)
    #+install(TARGETS <sharedlibname> LIBRARY DESTINATION lib/${CMAKE_LIBRARY_ARC...

    # Multiarch package requires library files to be installed to
    # /usr/lib/<triplet>/ .  If the build system does not support
    # $(DEB_HOST_MULTIARCH), you may need to override some targets such as
    # dh_auto_configure or dh_auto_install to use $(DEB_HOST_MULTIARCH) .

debian/control (template file, v=1.7):

    [debhello-1.7] $ cat debian/control
    Source: debhello
    Section: unknown
    Priority: optional
    Maintainer: "Osamu Aoki" <osamu@debian.org>
    Build-Depends:
     debhelper-compat (= 13),
     cmake,
    Standards-Version: 4.7.3
    Homepage: <insert the upstream URL, if relevant>
    Rules-Requires-Root: no
    #Vcs-Git: https://salsa.debian.org/debian/debhello.git
    #Vcs-Browser: https://salsa.debian.org/debian/<project_site>

    Package: debhello
    Section: unknown
    Architecture: any
    Multi-Arch: foreign
    Depends:
     ${misc:Depends},
     ${shlibs:Depends},
    Description: auto-generated package by debmake
     This Debian binary package was auto-generated by the
     debmake(1) command provided by the debmake package.
     .
     ===== This comes from the unmodified template file =====
     .
     Please edit this template file (debian/control) and other package files
     (debian/*) to make them meet all the requirements of the Debian Policy
     before uploading this package to the Debian archive.
     .
     See
      * https://www.debian.org/doc/manuals/developers-reference/best-pkging-pract...
      * https://www.debian.org/doc/manuals/debmake-doc/ch05.en.html#control
     .
     The synopsis description at the top should be about 60 characters and
     written as a phrase.  No extra capital letters or a final period.  No
     articles — "a", "an", or "the".
     .
     The package description for general-purpose applications should be
     written for a less technical user.  This means that we should avoid
     jargon.  GNOME or KDE is fine but GTK+ is probably not.
     .
     Use the canonical forms of words:
      * Use X Window System, X11, or X; not X Windows, X-Windows, or X Window.
      * Use GTK+, not GTK or gtk.
      * Use GNOME, not Gnome.
      * Use PostScript, not Postscript or postscript.

Let’s make this Debian package better as the maintainer.

debian/rules (maintainer version, v=1.7):

    [base_dir] $ cd debhello-1.7
    [debhello-1.7] $ vim debian/rules
     ... hack, hack, hack, ...
    [debhello-1.7] $ cat debian/rules
    #!/usr/bin/make -f
    export DH_VERBOSE = 1
    export DEB_BUILD_MAINT_OPTIONS = hardening=+all
    export DEB_CFLAGS_MAINT_APPEND  = -Wall -pedantic
    export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed

    %:
            dh $@

    override_dh_auto_configure:
            dh_auto_configure -- -DWITH-MATH=1

debian/control (maintainer version, v=1.7):

    [debhello-1.7] $ vim debian/control
     ... hack, hack, hack, ...
    [debhello-1.7] $ cat debian/control
    Source: debhello
    Section: devel
    Priority: optional
    Maintainer: Osamu Aoki <osamu@debian.org>
    Build-Depends:
     debhelper-compat (= 13),
     cmake,
    Standards-Version: 4.7.3
    Homepage: https://salsa.debian.org/debian/debmake-doc
    Rules-Requires-Root: no

    Package: debhello
    Architecture: any
    Multi-Arch: foreign
    Depends:
     ${misc:Depends},
     ${shlibs:Depends},
    Description: Simple packaging example for debmake
     This Debian binary package is an example package.
     (This is an example only)

There are several other template files under the debian/ directory. These also need to be updated.

The rest of the packaging activities are practically the same as the one in “Section 14.8, “Makefile.in + configure (single-binary package)””.

## 14.11. Autotools (multi-binary package)

Here is an example of creating a set of Debian binary packages including the executable package, the shared library package, the development file package, and the debug symbol package from a simple C source program using Autotools (Autoconf and Automake, which use Makefile.am and configure.ac as their input files) as its build system.

Let’s package this in a similar way to “Section 14.9, “Autotools (single-binary package)””.

Let’s assume this upstream tarball to be debhello-2.0.tar.xz.

This type of source is meant to be installed as a non-system file, for example, as:

    [base_dir] $ tar --xz -xmf debhello-2.0.tar.xz
    [base_dir] $ cd debhello-2.0
    [debhello-2.0] $ autoreconf -ivf # optional
    [debhello-2.0] $ ./configure --with-math
    [debhello-2.0] $ make
    [debhello-2.0] $ make install

Let’s get the source and make the Debian package.

Download debhello-2.0.tar.xz.

    [base_dir] $ wget http://www.example.org/download/debhello-2.0.tar.xz
     ...
    [base_dir] $ tar --xz -xmf debhello-2.0.tar.xz
    [base_dir] $ tree
    .
    ├── debhello-2.0
    │   ├── LICENSE
    │   ├── Makefile.am
    │   ├── README.md
    │   ├── configure.ac
    │   ├── data
    │   │   ├── hello.desktop
    │   │   └── hello.png
    │   ├── lib
    │   │   ├── Makefile.am
    │   │   ├── sharedlib.c
    │   │   └── sharedlib.h
    │   ├── man
    │   │   ├── Makefile.am
    │   │   └── hello.1
    │   └── src
    │       ├── Makefile.am
    │       └── hello.c
    └── debhello-2.0.tar.xz

    6 directories, 14 files

Here, the contents of this source are as follows.

src/hello.c (v=2.0):

    [base_dir] $ cat debhello-2.0/src/hello.c
    #include "config.h"
    #include <stdio.h>
    #include <sharedlib.h>
    int
    main()
    {
            printf("Hello, I am " PACKAGE_AUTHOR "!\n");
            sharedlib();
            return 0;
    }

lib/sharedlib.h and lib/sharedlib.c (v=1.6):

    [base_dir] $ cat debhello-2.0/lib/sharedlib.h
    int sharedlib();
    [base_dir] $ cat debhello-2.0/lib/sharedlib.c
    #include <stdio.h>
    int
    sharedlib()
    {
            printf("This is a shared library!\n");
            return 0;
    }

Makefile.am (v=2.0):

    [base_dir] $ cat debhello-2.0/Makefile.am
    # recursively process `Makefile.am` in SUBDIRS
    SUBDIRS = lib src man
    [base_dir] $ cat debhello-2.0/man/Makefile.am
    # manpages (distributed in the source package)
    dist_man_MANS = hello.1
    [base_dir] $ cat debhello-2.0/lib/Makefile.am
    # libtool librares to be produced
    lib_LTLIBRARIES = libsharedlib.la

    # source files used for lib_LTLIBRARIES
    libsharedlib_la_SOURCES = sharedlib.c

    # C pre-processor flags used for lib_LTLIBRARIES
    #libsharedlib_la_CPPFLAGS =

    # Headers files to be installed in <prefix>/include
    include_HEADERS = sharedlib.h

    # Versioning Libtool Libraries with version triplets
    libsharedlib_la_LDFLAGS = -version-info 1:0:0
    [base_dir] $ cat debhello-2.0/src/Makefile.am
    # program executables to be produced
    bin_PROGRAMS = hello

    # source files used for bin_PROGRAMS
    hello_SOURCES = hello.c

    # C pre-processor flags used for bin_PROGRAMS
    AM_CPPFLAGS = -I$(srcdir) -I$(top_srcdir)/lib

    # Extra options for the linker for hello
    # hello_LDFLAGS =

    # Libraries the `hello` binary to be linked
    hello_LDADD = $(top_srcdir)/lib/libsharedlib.la

configure.ac (v=2.0):

    [base_dir] $ cat debhello-2.0/configure.ac
    #                                               -*- Autoconf -*-
    # Process this file with autoconf to produce a configure script.
    AC_PREREQ([2.69])
    AC_INIT([debhello],[2.2],[foo@example.org])
    AC_CONFIG_SRCDIR([src/hello.c])
    AC_CONFIG_HEADERS([config.h])
    echo "Standard customization chores"
    AC_CONFIG_AUX_DIR([build-aux])

    AM_INIT_AUTOMAKE([foreign])

    # Set default to --enable-shared --disable-static
    LT_INIT([shared disable-static])

    # find the libltdl sources in the libltdl sub-directory
    LT_CONFIG_LTDL_DIR([libltdl])

    # choose one
    LTDL_INIT([recursive])
    #LTDL_INIT([subproject])
    #LTDL_INIT([nonrecursive])

    # Add #define PACKAGE_AUTHOR ... in config.h with a comment
    AC_DEFINE(PACKAGE_AUTHOR, ["Osamu Aoki"], [Define PACKAGE_AUTHOR])
    # Checks for programs.
    AC_PROG_CC

    # only for the recursive case
    AC_CONFIG_FILES([Makefile
                     lib/Makefile
                     man/Makefile
                     src/Makefile])
    AC_OUTPUT

Let’s use the debmake command to package this into multiple packages:

- debhello: type = bin
- libsharedlib1: type = lib
- libsharedlib-dev: type = dev

Here, we use the -b'libsharedlib1,libsharedlib-dev' option to specify the additional binary packages to be generated.

    [base_dir] $ cd debhello-2.0
    [debhello-2.0] $ debmake -b',libsharedlib1,libsharedlib-dev' -x1
    I: debmake (version: 5.1.4)
    I: Copyright © 2014-2026 Osamu Aoki <osamu@debian.org>
    I: [debhello-2.0] $ cd ..
    I: Non-native Debian package pkg="debhello", ver="2.0", rev="1" method="dir_d...
    I: already in the package-version form: "debhello-2.0"
    I: [base_dir] $ ln -sf debhello-2.0.tar.xz debhello_2.0.orig.tar.xz
    I: [base_dir] $ cd debhello-2.0
    I: parsing option -b ",libsharedlib1,libsharedlib-dev"
    I: binary package=debhello Type=bin / Arch=any M-A=foreign
    I: binary package=libsharedlib1 Type=lib / Arch=any M-A=same
    I: binary package=libsharedlib-dev Type=dev / Arch=any M-A=same
    I: build_type = Autotools with autoreconf
    I: ext_type = am                      4 files
    I: ext_type = c                       3 files
    I: ext_type = 1                       1 files
    I: creating debian/* files with "-x 1" option
    I: [debhello-2.0] $ licensecheck --recursive --copyright --deb-machine  . > d...
    I: creating debian/copyright by licensecheck.
    I: creating debian/control from control.py
    I: creating debian/control by control.py
    I: creating debian/changelog from extra0_changelog
     ...

The result is similar to “Section 14.8, “Makefile.in + configure (single-binary package)”” but with more template files.

Let’s inspect the notable template files generated.

debian/rules (template file, v=2.0):

    [base_dir] $ cd debhello-2.0
    [debhello-2.0] $ cat debian/rules
    #!/usr/bin/make -f
    # You must remove unused comment lines for the released package.
    # See debhelper(7) (un-comment to enable)
    # This is an autogenerated template for debian/rules.
    #
    # Output every command that modifies files on the build system.
    #export DH_VERBOSE = 1
    #
    # Copy some variable definitions from pkg-info.mk and vendor.mk
    # under /usr/share/dpkg/ to here if they are useful.
    #
    # See FEATURE AREAS/ENVIRONMENT in dpkg-buildflags(1)
    # Apply all hardening options
    #export DEB_BUILD_MAINT_OPTIONS = hardening=+all
    # Package maintainers to append CFLAGS
    #export DEB_CFLAGS_MAINT_APPEND  = -Wall -pedantic
    # Package maintainers to append LDFLAGS
    #export DEB_LDFLAGS_MAINT_APPEND = -Wl,-O1
    #
    # With debhelper version 9 or newer, the dh command exports
    # all buildflags.  So there is no need to include the
    # /usr/share/dpkg/buildflags.mk file here if compat is 9 or newer.
    #
    # These are rarely used code. (START)
    #
    # The following include for *.mk magically sets miscellaneous
    # variables while honoring existing values of pertinent
    # environment variables:
    #
    # Architecture-related variables such as DEB_TARGET_MULTIARCH:
    #include /usr/share/dpkg/architecture.mk
    # Vendor-related variables such as DEB_VENDOR:
    #include /usr/share/dpkg/vendor.mk
    # Package-related variables such as DEB_DISTRIBUTION
    #include /usr/share/dpkg/pkg-info.mk
    #
    # You may alternatively set them susing a simple script such as:
    # DEB_VENDOR ?= $(shell dpkg-vendor --query  Vendor)
    #
    # These are rarely used code. (END)
    #

    ### main packaging script based on post dh7 syntax
    %:
            dh $@ --with autoreconf

    # debmake generated override targets
    # Set options for ./configure
    #CONFIGURE_FLAGS = <options for ./configure>
    #overrride_dh_configure:
    #       dh_configure -- $(CONFIGURE_FLAGS)
    #
    # Do not install libtool archive, python .pyc .pyo
    #override_dh_install:
    #       dh_install --list-missing -X.la -X.pyc -X.pyo

Let’s make this Debian package better as the maintainer.

debian/rules (maintainer version, v=2.0):

    [base_dir] $ cd debhello-2.0
    [debhello-2.0] $ vim debian/rules
     ... hack, hack, hack, ...
    [debhello-2.0] $ cat debian/rules
    #!/usr/bin/make -f
    export DH_VERBOSE = 1
    export DEB_BUILD_MAINT_OPTIONS = hardening=+all
    export DEB_CFLAGS_MAINT_APPEND  = -Wall -pedantic
    export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed

    %:
            dh $@ --with autoreconf

    override_dh_missing:
            dh_missing -X.la

debian/control (maintainer version, v=2.0):

    [debhello-2.0] $ vim debian/control
     ... hack, hack, hack, ...
    [debhello-2.0] $ cat debian/control
    Source: debhello
    Section: devel
    Priority: optional
    Maintainer: Osamu Aoki <osamu@debian.org>
    Build-Depends:
     debhelper-compat (= 13),
     dh-autoreconf,
    Standards-Version: 4.7.3
    Homepage: https://salsa.debian.org/debian/debmake-doc
    Rules-Requires-Root: no

    Package: debhello
    Architecture: any
    Multi-Arch: foreign
    Depends:
     libsharedlib1 (= ${binary:Version}),
     ${misc:Depends},
     ${shlibs:Depends},
    Description: Simple packaging example for debmake
     This package contains the compiled binary executable.
     .
     This Debian binary package is an example package.
     (This is an example only)

    Package: libsharedlib1
    Section: libs
    Architecture: any
    Multi-Arch: same
    Pre-Depends:
     ${misc:Pre-Depends},
    Depends:
     ${misc:Depends},
     ${shlibs:Depends},
    Description: Simple packaging example for debmake
     This package contains the shared library.

    Package: libsharedlib-dev
    Section: libdevel
    Architecture: any
    Multi-Arch: same
    Depends:
     libsharedlib1 (= ${binary:Version}),
     ${misc:Depends},
    Description: Simple packaging example for debmake
     This package contains the development files.

debian/*.install (maintainer version, v=2.0):

    [debhello-2.0] $ vim debian/copyright
     ... hack, hack, hack, ...
    [debhello-2.0] $ cat debian/copyright
    Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
    Upstream-Name: debhello
    Upstream-Contact: Osamu Aoki <osamu@debian.org>
    Source: https://salsa.debian.org/debian/debmake-doc

    Files:     *
    Copyright: 2015-2021 Osamu Aoki <osamu@debian.org>
    License:   Expat
     Permission is hereby granted, free of charge, to any person obtaining a
     copy of this software and associated documentation files (the "Software"),
     to deal in the Software without restriction, including without limitation
     the rights to use, copy, modify, merge, publish, distribute, sublicense,
     and/or sell copies of the Software, and to permit persons to whom the
     Software is furnished to do so, subject to the following conditions:
     .
     The above copyright notice and this permission notice shall be included
     in all copies or substantial portions of the Software.
     .
     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
     CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Since this upstream source creates the proper auto-generated Makefile, there is no need to create debian/install and debian/manpages files.

There are several other template files under the debian/ directory. These also need to be updated.

Template files under debian/. (v=2.0):

    [debhello-2.0] $ rm -f debian/clean debian/dirs debian/install debian/links
    [debhello-2.0] $ rm -f debian/README.source debian/source/*.ex
    [debhello-2.0] $ rm -rf debian/patches
    [debhello-2.0] $ tree -F debian
    debian/
    ├── README.Debian
    ├── changelog
    ├── control
    ├── copyright
    ├── debhello.install
    ├── docs
    ├── examples
    ├── gbp.conf
    ├── libsharedlib-dev.install
    ├── libsharedlib1.install
    ├── libsharedlib1.symbols
    ├── manpages
    ├── rules*
    ├── salsa-ci.yml
    ├── source/
    │   └── format
    ├── tests/
    │   └── control
    ├── upstream/
    │   └── metadata
    └── watch

    4 directories, 18 files

The rest of the packaging activities are practically the same as the one in “Section 14.8, “Makefile.in + configure (single-binary package)””.

Here are the generated dependency list of all binary packages.

The generated dependency list of all binary packages (v=2.0):

    [debhello-2.0] $ dpkg -f debhello-dbgsym_2.0-1_amd64.deb pre-depends \
                depends recommends conflicts breaks
    Depends: debhello (= 2.0-1)
    [debhello-2.0] $ dpkg -f debhello_2.0-1_amd64.deb pre-depends \
                depends recommends conflicts breaks
    Depends: libsharedlib1 (= 2.0-1), libc6 (>= 2.34)
    [debhello-2.0] $ dpkg -f libsharedlib-dev_2.0-1_amd64.deb pre-depends \
                depends recommends conflicts breaks
    Depends: libsharedlib1 (= 2.0-1)
    [debhello-2.0] $ dpkg -f libsharedlib1-dbgsym_2.0-1_amd64.deb pre-depends \
                depends recommends conflicts breaks
    Depends: libsharedlib1 (= 2.0-1)
    [debhello-2.0] $ dpkg -f libsharedlib1_2.0-1_amd64.deb pre-depends \
                depends recommends conflicts breaks
    Depends: libc6 (>= 2.2.5)

## 14.12. CMake (multi-binary package)

This example demonstrates creating a set of Debian binary packages including the executable package, the shared library package, the development file package, and the debug symbol package from a simple C source program using CMake (CMakeLists.txt and files such as config.h.in) as its build system.

Let’s assume this upstream tarball to be debhello-2.1.tar.xz.

This type of source is meant to be installed as a non-system file, for example, as:

    [base_dir] $ tar --xz -xmf debhello-2.1.tar.xz
    [base_dir] $ cd debhello-2.1
    [debhello-2.1] $ mkdir obj-x86_64-linux-gnu
    [debhello-2.1] $ cd obj-x86_64-linux-gnu
    [debhello-2.1] $ cmake ..
    [debhello-2.1] $ make
    [debhello-2.1] $ make install

Let’s get the source and make the Debian package.

Download debhello-2.1.tar.xz.

    [base_dir] $ wget http://www.example.org/download/debhello-2.1.tar.xz
     ...
    [base_dir] $ tar --xz -xmf debhello-2.1.tar.xz
    [base_dir] $ tree
    .
    ├── debhello-2.1
    │   ├── CMakeLists.txt
    │   ├── LICENSE
    │   ├── README.md
    │   ├── data
    │   │   ├── hello.desktop
    │   │   └── hello.png
    │   ├── lib
    │   │   ├── CMakeLists.txt
    │   │   ├── sharedlib.c
    │   │   └── sharedlib.h
    │   ├── man
    │   │   ├── CMakeLists.txt
    │   │   └── hello.1
    │   └── src
    │       ├── CMakeLists.txt
    │       ├── config.h.in
    │       └── hello.c
    └── debhello-2.1.tar.xz

    6 directories, 14 files

Here, the contents of this source are as follows.

src/hello.c (v=2.1):

    [base_dir] $ cat debhello-2.1/src/hello.c
    #include "config.h"
    #include <stdio.h>
    #include <sharedlib.h>
    int
    main()
    {
            printf("Hello, I am " PACKAGE_AUTHOR "!\n");
            sharedlib();
            return 0;
    }

src/config.h.in (v=2.1):

    [base_dir] $ cat debhello-2.1/src/config.h.in
    /* name of the package author */
    #define PACKAGE_AUTHOR "@PACKAGE_AUTHOR@"

lib/sharedlib.c and lib/sharedlib.h (v=2.1):

    [base_dir] $ cat debhello-2.1/lib/sharedlib.h
    int sharedlib();
    [base_dir] $ cat debhello-2.1/lib/sharedlib.c
    #include <stdio.h>
    int
    sharedlib()
    {
            printf("This is a shared library!\n");
            return 0;
    }

CMakeLists.txt (v=2.1):

    [base_dir] $ cat debhello-2.1/CMakeLists.txt
    cmake_minimum_required(VERSION 3.31)
    project(debhello)
    set(PACKAGE_AUTHOR "Osamu Aoki")
    add_subdirectory(lib)
    add_subdirectory(src)
    add_subdirectory(man)
    [base_dir] $ cat debhello-2.1/man/CMakeLists.txt
    install(
      FILES ${CMAKE_CURRENT_SOURCE_DIR}/hello.1
      DESTINATION share/man/man1
    )
    [base_dir] $ cat debhello-2.1/src/CMakeLists.txt
    # Always define HAVE_CONFIG_H
    add_definitions(-DHAVE_CONFIG_H)
    # Generate config.h from config.h.in
    configure_file(
      "${CMAKE_CURRENT_SOURCE_DIR}/config.h.in"
      "${CMAKE_CURRENT_BINARY_DIR}/config.h"
      )
    include_directories("${CMAKE_CURRENT_BINARY_DIR}")
    include_directories("${CMAKE_SOURCE_DIR}/lib")

    add_executable(hello hello.c)
    target_link_libraries(hello sharedlib)
    install(TARGETS hello
      RUNTIME DESTINATION bin
    )

Let’s package this with the debmake command.

    [base_dir] $ cd debhello-2.1
    [debhello-2.1] $ debmake -b',libsharedlib1,libsharedlib-dev' -x1
    I: debmake (version: 5.1.4)
    I: Copyright © 2014-2026 Osamu Aoki <osamu@debian.org>
    I: [debhello-2.1] $ cd ..
    I: Non-native Debian package pkg="debhello", ver="2.1", rev="1" method="dir_d...
    I: already in the package-version form: "debhello-2.1"
    I: [base_dir] $ ln -sf debhello-2.1.tar.xz debhello_2.1.orig.tar.xz
    I: [base_dir] $ cd debhello-2.1
    I: parsing option -b ",libsharedlib1,libsharedlib-dev"
    I: binary package=debhello Type=bin / Arch=any M-A=foreign
    I: binary package=libsharedlib1 Type=lib / Arch=any M-A=same
    I: binary package=libsharedlib-dev Type=dev / Arch=any M-A=same
    I: build_type = Cmake
    I: ext_type = c                       4 files
    I: ext_type = 1                       1 files
    I: ext_type = desktop                 1 files
    I: creating debian/* files with "-x 1" option
    I: [debhello-2.1] $ licensecheck --recursive --copyright --deb-machine  . > d...
    I: creating debian/copyright by licensecheck.
    I: creating debian/control from control.py
    I: creating debian/control by control.py
    I: creating debian/changelog from extra0_changelog
     ...

The result is similar to “Section 14.8, “Makefile.in + configure (single-binary package)”” but not exactly the same.

Let’s inspect the notable template files generated.

debian/rules (template file, v=2.1):

    [base_dir] $ cd debhello-2.1
    [debhello-2.1] $ cat debian/rules
    #!/usr/bin/make -f
    # You must remove unused comment lines for the released package.
    # See debhelper(7) (un-comment to enable)
    # This is an autogenerated template for debian/rules.
    #
    # Output every command that modifies files on the build system.
    #export DH_VERBOSE = 1
    #
    # Copy some variable definitions from pkg-info.mk and vendor.mk
    # under /usr/share/dpkg/ to here if they are useful.
    #
    # See FEATURE AREAS/ENVIRONMENT in dpkg-buildflags(1)
    # Apply all hardening options
    #export DEB_BUILD_MAINT_OPTIONS = hardening=+all
    # Package maintainers to append CFLAGS
    #export DEB_CFLAGS_MAINT_APPEND  = -Wall -pedantic
    # Package maintainers to append LDFLAGS
    #export DEB_LDFLAGS_MAINT_APPEND = -Wl,-O1
    #
    # With debhelper version 9 or newer, the dh command exports
    # all buildflags.  So there is no need to include the
    # /usr/share/dpkg/buildflags.mk file here if compat is 9 or newer.
    #
    # These are rarely used code. (START)
    #
    # The following include for *.mk magically sets miscellaneous
    # variables while honoring existing values of pertinent
    # environment variables:
    #
    # Architecture-related variables such as DEB_TARGET_MULTIARCH:
    #include /usr/share/dpkg/architecture.mk
    # Vendor-related variables such as DEB_VENDOR:
    #include /usr/share/dpkg/vendor.mk
    # Package-related variables such as DEB_DISTRIBUTION
    #include /usr/share/dpkg/pkg-info.mk
    #
    # You may alternatively set them susing a simple script such as:
    # DEB_VENDOR ?= $(shell dpkg-vendor --query  Vendor)
    #
    # These are rarely used code. (END)
    #

    ### main packaging script based on post dh7 syntax
    %:
            dh $@

    # debmake generated override targets
    #override_dh_auto_configure:
    #       dh_auto_configure -- \
    #             -DCMAKE_LIBRARY_ARCHITECTURE="$(DEB_TARGET_MULTIARCH)"
    #
    # You may need to patch CMakeLists.txt to set the library install path to be:...
    #-install(TARGETS <sharedlibname> LIBRARY DESTINATION lib)
    #+install(TARGETS <sharedlibname> LIBRARY DESTINATION lib/${CMAKE_LIBRARY_ARC...

    # Multiarch package requires library files to be installed to
    # /usr/lib/<triplet>/ .  If the build system does not support
    # $(DEB_HOST_MULTIARCH), you may need to override some targets such as
    # dh_auto_configure or dh_auto_install to use $(DEB_HOST_MULTIARCH) .

Let’s make this Debian package better as the maintainer.

debian/rules (maintainer version, v=2.1):

    [base_dir] $ cd debhello-2.1
    [debhello-2.1] $ vim debian/rules
     ... hack, hack, hack, ...
    [debhello-2.1] $ cat debian/rules
    #!/usr/bin/make -f
    export DH_VERBOSE = 1
    export DEB_BUILD_MAINT_OPTIONS = hardening=+all
    export DEB_CFLAGS_MAINT_APPEND  = -Wall -pedantic
    export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
    DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)

    %:
            dh $@

    override_dh_auto_configure:
            dh_auto_configure -- \
                  -DCMAKE_LIBRARY_ARCHITECTURE="$(DEB_HOST_MULTIARCH)"

debian/control (maintainer version, v=2.1):

    [debhello-2.1] $ vim debian/control
     ... hack, hack, hack, ...
    [debhello-2.1] $ cat debian/control
    Source: debhello
    Section: devel
    Priority: optional
    Maintainer: Osamu Aoki <osamu@debian.org>
    Build-Depends:
     debhelper-compat (= 13),
     cmake,
    Standards-Version: 4.7.3
    Homepage: https://salsa.debian.org/debian/debmake-doc
    Rules-Requires-Root: no

    Package: debhello
    Architecture: any
    Multi-Arch: foreign
    Depends:
     libsharedlib1 (= ${binary:Version}),
     ${misc:Depends},
     ${shlibs:Depends},
    Description: Simple packaging example for debmake
     This package contains the compiled binary executable.
     .
     This Debian binary package is an example package.
     (This is an example only)

    Package: libsharedlib1
    Section: libs
    Architecture: any
    Multi-Arch: same
    Pre-Depends:
     ${misc:Pre-Depends},
    Depends:
     ${misc:Depends},
     ${shlibs:Depends},
    Description: Simple packaging example for debmake
     This package contains the shared library.

    Package: libsharedlib-dev
    Section: libdevel
    Architecture: any
    Multi-Arch: same
    Depends:
     libsharedlib1 (= ${binary:Version}),
     ${misc:Depends},
    Description: Simple packaging example for debmake
     This package contains the development files.

debian/*.install (maintainer version, v=2.1):

    [debhello-2.1] $ vim debian/copyright
     ... hack, hack, hack, ...
    [debhello-2.1] $ cat debian/copyright
    Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
    Upstream-Name: debhello
    Upstream-Contact: Osamu Aoki <osamu@debian.org>
    Source: https://salsa.debian.org/debian/debmake-doc

    Files:     *
    Copyright: 2015-2021 Osamu Aoki <osamu@debian.org>
    License:   Expat
     Permission is hereby granted, free of charge, to any person obtaining a
     copy of this software and associated documentation files (the "Software"),
     to deal in the Software without restriction, including without limitation
     the rights to use, copy, modify, merge, publish, distribute, sublicense,
     and/or sell copies of the Software, and to permit persons to whom the
     Software is furnished to do so, subject to the following conditions:
     .
     The above copyright notice and this permission notice shall be included
     in all copies or substantial portions of the Software.
     .
     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
     CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

The upstream CMakeLists.txt file needs to be patched to handle the multiarch path correctly.

debian/patches/* (maintainer version, v=2.1):

     ... hack, hack, hack, ...
    [debhello-2.1] $ cat debian/libsharedlib1.symbols
    libsharedlib.so.1 libsharedlib1 #MINVER#
     sharedlib@Base 2.1

Since this upstream source creates the proper auto-generated Makefile, there is no need to create debian/install and debian/manpages files.

There are several other template files under the debian/ directory. These also need to be updated.

Template files under debian/. (v=2.1):

    [debhello-2.1] $ rm -f debian/clean debian/dirs debian/install debian/links
    [debhello-2.1] $ rm -f debian/README.source debian/source/*.ex
    [debhello-2.1] $ tree -F debian
    debian/
    ├── README.Debian
    ├── changelog
    ├── control
    ├── copyright
    ├── debhello.install
    ├── docs
    ├── examples
    ├── gbp.conf
    ├── libsharedlib-dev.install
    ├── libsharedlib1.install
    ├── libsharedlib1.symbols
    ├── manpages
    ├── patches/
    │   ├── 000-cmake-multiarch.patch
    │   └── series
    ├── rules*
    ├── salsa-ci.yml
    ├── source/
    │   └── format
    ├── tests/
    │   └── control
    ├── upstream/
    │   └── metadata
    └── watch

    5 directories, 20 files

The rest of the packaging activities are practically the same as the one in “Section 14.8, “Makefile.in + configure (single-binary package)””.

Here are the generated dependency list of all binary packages.

The generated dependency list of all binary packages (v=2.1):

    [debhello-2.1] $ dpkg -f debhello-dbgsym_2.1-1_amd64.deb pre-depends \
                depends recommends conflicts breaks
    Depends: debhello (= 2.1-1)
    [debhello-2.1] $ dpkg -f debhello_2.1-1_amd64.deb pre-depends \
                depends recommends conflicts breaks
    Depends: libsharedlib1 (= 2.1-1), libc6 (>= 2.34)
    [debhello-2.1] $ dpkg -f libsharedlib-dev_2.1-1_amd64.deb pre-depends \
                depends recommends conflicts breaks
    Depends: libsharedlib1 (= 2.1-1)
    [debhello-2.1] $ dpkg -f libsharedlib1-dbgsym_2.1-1_amd64.deb pre-depends \
                depends recommends conflicts breaks
    Depends: libsharedlib1 (= 2.1-1)
    [debhello-2.1] $ dpkg -f libsharedlib1_2.1-1_amd64.deb pre-depends \
                depends recommends conflicts breaks
    Depends: libc6 (>= 2.2.5)

## 14.13. Internationalization

Here is an example of updating the simple upstream C source debhello-2.0.tar.xz presented in “Section 14.11, “Autotools (multi-binary package)”” for internationalization (i18n) and creating the updated upstream C source debhello-2.0.tar.xz.

In the real situation, the package should already be internationalized. So this example is educational for you to understand how this internationalization is implemented.

| Tip
The routine maintainer activity for the i18n is simply to add translation po files reported to you via the Bug Tracking System (BTS) to the po/ directory and to update the language list in the po/LINGUAS file.

Let’s get the source and make the Debian package.

Download debhello-2.0.tar.xz (i18n).

    [base_dir] $ wget http://www.example.org/download/debhello-2.0.tar.xz
     ...
    [base_dir] $ tar --xz -xmf debhello-2.0.tar.xz
    [base_dir] $ tree
    .
    ├── debhello-2.0
    │   ├── LICENSE
    │   ├── Makefile.am
    │   ├── README.md
    │   ├── configure.ac
    │   ├── data
    │   │   ├── hello.desktop
    │   │   └── hello.png
    │   ├── lib
    │   │   ├── Makefile.am
    │   │   ├── sharedlib.c
    │   │   └── sharedlib.h
    │   ├── man
    │   │   ├── Makefile.am
    │   │   └── hello.1
    │   └── src
    │       ├── Makefile.am
    │       └── hello.c
    └── debhello-2.0.tar.xz

    6 directories, 14 files

Internationalize this source tree with the gettextize command and remove files auto-generated by Autotools.

run gettextize (i18n):

    [base_dir] $ cd debhello-2.0
     $ gettextize
    Creating po/ subdirectory
    Creating build-aux/ subdirectory
    Copying file ABOUT-NLS
    Copying file build-aux/config.rpath
    Not copying intl/ directory.
    Copying file po/Makefile.in.in
    Copying file po/Makevars.template
    Copying file po/Rules-quot
    Copying file po/boldquot.sed
    Copying file po/en@boldquot.header
    Copying file po/en@quot.header
    Copying file po/insert-header.sin
    Copying file po/quot.sed
    Copying file po/remove-potcdate.sin
    Creating initial po/POTFILES.in
    Creating po/ChangeLog
    Creating directory m4
    Copying file m4/gettext.m4
    Copying file m4/iconv.m4
    Copying file m4/lib-ld.m4
    Copying file m4/lib-link.m4
    Copying file m4/lib-prefix.m4
    Copying file m4/nls.m4
    Copying file m4/po.m4
    Copying file m4/progtest.m4
    Creating m4/ChangeLog
    Updating Makefile.am (backup is in Makefile.am~)
    Updating configure.ac (backup is in configure.ac~)
    Creating ChangeLog

    Please use AM_GNU_GETTEXT([external]) in order to cause autoconfiguration
    to look for an external libintl.

    Please create po/Makevars from the template in po/Makevars.template.
    You can then remove po/Makevars.template.

    Please fill po/POTFILES.in as described in the documentation.

    Please run 'aclocal' to regenerate the aclocal.m4 file.
    You need aclocal from GNU automake 1.9 (or newer) to do this.
    Then run 'autoconf' to regenerate the configure file.

    You will also need config.guess and config.sub, which you can get from the CV...
    of the 'config' project at http://savannah.gnu.org/. The commands to fetch th...
    are
    $ wget 'http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/conf...
    $ wget 'http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/conf...

    You might also want to copy the convenience header file gettext.h
    from the /usr/share/gettext directory into your package.
    It is a wrapper around <libintl.h> that implements the configure --disable-nl...
    option.

    Press Return to acknowledge the previous 6 paragraphs.
    [debhello-2.0] $ rm -rf m4 build-aux *~

Let’s check generated files under the po/ directory.

files in po (i18n):

    [debhello-2.0] $ ls -l po
    total 60
    -rw-rw-r-- 1 osamu osamu   494 Feb 11 09:52 ChangeLog
    -rw-rw-r-- 1 osamu osamu 17577 Feb 11 09:52 Makefile.in.in
    -rw-rw-r-- 1 osamu osamu  3376 Feb 11 09:52 Makevars.template
    -rw-rw-r-- 1 osamu osamu    59 Feb 11 09:52 POTFILES.in
    -rw-rw-r-- 1 osamu osamu  2203 Feb 11 09:52 Rules-quot
    -rw-rw-r-- 1 osamu osamu   217 Feb 11 09:52 boldquot.sed
    -rw-rw-r-- 1 osamu osamu  1337 Feb 11 09:52 en@boldquot.header
    -rw-rw-r-- 1 osamu osamu  1203 Feb 11 09:52 en@quot.header
    -rw-rw-r-- 1 osamu osamu   672 Feb 11 09:52 insert-header.sin
    -rw-rw-r-- 1 osamu osamu   153 Feb 11 09:52 quot.sed
    -rw-rw-r-- 1 osamu osamu   432 Feb 11 09:52 remove-potcdate.sin

Let’s update the configure.ac by adding “AM_GNU_GETTEXT([external])”, etc..

configure.ac (i18n):

    [debhello-2.0] $ vim configure.ac
     ... hack, hack, hack, ...
    [debhello-2.0] $ cat configure.ac
    #                                               -*- Autoconf -*-
    # Process this file with autoconf to produce a configure script.
    AC_PREREQ([2.69])
    AC_INIT([debhello],[2.2],[foo@example.org])
    AC_CONFIG_SRCDIR([src/hello.c])
    AC_CONFIG_HEADERS([config.h])
    echo "Standard customization chores"
    AC_CONFIG_AUX_DIR([build-aux])

    AM_INIT_AUTOMAKE([foreign])

    # Set default to --enable-shared --disable-static
    LT_INIT([shared disable-static])

    # find the libltdl sources in the libltdl sub-directory
    LT_CONFIG_LTDL_DIR([libltdl])

    # choose one
    LTDL_INIT([recursive])
    #LTDL_INIT([subproject])
    #LTDL_INIT([nonrecursive])

    # Add #define PACKAGE_AUTHOR ... in config.h with a comment
    AC_DEFINE(PACKAGE_AUTHOR, ["Osamu Aoki"], [Define PACKAGE_AUTHOR])
    # Checks for programs.
    AC_PROG_CC

    # desktop file support required
    AM_GNU_GETTEXT_VERSION([0.19.3])
    AM_GNU_GETTEXT([external])

    # only for the recursive case
    AC_CONFIG_FILES([Makefile
                     po/Makefile.in
                     lib/Makefile
                     man/Makefile
                     src/Makefile])
    AC_OUTPUT

Let’s create the po/Makevars file from the po/Makevars.template file.

po/Makevars (i18n):

     ... hack, hack, hack, ...
    [debhello-2.0] $ diff -u po/Makevars.template po/Makevars
    --- po/Makevars.template        2026-02-11 09:52:55.403617303 +0000
    +++ po/Makevars 2026-02-11 09:52:55.482838579 +0000
    @@ -18,14 +18,14 @@
     # or entity, or to disclaim their copyright.  The empty string stands for
     # the public domain; in this case the translators are expected to disclaim
     # their copyright.
    -COPYRIGHT_HOLDER = Free Software Foundation, Inc.
    +COPYRIGHT_HOLDER = Osamu Aoki <osamu@debian.org>

     # This tells whether or not to prepend "GNU " prefix to the package
     # name that gets inserted into the header of the $(DOMAIN).pot file.
     # Possible values are "yes", "no", or empty.  If it is empty, try to
     # detect it automatically by scanning the files in $(top_srcdir) for
     # "GNU packagename" string.
    -PACKAGE_GNU =
    +PACKAGE_GNU = no

     # This is the email address or URL to which the translators shall report
     # bugs in the untranslated strings:
    [debhello-2.0] $ rm po/Makevars.template

Let’s update C sources for the i18n version by wrapping strings with _(…​).

src/hello.c (i18n):

     ... hack, hack, hack, ...
    [debhello-2.0] $ cat src/hello.c
    #include "config.h"
    #include <stdio.h>
    #include <sharedlib.h>
    #include <libintl.h>
    #define _(string) gettext (string)
    int
    main()
    {
            printf(_("Hello, I am " PACKAGE_AUTHOR "!\n"));
            sharedlib();
            return 0;
    }

lib/sharedlib.c (i18n):

     ... hack, hack, hack, ...
    [debhello-2.0] $ cat lib/sharedlib.c
    #include <stdio.h>
    #include <libintl.h>
    #define _(string) gettext (string)
    int
    sharedlib()
    {
            printf(_("This is a shared library!\n"));
            return 0;
    }

The new gettext (v=0.19) can handle the i18n version of the desktop file directly.

data/hello.desktop.in (i18n):

    [debhello-2.0] $ fgrep -v '[ja]=' data/hello.desktop > data/hello.desktop.in
    [debhello-2.0] $ rm data/hello.desktop
    [debhello-2.0] $ cat data/hello.desktop.in
    [Desktop Entry]
    Name=Hello
    Comment=Greetings
    Type=Application
    Keywords=hello
    Exec=hello
    Terminal=true
    Icon=hello.png
    Categories=Utility;

Let’s list the input files to extract translatable strings in po/POTFILES.in.

po/POTFILES.in (i18n):

     ... hack, hack, hack, ...
    [debhello-2.0] $ cat po/POTFILES.in
    src/hello.c
    lib/sharedlib.c
    data/hello.desktop.in

Here is the updated root Makefile.am with po added to the SUBDIRS environment variable.

Makefile.am (i18n):

    [debhello-2.0] $ cat Makefile.am
    # recursively process `Makefile.am` in SUBDIRS
    SUBDIRS = po lib src man

    ACLOCAL_AMFLAGS = -I m4

    EXTRA_DIST = build-aux/config.rpath m4/ChangeLog

Let’s make a translation template file, debhello.pot.

po/debhello.pot (i18n):

    [debhello-2.0] $ xgettext -f po/POTFILES.in -d debhello -o po/debhello.pot -k...
    [debhello-2.0] $ cat po/debhello.pot
    # SOME DESCRIPTIVE TITLE.
    # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
    # This file is distributed under the same license as the PACKAGE package.
    # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
    #
    #, fuzzy
    msgid ""
    msgstr ""
    "Project-Id-Version: PACKAGE VERSION\n"
    "Report-Msgid-Bugs-To: \n"
    "POT-Creation-Date: 2026-02-11 09:52+0000\n"
    "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
    "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
    "Language-Team: LANGUAGE <LL@li.org>\n"
    "Language: \n"
    "MIME-Version: 1.0\n"
    "Content-Type: text/plain; charset=CHARSET\n"
    "Content-Transfer-Encoding: 8bit\n"

    #: src/hello.c:9
    #, c-format
    msgid "Hello, I am "
    msgstr ""

    #: lib/sharedlib.c:7
    #, c-format
    msgid "This is a shared library!\n"
    msgstr ""

    #: data/hello.desktop.in:2
    msgid "Hello"
    msgstr ""

    #: data/hello.desktop.in:3
    msgid "Greetings"
    msgstr ""

    #: data/hello.desktop.in:5
    msgid "hello"
    msgstr ""

Let’s add a translation for French.

po/LINGUAS and po/fr.po (i18n):

    [debhello-2.0] $ echo 'fr' > po/LINGUAS
    [debhello-2.0] $ cp po/debhello.pot po/fr.po
    [debhello-2.0] $ vim po/fr.po
     ... hack, hack, hack, ...
    [debhello-2.0] $ cat po/fr.po
    # SOME DESCRIPTIVE TITLE.
    # This file is put in the public domain.
    # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
    #
    msgid ""
    msgstr ""
    "Project-Id-Version: debhello 2.2\n"
    "Report-Msgid-Bugs-To: foo@example.org\n"
    "POT-Creation-Date: 2015-03-01 20:22+0900\n"
    "PO-Revision-Date: 2015-02-21 23:18+0900\n"
    "Last-Translator: Osamu Aoki <osamu@debian.org>\n"
    "Language-Team: French <LL@li.org>\n"
    "Language: ja\n"
    "MIME-Version: 1.0\n"
    "Content-Type: text/plain; charset=UTF-8\n"
    "Content-Transfer-Encoding: 8bit\n"

    #: src/hello.c:34
    #, c-format
    msgid "Hello, my name is %s!\n"
    msgstr "Bonjour, je m'appelle %s!\n"

    #: lib/sharedlib.c:29
    #, c-format
    msgid "This is a shared library!\n"
    msgstr "Ceci est une bibliothèque partagée!\n"

    #: data/hello.desktop.in:3
    msgid "Hello"
    msgstr ""

    #: data/hello.desktop.in:4
    msgid "Greetings"
    msgstr "Salutations"

    #: data/hello.desktop.in:6
    msgid "hello"
    msgstr ""

    #: data/hello.desktop.in:9
    msgid "hello.png"
    msgstr ""

The packaging activities are practically the same as the one in “Section 14.11, “Autotools (multi-binary package)””.

You can find more i18n examples by following “Section 14.14, “Details””.

## 14.14. Details

You can obtain detailed information about the examples presented and their variants as follows:

How to get details.

    [base_dir] $ apt-get source debmake-doc
    [base_dir] $ cd debmake-doc*
    [debmake-doc-*] $ view examples/README.md

Follow the exact instruction in examples/README.md.

    [debmake-doc-*] $ cd examples
    [examples] $ make

Now, each directory named as examples/debhello-?.?_build-? contains the Debian packaging example.

- emulated console command line activity log: the .log file
- emulated console command line activity log (short): the .slog file
- snapshot source tree image after the debmake command: the debmake directory
- snapshot source tree image after proper packaging: the package directory
- snapshot source tree image after the debuild command: the test directory

Notable examples include:

- POSIX shell script with Makefile and i18n support (v=3.0)
- C source with Makefile.in + configure and i18n support (v=3.2)
- C source with Autotools and i18n support (v=3.3)
- C source with CMake and i18n support (v=3.4)

Chapter 13. Tool usages |  | Chapter 15. debmake(1) manpage