How to Compile Code in Linux

How to Compile Code in Linux Compiling code in Linux is a foundational skill for developers, system administrators, and open-source contributors. Unlike Windows or macOS, where many applications come as pre-built binaries, Linux often requires users to compile software from source code to ensure compatibility, optimize performance, or access the latest features not yet packaged by distribution mai

Oct 30, 2025 - 11:56
Oct 30, 2025 - 11:56
 1

How to Compile Code in Linux

Compiling code in Linux is a foundational skill for developers, system administrators, and open-source contributors. Unlike Windows or macOS, where many applications come as pre-built binaries, Linux often requires users to compile software from source code to ensure compatibility, optimize performance, or access the latest features not yet packaged by distribution maintainers. This process transforms human-readable source code—written in languages like C, C++, or Rust—into machine-executable binaries that run directly on the operating system.

Understanding how to compile code in Linux empowers you to take full control of your software environment. Whether you're installing a niche utility, customizing a kernel module, or contributing to open-source projects, the ability to compile from source is indispensable. It also deepens your understanding of how software is built, linked, and executed—skills that enhance debugging, optimization, and security analysis.

This guide provides a comprehensive, step-by-step walkthrough of compiling code in Linux, covering everything from installing essential tools to troubleshooting common errors. You’ll learn best practices, explore real-world examples, and gain access to essential resources that will make you proficient in source compilation—no matter your experience level.

Step-by-Step Guide

Prerequisites: Setting Up Your Linux Environment

Before you begin compiling code, ensure your Linux system is properly configured. Most modern Linux distributions come with package managers that simplify tool installation. The first step is installing the essential build tools.

On Debian-based systems (Ubuntu, Linux Mint, etc.), run:

sudo apt update && sudo apt install build-essential

On Red Hat-based systems (Fedora, CentOS, RHEL), use:

sudo dnf groupinstall "Development Tools"

Or on older RHEL/CentOS versions:

sudo yum groupinstall "Development Tools"

On Arch Linux and derivatives:

sudo pacman -S base-devel

The build-essential package (or equivalent) includes:

  • gcc – The GNU Compiler Collection for C and C++
  • g++ – The C++ compiler
  • make – A build automation tool
  • libc6-dev – C library headers
  • binutils – Essential binary utilities like ld (linker) and as (assembler)

Verify installation by checking the versions:

gcc --version

g++ --version

make --version

If these commands return version numbers, your system is ready. If not, revisit the installation steps or consult your distribution’s documentation.

Obtaining Source Code

Source code is typically distributed as compressed archives (.tar.gz, .tar.bz2, .zip) or via version control systems like Git. The most common sources are:

  • Official project websites (e.g., nginx.org, apache.org)
  • GitHub, GitLab, or Bitbucket repositories
  • Package mirrors or FTP servers

For this guide, we’ll use the htop process viewer as a practical example. Download the latest source from its official GitHub releases page:

wget https://github.com/hishamhm/htop/archive/refs/tags/3.3.0.tar.gz

Extract the archive using:

tar -xzf 3.3.0.tar.gz

This creates a directory named htop-3.3.0. Navigate into it:

cd htop-3.3.0

Always inspect the contents of the extracted directory. Look for files like README, INSTALL, or configure. These files contain critical instructions for building the software.

Running the Configuration Script

Most open-source software uses the GNU Autotools build system, which relies on a script called configure. This script detects your system’s environment—available libraries, compiler features, paths—and generates a customized Makefile.

Run the configuration script:

./configure

If the script runs successfully, you’ll see output listing detected components. If it fails, the error message will indicate a missing dependency. Common errors include:

  • configure: error: no acceptable C compiler found → gcc is not installed
  • configure: error: libncurses not found → Missing development library

To resolve missing dependencies, search for packages using your package manager. For example, on Ubuntu:

apt search ncurses-dev

Then install the development package:

sudo apt install libncurses-dev

After installing missing dependencies, rerun ./configure.

For advanced users, the configure script supports options to customize the build. Common flags include:

  • --prefix=/usr/local – Sets the installation directory (default is /usr/local)
  • --enable-debug – Enables debug symbols for troubleshooting
  • --disable-ipv6 – Disables optional features

