Home / Alt manpages / deb-src-symbols(5)

  • deb-src-symbols(5)
  • File format
  • linux

Write Debian Symbols Templates for dpkg-gensymbols

One silently dropped function in a shared library can break every program linked against it, and a symbols template is what catches that. This guide gives you a small workflow that records the library's exported ABI, lets dpkg-gensymbols compare later builds against it, and keeps source-only tags and patterns out of the binary package. The examples use dpkg-dev 1.22.6ubuntu6.6 and dpkg-gensymbols 1.22.6 as installed here.

Allow about 20 minutes for a first template and a review of its diff. You need:

  • A shared-library source package. One that builds a shared library, with the usual debian/ directory.
  • Edit access. Permission to change files in that source tree.

The commands inspect and generate package metadata. They do not install a package or restart a service. The template does affect runtime dependencies once the package is built, so review it like an ABI change.

1. Find the template and confirm the tool

deb-src-symbols(5) describes source-package templates. The usual names, in order of specificity, are debian/package.symbols.arch, debian/symbols.arch, debian/package.symbols and debian/symbols. The package-specific file is the clearest starting point because it says which binary package owns the library.

$ dpkg-query -W -f='${Package} ${Version}\n' dpkg-dev
dpkg-dev 1.22.6ubuntu6.6
$ dpkg-gensymbols --version
Debian dpkg-gensymbols version 1.22.6.

Inside the source package, identify the binary package name from debian/control, then look for its existing template:

PACKAGE='libexample1'
find debian -maxdepth 1 -type f -name "$PACKAGE.symbols*" -print

Checkpoint

If a template already exists, keep its header and review it before adding lines. If nothing turns up, do not create a guessed header. Establish the library's SONAME from the built file first, then let dpkg-gensymbols produce a candidate.

2. Read the header and symbol lines

A template starts with a library SONAME, the binary package's dependency template and #MINVER#. Each symbol line after that holds:

  • The exported name and its symbol version.
  • The earliest package version that provides it.

The SONAME must match the library itself, not just its filename.

libexample.so.1 libexample1 #MINVER#
 example_init@Base 1.0
 example_close@Base 1.0

The leading space before a symbol is conventional and keeps entries readable. #MINVER# is replaced when the binary package's dependency is calculated. Never write a made-up version: use the package version in which the symbol first became part of the supported ABI.

Comments begin with #, except for the special #include directive. A #MISSING: comment can document why a symbol disappeared. Keep comments factual. They are part of the maintenance record, not a way to silence an ABI check.

3. Generate a candidate from the built library

Build the package normally first. Then run dpkg-gensymbols from the source-package root, so it can find debian/control, the build directory and the package metadata:

dpkg-buildpackage -us -uc -b
dpkg-gensymbols -plibexample1 -Pdebian/tmp -v1.0 -Odebian/libexample1.symbols

Replace libexample1, debian/tmp and 1.0 with values from your package. The options:

  • -P points at the package build directory.
  • -p selects the binary package.
  • -v supplies the package version when there is no usable changelog.
  • -O writes the result to the named file.

In an ordinary package build, debhelper usually runs this step for you. Use the explicit command when creating or diagnosing a template.

For a read-only trial, write to standard output instead of changing debian/:

dpkg-gensymbols -plibexample1 -Pdebian/tmp -v1.0 -O- -c0

The output begins with the detected SONAME and lists the symbols found in the library. New symbols are normally reported in a diff on standard error. A successful exit status means the scan completed, not that every ABI decision is right.

Checkpoint

Save the candidate only after checking that the SONAME names the intended library and the symbol list is plausible. An empty or unexpectedly huge list usually means the wrong build directory, a plugin rather than a public library, or a library built without the expected exported ABI.

4. Tag deliberate exceptions

Tags go immediately before the symbol name, with no whitespace. The optional tag is for a symbol whose disappearance is allowed without failing the package. It still shows up as MISSING in the diff, so the loss stays visible:

 (optional)example_internal_helper@Base 1.0

Warning

Use optional only for a genuinely private or unstable ABI detail, never for a public function that vanished by accident. Removing a public symbol can break an existing consumer even when the package build succeeds.

Architecture restrictions help when a symbol exists only on some targets:

 (arch=linux-any)linux_only_entry@Base 1.0
 (arch-bits=64)wide_entry@Base 1.0
 (arch-endian=little)little_endian_entry@Base 1.0
 (arch-bits=32|arch-endian=little)small_le_entry@Base 1.0

