Why Compile C Code Yourself?
Many developers rarely touch raw C code, but occasionally you need to compile a C or C++ program from its source files. In the past, I relied on pre-built binaries—and on Linux that usually worked. After switching to macOS, however, I found myself needing to compile more often. This guide walks through the essential steps, using real examples like paperjam, sqlite, and qf (a pager that opens files from rg -n THING | qf). By the end, you'll understand the process from installing a compiler to running make.
Step 1: Install a C Compiler
Before anything else, you need a working C compiler. On Ubuntu or other Debian-based systems, the easiest way is to install the build-essential package:
sudo apt-get install build-essential
This installs gcc, g++, and make. On macOS, the situation is more fragmented; you typically install Xcode Command Line Tools:
xcode-select --install
Alternatively, you can use Homebrew to install gcc—but the command-line tools are usually sufficient.
Step 2: Install the Program's Dependencies
C lacks a built-in dependency manager, so you must track down libraries yourself. Fortunately, most C programs keep dependencies minimal, and they're often available via your system package manager. Always check the project's README for specific instructions.
Example: paperjam
Paperjam's README states:
To compile PaperJam, you need the headers for the libqpdf and libpaper libraries (usually available as libqpdf-dev and libpaper-dev packages). You may need a2x (found in AsciiDoc) for building manual pages.
On Debian/Ubuntu, run:
sudo apt install -y libqpdf-dev libpaper-dev
On macOS with Homebrew, the equivalent packages are often named without the -dev suffix, so you'd use brew install qpdf libpaper (though libpaper may not exist—check the project's docs).
Tip: When a README mentions a package like libqpdf-dev, assume it refers to a Debian-based distro. For other systems, search for the library's name (e.g., qpdf) in your package manager.
Example: sqlite
SQLite is famously self-contained—it has zero external dependencies. You can compile it with just a C compiler and the source files. That's why it's a great first project.
Example: qf
Qf is a simple pager written in C. Its dependencies are light (often just the standard library), but always check its README for any special requirements.
Step 3: Run ./configure (If Present)
Some C projects ship a Makefile directly; others include a ./configure script that generates one. The ./configure script checks your system for required libraries and compiler features, then produces a custom Makefile.
When to run it
If you see a configure file (or configure.ac), run:
./configure
It will output a lot of text—often cryptic. If it fails, read the error messages carefully; they usually indicate missing dependencies or incompatible tools.
Example: sqlite
SQLite's source distribution includes a configure script. Running it produces a Makefile tailored to your system. If you don't want to run configure, SQLite also provides a ready-made Makefile for simple builds (just make).
For projects without a configure script, you skip straight to make.
Step 4: Compile with make
Once you have a Makefile (either provided or generated by ./configure), compiling is usually a single command:
make
If you have multiple cores, you can speed up compilation with make -j4 (replace 4 with the number of CPU cores).
Common pitfalls
- Missing dependencies: The compiler will complain about missing headers or libraries. Install the required packages and try again.
- Outdated compiler: Some C11 or C17 features require a recent compiler. Update your toolchain if you see syntax errors.
- Makefile needs editing: Occasionally you must adjust paths or flags in the Makefile itself. Look for comments like “Edit here for your system.”
Step 5: Install the Program (Optional)
After successful compilation, you'll have a binary (usually named after the program). To use it system-wide, run:
sudo make install
Be careful: this copies files into /usr/local/bin or similar. If you prefer not to install system-wide, just run the binary from the build directory.
Example: qf
Qf compiles to a single executable. You can copy it to a directory in your $PATH, or use the project's install target if provided.
Final Thoughts
Compiling C programs isn't as intimidating as it seems. The steps are almost always:
- Install a C compiler and
make. - Install dependencies (check the README).
- Run
./configureif present. - Run
make. - Optionally
make install.
With practice, you'll learn to read compiler errors and track down libraries. Start with simple projects like sqlite, then move to tools like paperjam that have a few dependencies. Good luck—and happy compiling!