Example with custom prefix:

./configure --prefix=/opt/htop

This installs htop into /opt/htop instead of the default location, useful for keeping custom builds isolated.

Building the Code with Make

Once configuration completes successfully, run the make command:

make

This step compiles the source code into object files and links them into a final executable. The process may take seconds or several minutes, depending on the project size and your system’s CPU and disk speed.

During compilation, you’ll see output showing which files are being processed. Each line typically begins with a compiler command like:

gcc -c -o htop.o htop.c

These lines indicate that the C compiler is translating source files (.c) into object files (.o). After all object files are compiled, the linker (ld) combines them into a single binary.

If errors occur during make, they are usually due to:

  • Missing header files (install -dev packages)
  • Incorrect compiler flags
  • Version incompatibilities between libraries and source code

Read the error message carefully. For example:

error: ‘struct termios’ has no member named ‘c_line’

This suggests a kernel or library version mismatch. Search the error message online or check the project’s issue tracker for known fixes.

Installing the Compiled Program

After successful compilation, the executable is created in the build directory but not yet installed system-wide. To install it, run:

sudo make install

This command copies the binary, configuration files, and documentation to the directories specified during configuration (e.g., /usr/local/bin, /usr/local/share).

Verify the installation:

which htop

Should return:

/usr/local/bin/htop

Test the program:

htop

If it launches successfully, you’ve compiled and installed software from source!

Uninstalling Compiled Software

Unlike package managers, make install does not automatically track installed files. To uninstall, navigate back to the source directory and run:

sudo make uninstall

However, this only works if the project’s Makefile includes an uninstall target—which not all do. If make uninstall fails, you’ll need to manually remove files. Check the Makefile for installation paths or use:

make -n install

This simulates the install process without executing it, showing you exactly which files will be copied. Then remove them manually:

sudo rm /usr/local/bin/htop

sudo rm -r /usr/local/share/man/man1/htop.1

For future installations, consider using tools like checkinstall to create a .deb or .rpm package, which can be cleanly removed later.

Best Practices

Use a Separate Build Directory

Many developers make the mistake of compiling directly in the source directory. This can lead to clutter and make it difficult to clean up or switch between build configurations.

Instead, create a dedicated build directory:

mkdir build && cd build

../configure

make

This approach, known as “out-of-source” building, keeps source files pristine and allows you to maintain multiple build configurations (debug, release, cross-compile) from the same codebase.

Always Read Documentation

Before compiling, read the README and INSTALL files. They often contain crucial information about dependencies, known issues, or build flags specific to your platform.

Some projects require non-standard steps—for example, generating the configure script from autogen.sh if you’re building from a Git clone instead of a release tarball.

Use Version Control for Source Code

If you frequently compile from source, especially for development or customization, keep the source code under version control (Git). This allows you to track changes, revert to stable versions, and apply patches easily.

Example:

git clone https://github.com/hishamhm/htop.git

cd htop

git checkout v3.3.0

Using tagged releases ensures reproducibility and stability.

Install Dependencies Before Compiling

Always install all required development libraries before running configure. Missing libraries are the most common cause of build failures.

On Debian/Ubuntu, use:

apt install libssl-dev libncurses-dev libz-dev

On Fedora:

dnf install openssl-devel ncurses-devel zlib-devel

Use package search tools to find the correct -dev or -devel package name if unsure.

Avoid Running make as Root

Never run make as root. Compilation is a read-and-write process that should occur in your user space. Only use sudo for the final make install step.

Running make as root increases security risks. Malicious or buggy Makefiles could alter system files during compilation.

Use Checkinstall for Package Management

Instead of make install, consider using checkinstall to create a native package (.deb, .rpm) during installation:

sudo checkinstall

This tool monitors files installed by make install and packages them into a format your package manager recognizes. This allows you to uninstall later using:

sudo dpkg -r htop

or

sudo rpm -e htop

Install checkinstall via your package manager:

sudo apt install checkinstall

Keep a Build Log

For complex projects or troubleshooting, redirect output to a log file:

./configure > configure.log 2>&1

make > make.log 2>&1

sudo make install > install.log 2>&1

