| CARVIEW |
Advice for upstream developers who want their software to be in Debian. To learn how to actually create Debian packages, see Packaging.
Even if you don't want your software to be in Debian, much of the advice on this page will make your software easier to deploy, maintain, and package for other distributions.
Contents
- Why get your software into Debian?
- Make changes based on feedback
- Choose a standard open source license
- Register new media types
- Provide a well-named source tarball
- Release early, release often
- Use a bug tracker
- Document your build system
-
Maintain a flexible build process
- Run tests while building
- Support verbose building
- Support offline building
- Support out-of-tree builds
- Support out-of-VCS builds
- Support cleaning the tree
- Support other compiler commands
- Support staged installs
- Split the "make" and "install" stages
- Create directories during the "install" stage
- Ignore your project's top-level directory name
- Do not modify existing files
- Do not target the machine being built on
- See also
Why get your software into Debian?
You'll have more, happier users:
- people can find and install your software more easily
including users of Debian derivatives like Ubuntu
- organisations can streamline their approval process
they're protected from supply chain attacks (see paper and examples)
You'll get higher-quality software:
- you'll get a review from an external developer who can share best practices from other projects
- your Debian Maintainer will ensure your software plays nicely with system startup, logging, file types, network setup, desktop environment, sandboxing, and so on
- your dependencies' Debian Maintainers will ensure compatibility, security etc. for those projects
- CI tests will alert you about problems with specific hardware architectures (including ones you may not have access to)
- QA tests will alert you about changes in your dependencies
Make changes based on feedback
Be prepared for packagers to put significant effort into reviewing your code, and to suggest changes you see as trivial or problematic. Make time for their questions, and take their arguments as constructive criticism. Where possible, use feedback as an opportunity to write unit tests.
There is a lot of advice on this page, and Debian developers are responsible for ensuring their packages follow the Debian Policy Manual. This sometimes means making all Debian packages behave the same, because users would rather have one rule they can rely on, even if your way is better. And it sometimes means mitigating theoretical security concerns, because they'd rather be too secure for 99% of packages than not be secure enough for the several hundred edge cases in the Debian archive.
It's fine to put changes behind a configuration flag you disable by default, or to discuss alternative solutions instead of accepting the first answer - just engage constructively, and understand that your packager is working on a slightly different problem than you are. Debian can maintain downstream patches to your project if necessary (as can other distributions), but a one-line patch to a configuration file creates less of a maintenance burden than having to change behaviour throughout your codebase.
Debian will run your unit tests as part of every build, so every unit test you write becomes a free source of bug reports. If Debian upgrades a dependency, adds a new architecture, or makes some other seemingly-trivial change, a unit test will immediately tell you if it breaks your program somehow.
Debian supports a wide variety of architectures, and your packager may well ask for changes that aren't relevant to any architecture you actually use. For details, see CategoryMultiarch. Once the packaging process is underway, build logs on buildd.debian.org will show failures and compiler warnings for all supported architectures.
Bootstrapping (compilers/interpreters only)
If your project is a self-hosting compiler/interpreter for a programming language, explain how to compile the project on a new architecture that does not have an existing compiler for your language. Solutions include:
- support cross-compilation
for example, teach your x86_64 compiler to create armhf code
- write a compiler in a language that already exists for that platform, such as...
- a reference implementation of your language in Python
- a mini-compiler that only supports the subset of your language necessary to compile the compiler
- a fork of the last version of your project before self-hosting
This process will very rarely be used in practice, so it's OK for it to be quite baroque. For example, you might start with the last version before self-hosting, then use that to create a mini-compiler, then use that to create a non-optimising modern compiler, and so on.
For another perspective on why this is important, see Ken Thompson's famous reflections on trusting trust attack, and David A. Wheeler's diverse double-compiling defence.
Choose a standard open source license
License your project using one of the licenses compatible with the Debian Free Software Guidelines. Popular choices include the GPL, LGPL and 3-clause BSD license.
Writing your own license without training as a lawyer is like writing your own encryption algorithm without training as a cryptographer - you'll probably create something vulnerable to an attack that's widely known in the community but too obscure to think of yourself.
Use the same license for all files
Choose a single license and stick to it throughout the project. If some files need different licenses, consider splitting them into a separate project.
Debian needs to ensure it uses software in accordance with the license - multi-license projects are supported, but are significantly harder to maintain. And if a future legal judgement renders those licenses incompatible somehow, we won't be able to distribute your package at all.
For ways packagers can discard optional files with non-DFSG-free licenses, see "If upstream has content that is disallowed" in ManageUpstreamDifferences.
Maintain a COPYING file
Include a file in the top-level directory called COPYING, and if necessary other files with individual licenses.
If all files have the same license, COPYING should include the full text of that license.
If some files have different licenses, COPYING should specify which files have which licenses, and individual files called e.g. GPL or LGPL should include the full text of each license.
Some ecosystems use a different filename (e.g. Python suggests variations on "LICENSE"). If you're not sure a packager would find the file right away, mention the location in the README. It's OK to also create a symbolic link from COPYING to that file, although that might cause issues for Windows users who try to clone your repository. It's best not to maintain a second copy of the file, because it may become impossible to distribute your package if the two copies fall out of sync.
Maintain an AUTHORS file (optional)
If you want to provide detailed information about individual authors (e.g. their e-mail addresses, who they work for, and what they work on), put that in a file called AUTHORS in the project's top-level directory.
For an example, see GNU Hello's AUTHORS file.
This file is not related to git's mailmap file, but projects that need one are likely to need the other.
Put copyright attribution at the top of every file
Put a copyright attribution statement at the top of every file, including a statement about the author(s) and license. E-mail addresses and company names can only be omitted if they are listed in AUTHORS.
Debian needs to track the copyright information for each file you release, so our copyright review tools treat copyright statements as metadata. Without that metadata, reviewers have to spend a lot (often a majority) of their time manually confirming the license of each file. See also On the Importance of Per-File License Information.
For an example, see GNU Hello's src/hello.c file.
Keep copyright information up-to-date
Change the names and dates in all your copyright statements as necessary.
If you're taking over an abandoned project, add your name everywhere the previous maintainer's name went.
You'll need to update all the year numbers in the copyright statements next January. Consider writing the year as e.g. 2020-2020 instead of just 2020, so you can use a command like:
sed -i -e "s/\(20[0-9][0-9]-\)20[0-9][0-9]/\1$(date +%Y)/" \
$(git grep -l 20[0-9][0-9]-20[0-9][0-9])
Actually follow license rules!
License statements specify what you can do with the licensed project. Violating those rules means Debian can't package your project.
One common issue is choosing a BSD license but including GPL libraries. GPL licenses override BSD ones, applying the GPL to the whole package. You'll need to use LGPL libraries instead.
Some libraries have licenses that can't be used together at all. For example, OpenSSL used to have a license that did not allow linking against GPL code.
Register new media types
If you create a new media type ("MIME type"), consider registering it with the IANA. This ensures that applications distributed in Debian and other operating systems recognise your file type.
Provide a well-named source tarball
Provide your source code in a file called something like $PROJECT_NAME-$PROJECT_VERSION.tar.{gz,bz2,lzma,xz} (e.g. hello-1.0.tar.gz). If you want to provide precompiled binaries for users, put them in a separate binary tarball instead.
Debian needs you to provide complete source code so it can build its own binaries from your source code. That's how it knows the binaries it distributes actually match the source. Debian's standard tools expect to import sources from tarballs with filenames that specify the project name and version number.
Debian needs you not to provide binary files so it can distribute the source code itself. That's how other people can confirm that Debian is actually building the binaries from the specified source.
If you include binaries in your source tarball, your packager will need to spend time removing those files because they can't prove you didn't e.g. include an icon with unclear copyright attribution. If you want ordinary users to have a copy of the source code, add it to a subdirectory of the binary tarball instead of adding binaries to a subdirectory of the source tarball.
For an example of Debian distributing source and binary files, see the GNU Hello .deb file, and the source code to build it.
For information about proving binaries were created from a given source, see ReproducibleBuilds.
Specify dependencies and versions
Include a list of other projects necessary to build your project, and a separate list of projects necessary to run it. Each dependency should include a name, homepage, license and (where relevant) a range of supported version numbers. For dependencies that require a specific range of versions, describe the range of supported versions. For optional dependencies, mention that they're optional and how to work around their absence.
Debian needs to install packages on their servers while building your project, and needs to tell users which packages to install alongside your package. Listing the relevant projects makes that much easier.
If your project depends on a feature that was only added in a given version of a dependency, or is broken by a change in a given version, Debian needs to know that so it can install your package and know which versions of the dependency to ship.
Depending on a version that's only in Debian unstable might make it harder to release your package, and depending on an unreleased version or a patch that hasn't been accepted upstream will make things harder still. If you can't avoid such dependencies, explain the issue and link to a post or issue tracker where you sent the patch upstream - a packager may be willing to keep an eye on the issue and package your project when the upstream issue is resolved.
If a dependency needs to be removed from Debian for some reason (e.g. a license dispute), disabling the dependency may be the only way to keep your package available. This is only possible for optional dependencies.
Dependencies are usually specified as e.g. project-name >= 1.0.0. You can use = instead of >= if you need exactly 1.0.0, but if another package requires 1.0.1, Debian may be forced to remove your package from the archive.
For details about specifying versions, see Syntax of relationship fields. For architecture-specific dependencies, see discussions of the <!nocheck> profile in BuildProfileSpec. For tricks packagers use to find dependencies, see How do I know which packages to (build-)depend on?.
Do not include automatically-generated files
Avoid putting files in your tarball that are automatically generated from other files. Your build system should create these files, and your documentation should explain the dependencies necessary to create them. For artwork, audio etc., see How to be a good upstream for games.
For security and licensing reasons, Debian needs to prove all files really can be built from the original sources. The only way to do that is to build them, so your package needs to make that possible. For example, compiled documentation, lexers and parsers should all be buildable from source.
This rule is sometimes waived, mainly for historical reasons. For example, most packages do not rebuild the files generated by autoconf and automake, because they used to break during automatic builds.
See also AutoGeneratedFiles.
Do not include a /debian directory
Never put a top-level subdirectory called debian/ in your tarball. If you want to provide a rough initial packaging directory, consider using contrib/debian/ instead.
The Debian packaging process involves maintaining a debian/ directory with its own history separate from your project. Providing your own version of that directory will cause merge conflicts, so most packagers will delete it without looking at it.
If you create your own .deb packages, consider keeping your debian/ directory in a separate branch. Or if you want to nudge packagers to use particular metadata, put example files in contrib/debian/ and co-ordinate with them when you want to change it.
For information about managing upstream and packaging in a single repository, see "If there is no upstream repository" in PackagingWithGit. For workarounds used by packagers, see "If upstream has content that is disallowed" in ManageUpstreamDifferences.
Do not include third-party code
Do not put code in your tarball where the canonical version is hosted elsewhere. List other people's libraries as build-dependencies, and build against the library versions that are installed system-wide.
When a security issue is detected, Debian's security team needs to quickly identify and fix all the packages that include the vulnerable software. This can involve checking hundreds of projects in a short time, which is only possible if dependencies are declared in a standard way, and if completely automated rebuilds are available.
After the security team resolve a problem, the build servers need to rebuild affected packages, and users need to update their packages. If your package links against a library instead of including it, your package itself won't be part of that problem - your users can just download the library and restart your program.
If your project can only be built against a local copy of a dependency (e.g. because it contains patches you haven't yet pushed upstream), ensure the dependency is optional so Debian can just exclude it. If you can't make a dependency optional and can't get the authors to accept your patches, you'll need to fork that project and become its permanent maintainer.
If you want to specify the exact version of a third-party project because you've experienced version-specific bugs, state the version number in the list of build-dependencies and provide tests that fail on non-conforming versions of the third-party project. Debian will then have enough information to maintain the package.
For details, see debian policy 4.13.
Do not hardcode distribution-specific values
Do not hardcode messages or settings that are specific to any particular distribution. Instead, talk with your packager about adding build flags, paths to put logos in, or other hooks for them to hang distro-specific content on.
If you hardcode a distro-specific message in your man page or logo in your GUI, packagers for other distributions will need to replace them. That means maintaining a downstream fork, and checking each new release for new distro-specific additions.
Changing distro-specific content (e.g. a updating a logo) involves a lot of distro-wide co-ordination. If you make that configurable, distributions can make the change without needing any of your time.
Include all documentation
Put all your documentation in your source package. Do not hotlink to online versions, or rely on online contents (e.g. JavaScript libraries, images etc.). Avoid third-party libraries and non-free material altogether.
Many users prefer local documentation for various reasons: it works behind a restrictive company firewall, still exists when the online documentation has been updated to a newer version, and lets you grep for a regular expression.
If you use your documentation to generate your project website, consider documenting a build flag to disable site creation. Debian can then set that flag, and remove any build-dependencies that are only needed when making the site.
Write manual pages
Write a manual page for each executable, and for libraries in languages that usually provide them (like C and Perl). If possible, write a manual page for every configuration file. Include an EXAMPLES section wherever possible.
Users expect that typing man foo will tell them how to run foo. Note that generating a man page from --help output (with a tool such as help2man) usually don't look like users expect, and generating such a page during the build process can cause your package not to cross-compile.
Users can copy examples from an EXAMPLES section if they're busy or confused. For example, a page for an executable might show some common usages, a page for a library might show examples a user can paste into their own program, or a page for a config file might show the default configuration.
For details, see debian policy 12.1.
Provide upstream metadata
Include a list of project-related URLs, security contacts, etc. For scientific projects, include references to the work your project is based on.
Your packager will put this in a debian/upstream/metadata file - see that page for information and a suggested YAML format.
Use standard paths
Follow the Filesystem Hierarchy Standard for file locations. If possible, use variables like autotools' GNU Directory Variables or cmake's GNUInstallDirs. Other build systems should provide equivalents.
Upstream packages are often installed in /usr/local, but Debian packages must not touch that directory. If you use standard environment variables, packagers can change the location without patching the source.
See also Support staged installs.
Remove language extensions from executable filenames
Call your main program e.g. myprogram, not myprogram.py. If you feel a filename benefits from a language-specific extension, that usually suggests it should be an example program, and should go in an examples subdirectory.
Ordinary users shouldn't need to know what language programs are written in, so that information shouldn't be encoded in filenames.
Ordinary users may well want to know what language an example program is written in, but packagers need to put them in /usr/share/doc/package/examples instead of /usr/bin. If you put examples in an examples subdirectory, your packager can use dh_installexamples to install them.
For details, see:
Support /etc/your-project.d for configuration
Read configuration files from $(sysconfdir)/your-project.d/*.conf or $(sysconfdir)/your-project.d/your-project.conf, not just $(sysconfdir)/your-project.conf.
Supporting multiple configuration files often makes configuration easier. For example, logrotate reads anything in /etc/logrotate.d, so packages can register themselves with it just by putting a file in that directory.
Even if you only ever expect to support a single configuration file, putting that file in a separate directory can help with some use cases. For example, security-conscious users may want to run your program in a sandbox, which is easier if they can bind-mount a configuration directory (bind-mounting files is supported, but tends to behave in surprising ways).
Support XDG Base Directory paths
Choose directories for caching, configuration, data, sockets etc. based on the XDG Base Directory Specification. There are libraries available in Debian.
Users increasingly expect programs to follow the XDG Base Directory Specification, and will know to look for files there. And systemd uses these directories to configure user units.
Use the right home directory
Choose the user's home directory by checking the HOME environment variable (using getenv(3) or similar), or fall back on information from the password database (using getpwuid(3) or similar).
Hardcoding /home/$USER fails for commands run with sudo, and for people who choose to put an account's home directory in e.g. /mnt/memory-stick.
Release early, release often
Release a new tarball every time you reach a point where everything generally works and you've fixed a variety of bugs or implemented some interesting new features.
Releases signal to Debian that a version is considered stable. Otherwise Debian will have to guess the version from the latest commit to the upstream repo, or an automatic snapshot, or some other heuristic - these all tend to cause nasty surprises.
Adding a git tag for a release is a useful addition, but a source tarball is the baseline that is supported no matter the upstream or packaging workflow.
Use a public git repository (optional)
Publish your code in a git repository, hosted in a forge (or at least somewhere online).
Debian's packaging forge and Fedora's packaging forge both require packages to use git. Using git in your own project makes it easier for most Debian maintainers to pull your changes and send you their patches.
Debian can handle projects that just release tarballs, but putting your repository online lets package maintainers (and other contributors) pull your changes in a more natural way.
Forges provide a more familiar interface for ordinary users, and can include features that help automate the packaging process. For example, you might be asked to create a webhook on your forge that triggers a pipeline on Salsa whenever you release a new version.
Add git tags with a common format (optional)
If you manage your project with git, consider making a new tag of the form v$VERSION for each release (e.g. v1.2.3 for release 1.2.3). If you use a different pattern (e.g. release-$VERSION), explain the pattern so your packager can write a regular expression for it. Please avoid tags of the form upstream/$VERSION, as some Debian automation software generates this pattern by default.
Many packagers who use git will automate their process by looking for tags that match a known pattern. Guaranteeing that pattern makes their life easier.
For more information, see "Import from an upstream git repository" in PackagingWithGit.
Add unique version numbers
Give each release a version number greater than the previous release, even if the previous release was an accident that only went up for a few minutes. If version numbers are supposed to mean something (e.g. semantic versioning), ensure numbers follow the policy even if you have to bump features to a later milestone than you promised.
If two tarballs have the same release number, packaging scripts might behave surprisingly because they only saw one version. Or worse, they might think your website has been compromised and malicious code added to your package. No matter how tiny the change, you should never reuse a version number. Nobody will mind if you release version 1.2.4 a few minutes after 1.2.3 with a message about how the previous version was unusable for some boring reason.
Be bold about increasing version numbers - don't get trapped in sub-sub-sub-versions or scared about crossing magic numbers. If you promised yourself version 1.0 would have some feature, bump the feature back to version 2.0 instead of releasing a version 0.9.8.93 that's 1.0 in all but name. You won't run out of numbers, and anyway you'll be on to release version 1.1 the moment a user finds a bug.
Debian went straight from version 0.93R6 to 1.1, there is no Debian 1.0.
Sign releases
Sign your release tarballs, tags, and announcements with your OpenPGP key. Include digests for all artifacts in your announcement, using a strong digest such as SHA2-256, SHA2-512 or SHA3, not e.g. MD5, SHA-1 or RIPEMD-160. If your project is especially security-sensitive, consider signing every commit.
Package maintainers try to review your work, but their specialism is packaging, so they often have to accept your code changes are correct. Signing your packages makes it harder for an attacker to get malicious code into Debian by guessing some password.
Signing everything and including the digests in the announcement creates chain of trust for the entire release. If you only sign the release announcement, an attacker can replace the source tarball with a malicious copy. If you sign the release, source tarball, and any other artifacts but don't include the digests in the announcement, an attacker can replace the source tarball with a (signed) older version that still had a known vulnerability.
For information about signing tags, see git tag -s. For details about key-signing, see creating and signing OpenPGP keys and finding somebody to sign your key.
Explain support lifetimes
Explain the level of support for the current and older versions of your project. Consider committing to long-term support for versions of your software that wind up in stable releases of major distributions.
Distributions need to support all packages for the lifetime of a release, which is often several years. It's OK to leave that to distros if you don't have the resources to do it yourself, but they need to prepare for that during the packaging process.
If you're not sure how much support you can provide, talk it through with package maintainers and agree who will provide what level of support.
Ensure backwards-compatibility
Design your API/ABI with backwards-compatibility in mind, and update the project's major version every time you break compatibility. Don't let private symbols leak into public interfaces.
If you're writing a library that's compiled to a .so file, assign an SONAME like libfoo.so.N, where N is the project's current major version number. Consider using the ABI Compliance Checker to make sure you don't accidentally make an incompatible change.
I went to https://ispras.linuxbase.org/index.php/ABI_compliance_checker on 2025-06-05 and got a page that said "Can't contact the database server: Unknown MySQL server host 'db21.linux-foundation.org' (2) (db21.linux-foundation.org)" - consider deleting the link above if the page remains broken
If you're writing a library, hide symbols by default unless you explicitly want to make them part of the public API. For C and C++, see Visibility (page starts talking about C++ in GCC, then moves on to C and other compilers). For other languages, look for discussions about "visibility" , "hidden" or "private" symbols. For languages that lack a built-in "private" flag, there is often a convention of prepending an _ to indicate that a symbol is private.
If your project puts some functionality in library files for internal use only, make those libraries private whenever possible. For C and C++, use -fvisibility=hidden (discussed in Visibility). For other languages, search online for discussions about linkage. For interpreted languages, your build system might need to concatenate your libraries and executable into a single file.
Use a bug tracker
Explain how people should report issues. If possible, explain how to privately report security issues. For example, your README file could link to your GitHub issue URL and ask people to e-mail you privately about security issues.
Users often report issues to bugs.debian.org, even for non-packaging-related problems. Linking to your own bug tracker makes it easier for people triaging bugs to contact you, or for users to find your URL if they don't get a response from Debian.
It's particularly important to put your security procedure somewhere people will find it, because security issues are likely to come from people who haven't interacted with your package before (e.g. the Debian security team), and need to quickly mitigate problems with a large set of vulnerable packages.
Distinguish between bugfix and feature changes
Keep features and bugfixes in separate commits, especially if you rely on Debian for some of your project's support lifetime.
When you fix a bug in the latest version of your project, there may be a need to backport it to an older version. For small bugs in a well-maintained git repository, this is usually as simple as cherry-picking the commit and creating a new patch-level release.
Handle security issues transparently
Request a CVE identifier for every security issue, and include the CVE identifier(s) in commit logs, NEWS, changelogs and announcements. Provide patches for each version you support, and help security teams and maintainers who need to backport that fix to older versions you don't support. Contact the Debian security team if you have questions.
It's natural to take a moment to blame yourself when a security issue arises, but everyone else will judge you more on your actions after the event than before.
As a rule of thumb, transparency about security issues helps defenders more than attackers. Sneaking an undocumented fix into an unrelated patch might increase the time before evil hackers find it, but it also increases the risk overworked maintainers will ignore it completely. Announcing the issue on a mailing list probably won't give those hackers enough time to exploit it before you can patch it, let alone before your users can roll out temporary mitigations.
Ideally, you should provide a patch for all versions of your program in the stable versions of all major distros. It's OK to rely on distributions to do that maintenance work, but be aware they'll need your help cherry-picking the relevant commit(s) into their version.
Document your build system
Explain which build system your project uses, and which commands are necessary to build it.
Debian adds a Makefile called debian/rules that can wrap any build system, but well-supported build systems like those below tend to make packaging easier.
For a list of build systems explicitly supported by Debian, see Debhelper/Buildsystem/*.pm.
Autoconf and Automake
Update config.guess and config.sub before each release - use autoreconf, download them from GNU, or copy them from /usr/share/misc/ (they're part of autotools-dev).
Autoconf and automake are mature enough that most users can make do with older versions. But changes often affect some edge case that's relevant to Debian, so staying up-to-date can avoid build failures.
Make
Do not set variables used by dpkg-buildflags. For a list, see supported flags or do dpkg-buildflags --list. Common flags include CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS.
Some compilation flags are reserved for the user. The Automake manual and the GNU coding standards advise never to use them for switches that are required for proper compilation. dpkg-buildflags sets these variables during compilation, and overriding them can cause unexpected behaviour.
If you need to set compilation flags in your Makefile, use another name instead. For example:
LOCAL_CFLAGS=$(CFLAGS) -DFOO=1 -DBar=2
Java build systems
Consider using Maven. Debian can redirect pom.xml files to dependencies available locally, making maintenance much easier.
Some language-neutral issues that are particularly common in Java packages:
do not ship prebuilt .class or .jar files, or any other generated files without accompanying source code
- do not download files during the build process
- document each dependency, especially where its source code is available from
Perl build systems
Use Module::Build or ExtUtils::MakeMaker, and please don't modify it in too many odd ways. Provide a way to set defaults or bypass prompts with known answers, to make automated builds possible.
For details, see the Perl group's package policy.
Python build systems
Use one of Python's standard build systems. Debian's python policy specifically mentions setuptools.
Some language-neutral issues that are particularly common in Python packages:
- do not break API/ABI unless you really have to
- do not bundle local copies of third-party modules, we will remove them anyway
- do not depend on unstable or unreleased versions of third-party libraries
OCaml build systems
Support installing your project on architectures where the native-code compiler (ocamlopt) is not available.
OCaml provides native-code compilation for some platforms, and bytecode compilation for the rest.
The easiest solution is to provide make targets (or your build system's equivalent) called all and install to build native code, plus targets called opt and install-opt to build bytecode. Alternatively, have all and install behave differently depending on whether ocamlopt is present at build-time.
Avoid SCons
Avoid SCons - it is hard to use correctly. For example, it ignores environment variables like CFLAGS and DESTDIR by default, and doesn't support SONAMEs. Projects that use SCons often don't have a working install target. Projects also tend to have their own workarounds, so there's no way to just use a "standard" SCons project in Debian.
If you use SCons anyway, ensure that the usual environment compiler variables (CC, CFLAGS, etc.) and path variables (DESTDIR, BINDIR, LIBDIR, etc.) are honoured. There is a recipe to address some of these issues.
For more information, see the Gentoo wiki's arguments against using SCons.
Avoid waf
Avoid waf - it recommends shipping a waf executable in your source tarball (i.e. shipping an auto-generated file).
Debian's FTP team consider shipping just the waf binary non-compliant with the Debian Free Software guidelines, creating more work for your packager. For details, see #645190. If you ship a waf executable anyway, see UnpackWaf.
Debian supports leaving the waf executable out of your source tarball and compiling with the system-provided waf instead. But upstream waf explicitly discourages that.
Maintain a flexible build process
Run tests while building
Make a test suite that runs during the build process. If possible, make another test suite for the actual installed program.
Unit tests are a great way to ensure your program works. Running them with a command like make test lets Debian check your program works on every architecture it's built for. It's quite common for programs that have only ever run on an x86_64 PC to fail on e.g. armhf.
System integration tests are a useful way to check for packaging errors. For example, Debian can often detect missing dependencies just by installing your package and calling your program with --help. Programs that interact with the system in more complex ways (e.g. editing the firewall) may find integration tests even more useful than unit tests.
For test results from recently-tested packages, see https://ci.debian.net.
Support verbose building
Disable your build system's "verbose" mode by default, enable it with a flag that is either well-known or documented in your README file.
Your packager will build your package a few times, then hand it over to Debian's build servers, which will rebuild automatically from time to time (e.g. when your dependencies are updated). Packagers usually prefer a quiet build log during testing, ignore the log for successful automatic builds, then suddenly want all the information they can get when they find an intermittent error that only occurs on riscv64. That will all just work if you provide a standard way for the build servers to enable verbosity.
These well-known flags are currently recommended:
# if you use autoconf:
./configure --disable-silent-rules
# if you use Makefiles:
make V=1
Support offline building
Ensure that your project can be built without Internet access. You should only need the dependencies listed in your README file.
Debian guarantees every binary package can be built from the available source packages for licensing and security reasons. For example, if your build system downloaded dependencies from an external site, the owner of the project could release a new version of that dependency with a different license. An attacker could even serve a malicious version of the dependency when the request comes from Debian's build servers.
Support out-of-tree builds
Ensure that your software can be built from specific subdirectories of the source tree, and from entirely different locations.
Debian may need to create multiple packages for your project. For example, if your /server directory contains a C program and your /client directory contains a shell script, Debian will probably cd .../server and build it for every architecture, then cd .../client and just build it once.
Debian may also need to build your software for multiple architectures at the same time. For example, if your project needs to be compiled for i386 and x86_64, the build system might extract the project contents into two separate directories and run the compilations in parallel.
If you use automake, make distcheck will check your package supports this.
Support out-of-VCS builds
Ensure that your software can be built in a directory without files from your version control system (e.g. .git or .svn).
Debian guarantees every binary package can be built from the available source packages for licensing and security reasons. We can't do that if your package requires version control information that isn't present in the source tarball.
If your project can't be built without VCS metadata, you will need to include it in your source tarball. Consider exporting VCS logs with git2cl, svn2cl or cvs2cl. Or consider autorevision to export VCS metadata.
Support cleaning the tree
Delete all generated files and reset the build tree to its initial state with a command that is either well-known or documented in your README file.
Debian (and your users) may want to reuse an extracted directory instead of deleting it. This is usually done with make clean, but other options can be supported if necessary.
Support other compiler commands
Call your compiler using a variable like $(CC) or $(CXX), not a specific program name like gcc or g++. Either use standard variables names or document the variables. If possible, try your code in another compiler like clang.
Your project will usually be compiled on an amd64 PC, but can be cross-compiled for all of Debian's other architectures. Cross-compilation builds of gcc have filenames like aarch64-linux-gnu-gcc, so Debian needs to call the right command when cross-compiling.
Debian's build system sets the well-known CC and CXX environment variables when cross-compiling, but packagers can add non-standard variables in debian/rules if necessary.
Compiling your code in another compiler can be a good way to find subtle bugs. For example, gcc and clang often adapt each other's code tests, so fixing a clang-only warning today could avoid a gcc error tomorrow.
The following standard variables are available by default:
Replace... |
... with |
ar |
$(AR) |
as |
$(AS) |
cc |
$(CC) |
ctangle |
$(CTANGLE) |
cweave |
$(CWEAVE) |
g++ |
$(CXX) |
f77 |
$(F77) |
ld |
$(LD) |
lex |
$(LEX) |
lint |
$(LINT) |
m2c |
$(M2C) |
make |
$(MAKE) |
cc |
$(OBJC) |
pc |
$(PC) |
tangle |
$(TANGLE) |
tex |
$(TEX) |
texi2dvi |
$(TEXI2DVI) |
weave |
$(WEAVE) |
yacc |
$(YACC) |
Other binutils commands (like strip or readelf) need to be replaced with variables, but do not have standard names.
Support staged installs
Support installing in a subdirectory with the DESTDIR environment variable. GNU Directory Variables, GNUInstallDirs etc. do this automatically.
When building a package, your project will be installed to a staging directory, then everything in that directory will be packaged. This is usually accomplished by setting the DESTDIR environment variable, and expecting the build system to prefix that to all paths.
For details, see DESTDIR: Support for Staged Installs.
If you use automake, make distcheck will check your package supports this.
Split the "make" and "install" stages
Provide a "make" step that builds all necessary files, and an "install" step that just moves those existing files into their correct location.
If you modify files during the install stage, you risk embedding temporary staging paths in the final output. This is ugly at best, and can be a security issue for RPATH values.
Create directories during the "install" stage
Ensure your "install" stage works whether or not your destination directories exist.
Most users who run make install on their local system will already have a /usr/local directory, but most automated build systems will set DESTDIR to an empty directory. The mkdir -p, install -d and installdirs commands all succeed whether or not the destination path exists, as does the $(MKDIR_P) Autoconf/Automake macro. Your build system may also provide its own solution.
Ignore your project's top-level directory name
Don't assume your project's top-level directory will have any particular name.
When building packages, Debian might unpack your project into a temporary directory. So for example, a cmake script that sets PROJECT_NAME based on CMAKE_SOURCE_DIR could end up calling your project tmp.HjH9buvNvx.
Do not modify existing files
Treat files in your source tarball as read-only. If you need to generate a file based on them, create a new file with a different name instead of overwriting the original.
Files with different contents between the source tarball and the final build are confusing, and can make it look like your packager has introduced a Debian-local modification. Such modifications are frowned upon, which makes your packager look bad.
Autoconf solves this problem well. It reads files of the form foo.in, substitutes some variables, then writes an equivalent foo file. foo should be treated like any other generated file, and should be deleted by make clean and/or make distclean.
Do not target the machine being built on
Avoid compilation options that assume the CPU being built on is the same as the CPU the program will run on. If you want to provide such options, disable them by default and mention how to enable them in the README. Or if you want to provide optimised versions of libraries, use hardware capabilities directories.
Packages are usually compiled on machines that are relatively modern, but Debian supports decades-old CPUs so long as they support certain baseline features. If you create binaries that require all the features of the build system's processor, your program will crash on most users' machines. Even if you just optimise for the current build system, you will reduce performance for the users who most need it.
See also
Debian resources for your package
http://tracker.debian.org/your-package
- a portal to all kinds of information
click subscribe in the top-right to be notified about releases and bug reports
- recommended but optional - the Debian maintainer will forward you bugs that need your help or interest
http://bugs.debian.org/your-package
- all bugs that have been reported by Debian users
- we would be delighted if you helped out, proposed patches or fixed issues upstream
- discussion about technical development topics
- non-technical topics related to the Debian Project
Producing software
Producing Open Source Software by Karl Fogel
Packaging Unix software by Adam Sampson
Releasing FLOSS for Source Installation by David A. Wheeler
Ten Simple Rules for the Open Development of Scientific Software by Andreas Prlić and James B. Procter (LWN comments)
FOSS Build and Install Common Practices by Matt Taggart
The Fundamental Theorem of Developing FLOSS by Máirín Duffy (followup)
Expectations of free software developers by Lars Wirzenius
What is source code? by Francesco Poli
Possibly controversial Best Practices Criteria for Open Source Software (OSS) by the Linux Foundation's Core Infrastructure Initiative (LWN article)
Release management in Open Source projects by Martin Michlmayr
What is Left to do After your Open Source Project is Done by Loup Vaillant
Our Software Dependency Problem by Russ Cox
Writing a C library by David Zeuthen
(includes some advice that can be considered controversial) How you know your Free or Open Source Software Project is doomed to FAIL (wiki version) by Tom Callaway
see also This is why you FAIL at SCALE 2011 and This is why you fail: The avoidable mistakes open source projects STILL make at OSCON 2015
includes some advice that large successful projects like Linux, Qt, and GTK do not heed
- A blog series by François Marier
Interacting with distributions
Ubuntu's Upstream Guide
How to be a good upstream, a FOSDEM 2010 talk by Petteri Räty of Gentoo
"Distribution-friendly projects" by Diego Pettenò - part 1, part 2, part 3
Why not bundle dependencies by Sebastian Pipping and others
How to be a good upstream for games by Debian/Fedora/etc games teams
The java packaging nightmare... by Vincent Fourmond
The real problem with Java in Linux distros by Thierry Carrez (LWN comments)
Managing a community
Free Software Project Management HOWTO by Benjamin Mako Hill
The cost of going it alone by Dave Neary (LWN comments)
Open Source Community, Simplified by Max Kanat-Alexander
How to spread the word about your code by Peter Cooper and Robert Nyman
Considerations on a non-profit home for your project by Bradley M. Kuhn
Spread the word: Marketing your FOSS project by VM Brasseur
The open source way by Red Hat
Legal and philosophical
Managing Copyright Information within a Free Software Project by the Software Freedom Law Center (LWN comments)
Community Distribution Patent Policy FAQ by the Software Freedom Law Center with input from Stefano Zacchiroli (LWN comments)
It isn't open source if it doesn't pass "The patch test" by Andy Oliver
Don't call it "open source" unless you mean it by Christian Heilmann (LWN comments)
Choosing a license by Dave Neary
Source required for art licensed under the GPL discussion started by Guus Sliepen
Missing source code for non-software works in free GNU/Linux distributions by Michał Masłowski
UpstreamGuide (last modified 2025-10-24 00:59:12)
- Changes made after 24 July 2025 00:00 UTC are available under Creative Commons Attribution-ShareAlike 4.0 International unless otherwise noted.
- Debian privacy policy, Wiki team, bugs and config.
- Powered by MoinMoin and Python, with hosting provided by Metropolitan Area Network Darmstadt.
