--- title: "How to Compile Software from Source on Ubuntu 24.04" description: "Install build tools, download and verify a source tarball, then configure, compile and install it under /usr/local on Ubuntu 24.04, with CMake and Meson too." category: "Operating Systems" language: en source: https://cubepath.com/docs/operating-systems/compiling-software-from-source-code updated: 2026-09-25 --- # How to Compile Software from Source on Ubuntu 24.04 Most software on Ubuntu should come from the package manager, but sometimes you need a newer release, a compile-time option the distribution disabled, or a tool that is not packaged at all. In that case you build it from source. In this tutorial you will install the toolchain on Ubuntu 24.04, download and verify a real source release (GNU nano), build it with the classic `configure`, `make`, `make install` workflow, install it under `/usr/local` without touching system packages, and learn the equivalent commands for projects that use CMake or Meson. ## Prerequisites To follow this guide you need: - A server running Ubuntu 24.04 LTS, for example a CubePath VPS. - A non-root user with `sudo` privileges. - About 1 GB of free disk space for build tools and sources. Large projects (compilers, browsers, databases) need several GB and more RAM. ## Step 1 - Installing the build toolchain The `build-essential` metapackage pulls in the GCC and G++ compilers, `make`, and the C library headers. Add `pkg-config`, which build scripts use to locate libraries, and the tools needed to download and verify sources: ```bash sudo apt update sudo apt install build-essential pkg-config curl gnupg xz-utils ``` Confirm the compiler and `make` are available: ```bash gcc --version make --version ``` ```output gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0 ... GNU Make 4.3 ``` ## Step 2 - Installing the library dependencies Every project lists its build dependencies in a `README`, `INSTALL` or `BUILDING` file. On Ubuntu, libraries you link against are split into a runtime package (`libncursesw6`) and a development package ending in `-dev` (`libncurses-dev`) that contains the headers. You need the `-dev` packages to compile. GNU nano needs the ncurses headers, plus `libmagic-dev` for syntax detection by file type: ```bash sudo apt install libncurses-dev libmagic-dev ``` ### Using apt build-dep for packaged software When you are building a newer version of something Ubuntu already packages, you can let apt install the exact build dependencies of the packaged version, which are usually close to what the new release needs. This requires source repositories. On Ubuntu 24.04 they are defined in `/etc/apt/sources.list.d/ubuntu.sources`: ```bash sudo nano /etc/apt/sources.list.d/ubuntu.sources ``` In each block, change the `Types:` line so it includes `deb-src`: ```text Types: deb deb-src ``` Then refresh the package index and install the build dependencies: ```bash sudo apt update sudo apt build-dep nano ``` ### Finding which package provides a missing file When `configure` complains about a missing header such as `zlib.h`, `apt-file` tells you which package ships it: ```bash sudo apt install apt-file sudo apt-file update apt-file search include/zlib.h ``` ```output zlib1g-dev: /usr/include/zlib.h ``` ## Step 3 - Downloading and verifying the source Keep sources in a directory you own rather than building as root. Create one and move into it: ```bash mkdir -p ~/src cd ~/src ``` Check `https://ftp.gnu.org/gnu/nano/` for the latest release and set the version in a variable so the following commands stay the same. This guide uses 8.3: ```bash VERSION=8.3 curl -fLO "https://ftp.gnu.org/gnu/nano/nano-${VERSION}.tar.xz" curl -fLO "https://ftp.gnu.org/gnu/nano/nano-${VERSION}.tar.xz.sig" ``` Before building anything, verify that the tarball was signed by the project's maintainers. GNU publishes a keyring with its maintainers' public keys: ```bash curl -fLO https://ftp.gnu.org/gnu/gnu-keyring.gpg gpg --verify --keyring ./gnu-keyring.gpg "nano-${VERSION}.tar.xz.sig" "nano-${VERSION}.tar.xz" ``` Look for `Good signature` in the output. A warning that the key is not certified with a trusted signature is expected, because you have not personally signed the maintainer's key: ```output gpg: Signature made ... gpg: Good signature from "Benno Schulenberg " [unknown] gpg: WARNING: This key is not certified with a trusted signature! ``` If you see `BAD signature`, delete the files and do not build them. > Note: Not every project signs its releases. When a project only publishes a SHA-256 checksum, compare it with `sha256sum file.tar.gz`. Downloading from a project's Git repository over HTTPS and checking out a signed tag (`git tag -v `) is another option. Extract the archive and enter the source directory: ```bash tar -xf "nano-${VERSION}.tar.xz" cd "nano-${VERSION}" ``` ## Step 4 - Configuring the build Projects that use GNU Autotools ship a `configure` script. It checks your system for compilers and libraries and writes the Makefiles. The most important option is `--prefix`, the directory the software will be installed into. The default for source builds is `/usr/local`, which keeps your files separate from those managed by apt (which live under `/usr`). List the project-specific options first, so you know which features you can enable or disable: ```bash ./configure --help | less ``` Run `configure` with the prefix: ```bash ./configure --prefix=/usr/local ``` If a dependency is missing, `configure` stops with an error that names it, for example: ```output configure: error: *** No curses library found ``` Install the matching `-dev` package (Step 2) and run `./configure` again. A successful run ends by creating the Makefiles and a `config.status` file, with no `error:` lines. ## Step 5 - Compiling Run `make` to compile. The `-j` flag runs several compile jobs in parallel; `nproc` returns the number of CPU cores: ```bash make -j"$(nproc)" ``` On a small server this takes under a minute for nano. When it finishes without `Error` lines, the binary is in the `src/` directory. Test it before installing: ```bash ./src/nano --version ``` ```output GNU nano, version 8.3 ``` Many projects also provide a test suite. When one exists, run it at this point with `make check` (Autotools) or the equivalent documented by the project. ## Step 6 - Installing under /usr/local Only the installation step needs root, because it writes to `/usr/local`: ```bash sudo make install ``` On Ubuntu, `/usr/local/bin` comes before `/usr/bin` in `PATH`, so your shell will now find the compiled version first. Clear the shell's command cache and check which binary runs: ```bash hash -r command -v nano nano --version ``` ```output /usr/local/bin/nano GNU nano, version 8.3 ``` The version packaged by Ubuntu is still installed in `/usr/bin/nano`. apt keeps updating that copy and never touches the files under `/usr/local`. If the project installs shared libraries into `/usr/local/lib`, refresh the dynamic linker cache so programs can find them: ```bash sudo ldconfig ``` ### Installing to a self-contained prefix instead For larger applications, installing each version into its own directory makes upgrades and removal trivial: ```bash ./configure --prefix=/opt/nano-${VERSION} make -j"$(nproc)" sudo make install ``` The binaries then live in `/opt/nano-8.3/bin`. Add that directory to `PATH` or create a symbolic link, for example `sudo ln -s /opt/nano-8.3/bin/nano /usr/local/bin/nano`. Removing the version later is a matter of deleting the directory and the link. ## Step 7 - Uninstalling a source build apt does not know about software you installed with `make install`, so it cannot remove it. Keep the source directory: Autotools projects provide an `uninstall` target that removes exactly the files `make install` created: ```bash cd ~/src/nano-8.3 sudo make uninstall ``` Check that the system version is used again: ```bash hash -r command -v nano ``` ```output /usr/bin/nano ``` ## Building projects that use CMake or Meson Many modern projects do not ship a `configure` script. If the source tree contains a `CMakeLists.txt`, it uses CMake; if it contains `meson.build`, it uses Meson. Install both tools with: ```bash sudo apt install cmake meson ninja-build ``` ### CMake CMake builds in a separate directory, which keeps the source tree clean. From the project's top-level directory, configure, build and install: ```bash cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local cmake --build build -j"$(nproc)" sudo cmake --install build ``` List the project's options with `cmake -S . -B build -LH`. CMake has no `uninstall` target by default, but it records every installed file in `build/install_manifest.txt`, which you can use to remove them: ```bash xargs -d '\n' sudo rm -f < build/install_manifest.txt ``` ### Meson Meson uses Ninja as its backend and also builds in a separate directory: ```bash meson setup build --prefix=/usr/local --buildtype=release meson compile -C build sudo meson install -C build ``` Show the available options with `meson configure build`. To remove the installed files later, run `sudo ninja -C build uninstall`. ## Troubleshooting **`configure: error: ... not found` or `Package 'foo' was not found in the pkg-config search path`**: a development package is missing. Search for the header or `.pc` file with `apt-file search foo.pc` and install the `-dev` package that provides it. **`fatal error: something.h: No such file or directory` during `make`**: same cause as above, detected later. Install the `-dev` package, then run `./configure` again before `make`, because `configure` caches its results. **`error while loading shared libraries: libfoo.so.1: cannot open shared object file`**: the library was installed under `/usr/local/lib` but the linker cache was not refreshed. Run `sudo ldconfig`. **The build is killed with no clear error**: on servers with little RAM, parallel compilation of large C++ projects can exhaust memory and trigger the OOM killer. Check with `sudo dmesg | grep -i oom`, then build with fewer jobs (`make -j2`) or add swap. **The old version still runs after installing**: your shell cached the old path. Run `hash -r` or open a new session. ## Conclusion You installed the build toolchain on Ubuntu 24.04, verified a signed source release, compiled it, installed it under `/usr/local` alongside the packaged version, and removed it cleanly. The same pattern (install `-dev` dependencies, configure with a prefix, build as a regular user, install with `sudo`) applies to Autotools, CMake and Meson projects alike. As next steps, you can: - Subscribe to the project's release announcements, since source builds do not receive security updates through `apt upgrade`. - Keep each build in its own `/opt/-` prefix when you need several versions side by side. - Package your build as a `.deb` if you need to deploy it to many servers.