This creates a record of every step, useful for diagnosing failures or replicating builds on other systems.

Test Before Deployment

After compiling and installing, test the software thoroughly. Run its built-in tests if available:

make test

or

make check

These commands execute unit or integration tests to verify functionality. Skipping them may lead to unstable software in production environments.

Tools and Resources

Essential Build Tools

  • gcc – GNU Compiler Collection for C, C++, Objective-C, Fortran, and more
  • g++ – C++ frontend for gcc
  • make – Automates compilation using Makefiles
  • cmake – Modern cross-platform build system (used by many newer projects)
  • ninja – Fast build system often used with CMake
  • autotools – Legacy but still widely used (autoconf, automake, libtool)
  • pkg-config – Helps locate library dependencies
  • checkinstall – Creates installable packages from source
  • strace – Debugs system calls during compilation
  • ldd – Lists shared library dependencies of binaries

Package Managers and Dependency Resolution

Each Linux distribution has its own package manager:

  • apt – Debian, Ubuntu, Linux Mint
  • dnf – Fedora, RHEL 8+
  • yum – RHEL 7 and older
  • pacman – Arch Linux
  • zypper – openSUSE

Always use your system’s package manager to install development libraries. For example:

apt search openssl-dev

Search for -dev (Debian) or -devel (RPM) packages, as these contain headers and static libraries needed for compilation.

Online Resources

  • Linux From Scratch (LFS) – https://www.linuxfromscratch.org – Teaches building a Linux system from source, including detailed compilation guides.
  • GNU Autotools Documentation – https://www.gnu.org/software/automake/manual/html_node/index.html – Official guide to configure scripts and Makefiles.
  • CMake Documentation – https://cmake.org/documentation – Modern alternative to autotools.
  • Stack Overflow – Search for “Linux compile [error message]” – Most compilation errors have been solved here.
  • GitHub Issues – Check the issue tracker of the project you’re compiling. Many build problems are already documented and fixed.

Compiler Flags and Optimization

Advanced users can optimize compilation using flags passed to gcc/g++:

  • -O2 – Optimizes for speed (recommended for production)
  • -O3 – Aggressive optimization (may increase binary size)
  • -g – Includes debug symbols for gdb
  • -Wall – Enables all common warnings
  • -Wextra – Enables additional warnings
  • -std=c11 – Enforces C11 standard

Example with optimization and warnings:

CFLAGS="-O2 -Wall -Wextra" ./configure

These flags can be passed to configure scripts that respect CFLAGS and CXXFLAGS environment variables.

Cross-Compilation Tools

If you’re building software for a different architecture (e.g., compiling ARM code on x86), use cross-compilers:

arm-linux-gnueabihf-gcc

Install cross-compilation toolchains via your package manager:

sudo apt install gcc-arm-linux-gnueabihf

Then configure with:

./configure --host=arm-linux-gnueabihf

Real Examples

Example 1: Compiling Nginx from Source

Nginx is often compiled from source to enable custom modules or optimize for specific hardware.

Step 1: Install dependencies

sudo apt update

sudo apt install build-essential libpcre3-dev libssl-dev zlib1g-dev

Step 2: Download source

wget https://nginx.org/download/nginx-1.26.0.tar.gz

tar -xzf nginx-1.26.0.tar.gz

cd nginx-1.26.0

Step 3: Configure with custom options

./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --with-http_ssl_module --with-http_v2_module --with-http_gzip_static_module

Step 4: Compile and install

make

sudo make install

Step 5: Create a systemd service

Create /etc/systemd/system/nginx.service:

[Unit]

Description=The NGINX HTTP and reverse proxy server

After=network.target

[Service]

Type=forking

PIDFile=/var/run/nginx.pid

ExecStartPre=/usr/sbin/nginx -t

ExecStart=/usr/sbin/nginx

ExecReload=/usr/sbin/nginx -s reload

ExecStop=/bin/kill -s QUIT $MAINPID

PrivateTmp=true

[Install]

WantedBy=multi-user.target

Enable and start:

sudo systemctl daemon-reload

sudo systemctl enable nginx

sudo systemctl start nginx

Example 2: Compiling a Custom Kernel Module

