How to Build Software from Source on Linux
Build Linux software from source using configure, make, and make install — with dependency tips, CMake and Meson coverage, and clean-install strategies.
Before you start
- ▸sudo or root access to install packages and files system-wide
- ▸Basic terminal familiarity: navigating directories, reading error output
- ▸Sufficient disk space (source + build artifacts can exceed 1 GB for large projects)
- ▸Internet access to download source tarballs and missing dependencies
Binary packages are convenient, but they are built for the lowest common denominator. Building from source lets you target your specific CPU, enable or disable features, and run software versions that your distribution simply does not ship. The workflow is almost always the same: fetch the source, satisfy dependencies, configure, compile, and install. The details are where most people trip up.
Before You Start: Required Build Tools
You need a C/C++ toolchain, make, and supporting utilities. Most projects also need pkg-config to locate libraries.
Debian / Ubuntu
sudo apt update
sudo apt install build-essential pkg-config git wget
Fedora / RHEL / Rocky
sudo dnf groupinstall "Development Tools"
sudo dnf install pkg-config git wget
Arch Linux
sudo pacman -S base-devel git wget
Step 1: Fetch the Source
Always prefer a tagged release tarball over a random commit. Tarballs from a project's releases page are tested and do not require autotools to regenerate the build system.
wget https://example.com/project/project-2.4.1.tar.gz
tar -xzf project-2.4.1.tar.gz
cd project-2.4.1
If you need the bleeding edge or want to contribute, clone via Git:
git clone --depth=1 --branch v2.4.1 https://github.com/example/project.git
cd project
When cloning a repository that ships configure.ac but no pre-generated configure script, you must run the bootstrap step first:
./autogen.sh
# or, if no autogen.sh exists:
autoreconf -fiv
Step 2: Read the Build Instructions
Before running anything, read README, INSTALL, or docs/building.md. Projects increasingly switch from Autotools to CMake or Meson. The configure commands differ, and attempting an Autotools workflow on a Meson project will fail immediately.
- Autotools: has a
configurescript at the root - CMake: has a
CMakeLists.txtat the root - Meson: has a
meson.buildat the root
This guide covers all three, starting with Autotools since it remains the most common in older and C-focused projects.
Step 3: Resolve Dependencies
Run ./configure (or the equivalent) once. It will fail loudly on any missing library and tell you exactly what is missing. Do not ignore these messages. Search your package manager for the development package, which includes headers.
Finding development packages
Debian / Ubuntu
apt search libfoo-dev
sudo apt install libfoo-dev
Fedora / RHEL / Rocky
dnf search libfoo-devel
sudo dnf install libfoo-devel
Arch Linux
pacman -Ss libfoo
sudo pacman -S libfoo
Repeat until ./configure finishes without errors. The last line of successful Autotools configure output looks like:
config.status: creating Makefile
Step 4: Configure the Build
The configure step is where you set the install prefix and toggle features. The single most important flag is --prefix, which controls where files land. Using /usr/local keeps your hand-built software separate from the system package manager.
Autotools
./configure --prefix=/usr/local \
--enable-optimizations \
--disable-debug
Run ./configure --help to see every available flag for that project.
CMake (out-of-tree build — always recommended)
cmake -B build \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr/local
Meson
meson setup build \
--prefix=/usr/local \
--buildtype=release
Meson requires its own package. Install it with pip install meson ninja or from your distro's repositories if you need a recent version.
Step 5: Compile
Use all available CPU cores. nproc returns the logical core count on every major distro.
Autotools / plain Makefile
make -j$(nproc)
CMake
cmake --build build -j$(nproc)
Meson / Ninja
ninja -C build -j$(nproc)
A successful compile ends with a linker step and no error lines. Warnings are usually not fatal. Errors reference a specific source file and line number — use that to search the project's issue tracker before assuming something is wrong with your system.
Step 6: Install — and Stay Tidy
The naive approach is sudo make install. It works, but it scatters files across /usr/local with no record of what was installed, making clean removal painful later. Use checkinstall or DESTDIR staging instead.
Option A: checkinstall (creates a native package)
sudo apt install checkinstall # Debian/Ubuntu
sudo checkinstall # replaces 'make install'
checkinstall runs make install internally, captures every file it writes, and wraps the result in a .deb (or .rpm on RPM systems). You can then uninstall cleanly with sudo apt remove project. This is the recommended method on Debian/Ubuntu systems. On Fedora, it is less maintained; use DESTDIR staging instead.
Option B: DESTDIR staging (universal)
make install DESTDIR=/tmp/project-root
ls /tmp/project-root/usr/local/bin # verify layout
You can then use rsync to push the staged tree into place, or hand it to fpm to create a proper package. This works with CMake (cmake --install build --prefix /tmp/project-root) and Meson (DESTDIR=/tmp/project-root ninja -C build install) too.
Option C: Plain install (acceptable for isolated tools)
sudo make install
If you are installing a single binary to a custom prefix like $HOME/.local or /opt/project, plain install is fine because the prefix is already isolated.
Step 7: Verify the Installation
Confirm the binary is reachable and reports the expected version:
which project
project --version
If which returns nothing, your prefix's bin directory is not in PATH. Add it for your shell:
echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
If the binary links against shared libraries you built, also update the linker cache:
echo "/usr/local/lib" | sudo tee /etc/ld.so.conf.d/local.conf
sudo ldconfig
Troubleshooting
configure: error: C compiler cannot create executables
Your toolchain installation is incomplete. Verify with gcc --version and reinstall the build-essential / Development Tools group.
cannot find -lfoo during linking
A required library is present but the linker cannot find it. Check that its -dev/-devel package is installed, then run sudo ldconfig. If it is in a non-standard location, export LDFLAGS="-L/path/to/lib" before running configure.
make: Nothing to be done for 'all'
Object files from a previous build are still present. Run make clean or make distclean (Autotools), rm -rf build (CMake/Meson), then configure and compile again.
Installed binary crashes with version mismatch
The running binary found a different shared library version than the one it was built against. Run ldd $(which project) to see which libraries are resolved and compare against what you expected. DESTDIR staging makes this easier to audit before system-wide installation.
Frequently asked questions
- Why use --prefix=/usr/local instead of /usr?
- /usr is owned by the package manager on most distros. Installing to /usr/local keeps hand-built software in a separate tree, preventing conflicts and making it easier to remove later.
- How do I uninstall software built from source?
- If you used checkinstall, uninstall via your package manager. If you used plain make install and still have the source tree, run sudo make uninstall. Otherwise use DESTDIR staging next time and track files with a native package.
- Is it safe to run make with -j$(nproc) on every project?
- Almost always yes. Occasionally a project has broken Makefile dependencies that only manifest during parallel builds. If you get strange errors, try make -j1 to reproduce them serially before filing a bug.
- Can I build as a regular user without sudo?
- Yes. Set --prefix=$HOME/.local and the entire build and install happens without elevated privileges. Make sure $HOME/.local/bin is in your PATH.
- What is the difference between make clean and make distclean?
- make clean removes compiled object files and binaries. make distclean also removes the generated Makefile and configure output, returning the tree to roughly its tarball state. Use distclean when you want to reconfigure with different options.
Related guides
AI and Artificial-Life Tools on Linux
Set up open-source AI/ML and artificial-life toolkits on Linux: PyTorch, JAX, DEAP, Avida, NetLogo, and RL environments with GPU driver guidance.
Assembly Language on Linux: A Starter Guide
Write x86-64 assembly on Linux from scratch: install NASM and GAS, learn syscalls, assemble and link a working program, then inspect and debug it.
How to Benchmark Disk Performance with fio
Learn to benchmark Linux disk performance with fio: writing job files, testing latency and throughput, and interpreting IOPS and percentile output correctly.
The Linux Boot Process Explained
Trace the full Linux boot sequence from UEFI firmware through GRUB2, the kernel, initramfs, and systemd to your login prompt — with diagnostics at each stage.