Back to Blog

Build Debian packages for Ubuntu: control files, scripts and linting

Complete tutorial on dpkg/deb in Ubuntu. Learn debian/control, postinst/prerm, dependencies, lintian checks.

Build Debian packages for Ubuntu: control files, scripts and linting

Build Debian Packages for Ubuntu: Control Files, Scripts, and Linting

Introduction

Debian packages (files with the .deb extension) are essential components of the Debian and Ubuntu ecosystem, allowing developers to distribute software easily. Understanding how to build these packages is crucial for developers, system administrators, and anyone involved in software deployment. Packaging software into Debian format not only simplifies installation and uninstallation but also ensures that dependencies are managed correctly.

In this tutorial, we will explore the process of creating Debian packages for Ubuntu, focusing on key elements such as the debian/control file, the installation scripts (postinst and prerm), and how to validate our packages using linting tools. Mastering these concepts is vital for producing high-quality packages that adhere to the conventions of the Debian packaging system, ensuring that they function correctly in various environments.

Prerequisites

  • Ubuntu Version: This tutorial is applicable to Ubuntu 20.04 and later.

  • Required Packages: Install the necessary tools with the following command:

    sudo apt update && sudo apt install build-essential devscripts dh-make lintian
    
  • Permissions: You need sudo privileges to install packages and create directories in the filesystem.

  • Risks: Incorrectly configured packages can lead to broken installations, so always test in a safe environment before deploying to production.

Core Concepts

Understanding the core concepts of Debian packaging is essential for creating functional packages:

  • Control Files: These are configuration files that provide metadata about the package, such as its name, version, maintainer, and dependencies.
  • Installation Scripts: Scripts like postinst (post-installation) and prerm (pre-removal) allow you to execute commands during package installation and removal.
  • Dependencies: Specifying dependencies ensures that your package has the required libraries or packages to function correctly.
  • Linting: Using tools like lintian, you can check your package for common issues and adhere to Debian policy standards.

Syntax/Commands

Command Description
dpkg-deb Tool to build and manipulate Debian packages
debuild A wrapper around dpkg-buildpackage for building packages
lintian A tool to analyze Debian packages for policy compliance

Practical Examples

Here are practical examples to help illustrate the process of building Debian packages.

1. Create the Directory Structure

mkdir mypackage-1.0
cd mypackage-1.0
mkdir -p debian

2. Create the Control File

echo "Source: mypackage
Section: utils
Priority: optional
Maintainer: Your Name <youremail@example.com>
Build-Depends: debhelper (>= 9)
Standards-Version: 4.5.0
Homepage: http://example.com

Package: mypackage
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: A brief description of my package
 Long description of my package." > debian/control

3. Create Installation Scripts

Post-installation Script (postinst):

echo "#!/bin/bash
set -e

echo 'Configuring mypackage...'
# Custom post-installation commands go here

exit 0" > debian/postinst
chmod +x debian/postinst

Pre-removal Script (prerm):

echo "#!/bin/bash
set -e

echo 'Removing mypackage...'
# Custom pre-removal commands go here

exit 0" > debian/prerm
chmod +x debian/prerm

4. Build the Package

debuild -us -uc

5. Install the Package

sudo dpkg -i ../mypackage_1.0-1_amd64.deb

6. Check for Dependencies

sudo apt-get install -f

7. Lint the Package

lintian ../mypackage_1.0-1_amd64.deb

8. Clean Up

debuild clean

Real-World Scenarios

Scenario 1: Deploying a Custom Utility

Suppose you have developed a custom network utility called netutil. You can package it using the steps outlined above, enabling you to distribute it easily across multiple Ubuntu systems.

Scenario 2: Managing Library Dependencies

When creating a library package, ensure you specify the necessary dependencies in your debian/control file. This prevents runtime errors by ensuring all required libraries are installed when your package is installed.

Scenario 3: Automating Deployments

Using a combination of shell scripts and the above packaging techniques, you can automate the deployment of your software in production environments, ensuring consistency and reducing manual errors.

Best Practices

  1. Versioning: Always follow semantic versioning for your packages to avoid conflicts.
  2. Use Lintian: Run lintian on your package to catch potential issues before distribution.
  3. Testing: Test your packages in a clean environment to ensure they install and uninstall cleanly.
  4. Control File Accuracy: Keep your debian/control file updated with accurate dependencies.
  5. Documentation: Include a README or changelog to inform users about your package.

Common Errors

Error Message Cause Fix
dpkg-deb: error: parsing file ‘debian/control’ Syntax error in control file Check for missing or incorrect entries.
dpkg: dependency problems prevent configuration Missing dependencies Install the required dependencies.
postinst script returned error exit status 1 Error in the post-installation script Debug the script for any commands that fail.
package architecture does not match Incorrect architecture specified Set the correct architecture in control.

Related Commands

Command Description Differences
dpkg Low-level package manager Works with .deb files directly
apt-get High-level package management Handles dependencies automatically
dpkg-buildpackage Builds Debian packages Similar to debuild, with more options

Automation Script

Here is a complete bash script for automating the Debian package creation process.

#!/bin/bash

# Variables
PACKAGE_NAME="mypackage"
VERSION="1.0"
MAINTAINER="Your Name <youremail@example.com>"
ARCHITECTURE="any"

# Create directory structure
mkdir -p ${PACKAGE_NAME}-${VERSION}/debian
cd ${PACKAGE_NAME}-${VERSION}

# Create control file
cat <<EOL > debian/control
Source: ${PACKAGE_NAME}
Section: utils
Priority: optional
Maintainer: ${MAINTAINER}
Build-Depends: debhelper (>= 9)
Standards-Version: 4.5.0
Homepage: http://example.com

Package: ${PACKAGE_NAME}
Architecture: ${ARCHITECTURE}
Depends: \${shlibs:Depends}, \${misc:Depends}
Description: A brief description of ${PACKAGE_NAME}
 Long description of ${PACKAGE_NAME}.
EOL

# Create postinst script
cat <<EOL > debian/postinst
#!/bin/bash
set -e
echo 'Configuring ${PACKAGE_NAME}...'
exit 0
EOL
chmod +x debian/postinst

# Create prerm script
cat <<EOL > debian/prerm
#!/bin/bash
set -e
echo 'Removing ${PACKAGE_NAME}...'
exit 0
EOL
chmod +x debian/prerm

# Build the package
debuild -us -uc

# Clean up
debuild clean

Conclusion

In this tutorial, we have explored how to build Debian packages for Ubuntu, covering essential components such as control files, installation scripts, and linting. By mastering these skills, you can effectively manage software distribution and ensure your packages meet quality standards.

As next steps, consider diving deeper into advanced packaging techniques, including multi-architecture packages and automated builds using CI/CD pipelines.

References

🚀 With this knowledge, you're ready to tackle Debian packaging on Ubuntu effectively!