Kernel modules are compiled against the current kernel headers.

Step 1: Install kernel headers

sudo apt install linux-headers-$(uname -r)

Step 2: Create a simple module (hello.c)

include <linux/init.h>

include <linux/module.h>

include <linux/kernel.h>

static int __init hello_init(void)

{

printk(KERN_INFO "Hello, Linux Kernel!\n");

return 0;

}

static void __exit hello_exit(void)

{

printk(KERN_INFO "Goodbye, Linux Kernel!\n");

}

module_init(hello_init);

module_exit(hello_exit);

MODULE_LICENSE("GPL");

MODULE_DESCRIPTION("A simple hello module");

Step 3: Create Makefile

obj-m += hello.o

all:

make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:

make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Step 4: Compile

make

Step 5: Load the module

sudo insmod hello.ko

dmesg | tail

You should see “Hello, Linux Kernel!” in the kernel log.

Unload it with:

sudo rmmod hello

Example 3: Compiling Rust Code

Rust uses Cargo, its own build system. Install Rust:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Then create a new project:

cargo new myapp

cd myapp

Build and run:

cargo build

cargo run

For release builds:

cargo build --release

Rust binaries are statically linked by default, making them portable across Linux systems.

FAQs

Why should I compile software from source instead of using a package manager?

Compiling from source gives you access to the latest features, allows you to enable or disable optional components, and ensures the software is optimized for your specific hardware. Package managers often provide stable, tested versions—but these may be outdated or lack specific patches or flags you need.

What should I do if ./configure fails with “No such file or directory”?

This usually means you’re trying to run configure on source code that hasn’t been prepared for Autotools—common when cloning from Git. Run ./autogen.sh or sh autogen.sh first. If that file doesn’t exist, consult the project’s README for build instructions.

Can I compile Windows software on Linux?

Not directly. Windows binaries (.exe) are incompatible with Linux. However, you can compile the source code of cross-platform software (e.g., using MinGW or Wine for Windows API emulation). For native Linux builds, ensure the code is written in portable languages like C, C++, or Go.

How do I know which libraries I need to install?

Look for error messages like “fatal error: openssl/ssl.h: No such file or directory.” This indicates you need the OpenSSL development package. Search for the header file name with your package manager: apt search ssl.h or dnf provides */ssl.h.

Is compiling software from source safe?

It is safe if you trust the source. Always download code from official project websites or verified repositories. Avoid compiling code from untrusted third-party sites. Review the source code before compilation if security is critical.

Why is my compiled program so large?

Debug symbols and unoptimized builds increase binary size. Use -O2 during compilation and strip symbols after install:

strip /usr/local/bin/myprogram

This reduces size significantly without affecting functionality.

Can I compile code on a headless server?

Yes. Compilation does not require a graphical interface. As long as you have the compiler, build tools, and dependencies installed, you can compile any software from the command line—even on remote servers via SSH.

What’s the difference between gcc and g++?

gcc is primarily for C code. g++ is for C++ and automatically links the C++ standard library. Use g++ when compiling C++ source files (.cpp, .cc). Using gcc on C++ code may result in linker errors.

How do I update a program I compiled from source?

Re-download the new source, reconfigure, recompile, and reinstall. If you used checkinstall, uninstall the old package first. Always backup configuration files before upgrading.

Conclusion

Compiling code in Linux is not just a technical skill—it’s a gateway to deeper control, customization, and understanding of how software works under the hood. From installing essential build tools to troubleshooting missing dependencies and optimizing compilation flags, this guide has equipped you with the knowledge to confidently compile software from source across any Linux distribution.

Remember: always read documentation, use version control, isolate your builds, and test thoroughly. Whether you’re installing a web server, building a kernel module, or contributing to open-source projects, the ability to compile from source ensures you’re never limited by pre-packaged binaries.

As you gain experience, you’ll begin to appreciate the elegance of the Unix philosophy: small, modular tools working together. The compiler, linker, and make system are among the most powerful of these tools. Master them, and you unlock the full potential of Linux as a development and production platform.

Keep experimenting. Build your own tools. Share your code. And never stop learning—the world of software compilation is vast, rewarding, and constantly evolving.