The Advanced Package Tool (APT) makes installing software incredibly simple on Debian-based Linux distributions. With just a single apt install
command, entire dependency chains can be resolved and installed automatically. This removes the headache of managing software dependencies manually.
In this comprehensive guide, we will cover everything you need to know about working with apt to install dependencies on Ubuntu, Debian, Linux Mint, Pop!_OS and other apt-based systems.
APT Dependency Resolution Explained
To understand apt‘s dependency handling, we first need to briefly understand Linux package management.
The Linux ecosystem is made up of tens of thousands of interdependent software packages and libraries. Each package maintainer defines meta-data that lists the dependencies their package needs.
When you go to install a package with apt, here is simplified view of what happens:
- The apt client contacts the package repository and retrieves the latest package meta-data
- apt examines the dependencies of the package you want to install
- It recursively expands this tree of dependencies, resolving version numbers
- The required packages are downloaded from the repos and installed
The key thing that makes apt so robust is that it will resolve all layers of dependencies automatically. This prevents breakages from missing libraries or incompatible versions.
Why is APT Better Than Other Package Managers?
There are a few reasons why APT has an advantage over package managers like yum or pacman:
Sanity Checking: apt will sanity check all dependencies before installing anything. This prevents half-installed or broken packages. If a dependency can‘t be resolved, apt will error out rather than breaking the system.
Version Handling: apt follows a robust algorithm for sorting package versions and dependency chains. This prevents incompatible package versions from being installed.
Security: Packages installed through apt come strictly from trusted repositories. Installs don‘t rely on trusting individual maintainers or arbitrary code from the internet. All packages are cryptographically verified.
Prevent Breakage: apt will preferentially keep working packages installed rather than upgrading packages that would break dependencies. This prevents sudden software breakage during upgrades.
Of course advanced users can override apt‘s algorithms if needed. But in most cases, just using the default apt commands will lead to a very stable system.
Next let‘s walk through some common examples of installing popular software stacks and their dependencies with APT.
Installing a LAMP Stack and Dependencies
The LAMP stack (Linux, Apache, MySQL, and PHP) is very common in web development. There can be complex dependency chains between each component, but apt handles this seamlessly:
sudo apt update
sudo apt install apache2 mysql-server php libapache2-mod-php php-mysql
After just two commands, apt will have installed Apache, MySQL server, PHP, connected MySQL support in PHP, and configured Apache to handle .php files.
All the dependencies like PHP modules, database connectors, log handlers, and config files are handled automatically in the background.
Here is a more complete LAMP stack install that adds on some extras like phpMyAdmin:
sudo apt install apache2 mariadb-server php php-mysql php-gd \
php-json php-mbstring phpmyadmin php-zip php-curl
With over a dozen interconnected packages, this would be tedious to install manually. Apt turn this into a one-liner.
Installing Python PIP Dependencies
Python has its own ecosystem of PyPI packages separate from the OS-level packages. But apt can still assist in setting up language runtimes and package managers:
sudo apt install build-essential python3-dev python3-pip python3-setuptools python3-virtualenv
This installs gcc and python compiler tools, the python3 runtime, pip package manager, virtual environment support, and other core dependencies to start coding in Python on Ubuntu.
Once those are setup, native python packages can be installed with pip
:
pip install flask django numpy scipy
So combining apt for lower level dependencies, with Python‘s own manager for language libraries, gives a robust dependency environment for Python development.
Installing Node.js npm Dependencies
As another example, JavaScript development relies heavily on the npm ecosystem. Setting up the initial Node.js runtime is best done through apt:
sudo apt install nodejs npm
But compiling native Node modules requires additional development tools:
sudo apt install build-essential
Now that Node.js and compilation tools are setup, front-end javascript libraries can be installed with npm
:
npm install react vue underscore axios
Just like Python, combining apt and Node‘s package manager creates a complete JavaScript dependency environment.
How APT Differs From YUM, Pacman, Portage, and Other Package Managers
APT is not the only game in town. Other common package managers like yum (Red Hat), pacman (Arch), and emerge (Gentoo) take different approaches.
Yum operates very similarly to apt with automatic dependency resolution. The main difference is yum relies on RPM packages whereas apt uses Deb packages. These are incompatible, so software needs to be packaged specifically for each format.
Pacman and Portage do not resolve dependencies automatically. The user must manually install all dependencies listed for a package before installing it. This allows more control but requires more effort.
Below is a comparison of key differences in how major package managers handle dependencies:
Package Manager | Auto-Resolves Deps | Checks for Breakage | Package Format | Common Distros |
---|---|---|---|---|
apt | Yes | Yes | deb | Debian, Ubuntu, Mint |
yum | Yes | Yes | rpm | RHEL, CentOS, Fedora |
pacman | No | No | tar.zst | Arch, Manjaro |
emerge | No | No | ebuild | Gentoo |
In general apt and yum offer the most convenience, pacman offers flexibility, while Portage offers customizability.
Best Practices for Managing APT Dependencies
While apt handles most dependency details automatically, there are still a few best practices worth following:
Always Update Package Lists Before Installing
Before installing new packages, be sure to run:
sudo apt update
This fetches the latest package versions and dependencies. Installing packages without updating can lead to outdated or conflicting libraries.
Check Package Signatures Before Installing
When adding 3rd party repositories or PPAs, verify package signatures to avoid compromised software:
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys KEY-GOES-HERE
This downloads and verifies public keys before installing unpublished packages.
Prioritize Version Control Over Bleeding Edge
When possible, avoid using many PPAs or mixing release channels (like stable, testing, unstable). This can lead to library incompatibilities from different Debian releases.
Favor system stability over having the very latest software versions. For development, use virtual environments instead when possible.
Perform Test Runs First
Before running an apt command like apt upgrade
across the whole system, append -s
first, to simulate the run:
sudo apt -s upgrade
Review the output for any major changes, before commiting them by rerunning without -s
.
Clean Cache to Free Space
The apt cache in /var/cache/apt
can grow large. To free space periodically run:
sudo apt clean
And to remove unneeded downloaded packages:
sudo apt autoclean
This maintenance keeps your system lean.
By following best practices like these, even complex multi-layered dependency trees can be easily managed through apt.
Using Apt Preferences to Control Versions
APT has a preferences system that can override default dependency versions when needed. By default apt attempts to install the latest available version of any package.
But occasionally you may need to roll back a package version, install an older version, or limit version upgrades going forward. This is done by setting apt preferences through config files.
Common reasons to set explicit apt preferences include:
- Downgrading a buggy package to a previous release
- Sticking with an LTS kernel version
- Freezing all packages at a specific Debian release
As an example, here is how to limit PostgreSQL to v11, by creating a preferences file:
sudo vim /etc/apt/preferences.d/postgres
With the contents:
Package: postgresql*
Pin: version 11*
Pin-Priority: 1001
This will force apt to prefer installing a maximum of PostgreSQL 11.x, even once higher versions get released.
The pin-priority sets how strict the rule is against upgrades. 1001 means the version lock can only be overridden manually by deleting this file.
Now when running apt upgrade
, PostgreSQL will stick to the v11 branch.
There are many other apt preference options available – forcing certain packages to only install from certain releases like stable/testing/unstable, source preferences, and architecture preferences.
Handling Leftover Dependencies After Removing Packages
A related concept to installing dependencies is removing packages that are no longer needed.
Sometimes removing a package leaves behind now-unneeded libraries that were installed. This is known as having leftover dependencies on the system. Too many unused dependencies leads to bloated storage usage and potential conflicts.
Here are couple tools that can identify and remove these unnecessary packages:
deborphan – Finding Leftover Libraries
deborphan is a tool that scans all installed packages and detects libraries that were installed only to meet a dependency that no longer exists:
sudo apt install deborphan
deborphan
It will list package names that are now considered orphaned. You can safely remove the suggested packages.
debfoster – Recursively Removing Dependencies
debfoster recursively removes libraries that are no longer needed. Once you remove a package with apt purge
, running:
sudo debfoster
Will display reverse dependency trees for all orphaned packages and prompt to remove. This allows fully purging unused packages.
Troubleshooting Unsatisfied Dependencies
The most common apt issue users run into is failing to install a package due to unsatisfied dependencies.
This happens when the package lists a dependency that is unavailable or conflicts with other installed software.
Here is an ordered checklist for resolving unsatisfied dependency errors while installing packages:
1. Update Package Lists
Start by running apt update
to fetch the latest package metadata from repositories. This also refreshes what versions of dependencies are actually available.
2. Verify 3rd Party Repos
If enabling any 3rd party PPAs or non-standard repos, check that they are still maintained and hosting the packages you expect. Sometimes repos get abandoned.
3. Search for Conflicts
Use apt policy
to display installed and available versions of a contested package. Compare versions of libraries the software needs against versions already installed system-wide.
4. Identify Local Modifications
Libraries may conflict due to local modifications rather than true version issues. You may need to rebuild, reconfigure, or even reset some existing components for clean dependency graphs. Check for things you have compiled or customized manually.
5. Consider Downgrading
If a key package needs an older dependency version than is available, check if manually downgrading the installed package can resolve rather than upgrading.
6. Check Bug Reports
Search Debian and Ubuntu bug trackers to see if the unsatisfied dependency is a known issue and if any workarounds are available.
7. Consider Rebuilding Debs
As a last resort, download the source code of a project and attempt to rebuild .deb packages from scratch using dpkg-buildpackage
. This can let you specify customized dependencies.
With a combination of these strategies, most unsatisfied dependency errors can be addressed to allow installing the target packages.
Conclusion
The Advanced Packaging Tool brings professional-grade software management that streamlines system administration. We covered how apt installs dependencies automatically, compared to other major package managers, looked at best practices, and also handled some common issues like conflicts.
With robust algorithms for dependency resolution, package sanity checking, authentication, and repositories containing tens of thousands of linux programs, apt makes running Debian-based systems a pleasure. It took decades of packaging work to build up the linux ecosystem we rely on today.
Hopefully this guide gives you confidence in managing software with apt. Let us know in the comments about your favorite apt packages or any issues you‘ve run into!