Architecture names use the same form as Debian Build-Depends restrictions, without square brackets. arch-bits and arch-endian are supported since dpkg 1.18.0. In normal, non-template output only entries matching the current host are written. Template mode keeps entries for foreign architectures too.

The allow-internal tag permits a toolchain-internal symbol that dpkg normally blacklists. Treat it as an exception that needs a comment and a review. ignore-blacklist is its deprecated alias.

Other standard tags include c++, symver and regex. These select pattern matching rather than naming one exact exported symbol.

5. Use patterns only when one rule covers many symbols

A pattern supplies a default specification for real symbols that have no exact entry. An exact symbol entry takes precedence. The first matching generic pattern wins, so a broad regular expression can hide a later, more precise rule.

libexample.so.1 libexample1 #MINVER#
 (symver)EXAMPLE_1.0 1.0
 (regex)"^example_private_.*@Base$" 1.0
 (regex|optional)"^example_experimental_.*@Base$" 1.0

The regex expression is matched against the symbol's name@version. Anchor it with ^ and $ unless matching a substring is intentional. A pattern that matches nothing counts as lost and can fail the comparison at level 1 or above. Adding optional turns that into a visible MISSING result.

  • Use c++ when a demangled C++ name is stable but its mangled spelling changes between architectures.
  • Use symver when the library's symbol versions are the useful grouping.
  • Do not use a broad regex as a shortcut for understanding the ABI.

6. Split architecture-specific templates with includes

When one file gets hard to review, factor out the common entries and include architecture-specific files at the point where their entries should be read:

libexample.so.1 libexample1 #MINVER#
 common_entry@Base 1.0
 (arch=amd64 ia64 alpha)#include "libexample1.symbols.64-bit"
 (arch=!amd64 !ia64 !alpha)#include "libexample1.symbols.32-bit"
 another_common_entry@Base 1.0

Includes are processed line by line. Content after an include can override content from it, and tags on the include are inherited by the included entries. An entry in the included file can add tags or replace inherited values, but it cannot remove an inherited tag. Keep the files close to the main template and use quoted, repository-relative names another maintainer can find.

7. Compare the template and pick the output mode

Use comparison checking during packaging. The default level is -c1, and levels 0 through 4 get progressively stricter. Start at level 1, inspect the diff, and raise the level only when the package's ABI policy calls for it.

dpkg-gensymbols -plibexample1 -Pdebian/tmp -v1.0 -c1
printf 'dpkg-gensymbols status: %s\n' "$?"

For a template-preserving inspection, add -t. Template mode keeps standard and unknown tags in the output. Without -t, dpkg processes standard tags and strips them from the symbols file embedded in the binary package.

Warning

Do not commit template-mode output as if it were the final binary DEBIAN/symbols file.

This installed dpkg release predates the upstream #CURVER# metavariable, which current dpkg documentation marks as supported since dpkg 1.23.4. Do not put #CURVER# in a template meant to build with dpkg 1.22.6. Use the locally supported syntax, or raise the package's toolchain requirement deliberately.

8. Review failures without weakening the check

A missing required symbol means stop and investigate. Check that the library in debian/tmp is the newly built file, inspect its SONAME and exported versions, and confirm the template belongs to the selected binary package. Do not add optional just to turn a failure green.

  • New symbol. It normally needs a minimum package version line.
  • Disappeared symbol. It needs an ABI decision: restore it, document an intentional private-ABI removal, or make the package transition explicit.
  • Unstable ABI. If the library's ABI is intentionally unstable, a strict dependency using the appropriate package-version mechanism may be safer than pretending the symbol is compatible.

These commands change files only when you give -O a filename or run the normal package build. Before replacing a trusted template, copy it somewhere temporary or commit the current change in your normal source-control workflow.

Recovery

To undo an unreviewed generated file without touching other work, restore that one file from version-control history. Do not delete the whole debian/ directory.

Done means

  • Named and headed correctly. The template is named for the binary package and its header matches the library SONAME.
  • Versions are honest. Every minimum version is the first package version that provided the symbol.
  • Exceptions are deliberate. Optional, architecture-specific and pattern rules cover real ABI cases only.
  • Diff reviewed. dpkg-gensymbols has run against the intended debian/tmp tree.
  • Modes kept apart. Template mode is not confused with the tag-stripped symbols file shipped in the binary package.
  • Toolchain matches. The package builds with the installed dpkg version, or newer syntax has an explicit toolchain requirement.