Skip to content
ALB Wiki

Diff — Building from Source

Comparing rev 5 → rev 6

{{infobox
| title = Building from Source
| chapter = Linux Handbook, chapter 16 — tarballs, configure/make/install, build systems, patching
| core | The ./configure && make && make install liturgy — and what each step does
| systems | autotools · cmake · meson/ninja · plain makefiles
| skills | configure flags · DESTDIR/prefix · patches · out-of-tree builds
| next | Inside a Linux system — what a built system consists of
}}
**Building from source is the original Linux distribution mechanism** — before package managers, you got software as a tarball, configured it for your system, compiled it, and installed it. Every LFS chapter is this ritual repeated; every BLFS package, every `git clone` project, every ancient tarball in an archive.org listing runs the same liturgy. This chapter teaches the liturgy and the build systems that automate it — the universal grammar of "source → installed".
## The liturgy — three sacred steps
```sh
tar -xf package-1.0.tar.xz
cd package-1.0
./configure --prefix=/usr      # adapt the build to THIS system
make -j$(nproc)                # compile
make check                     # optional testsuite
sudo make install              # install
```
**`configure`** probes the system — compiler present? headers? libraries? — and generates the Makefiles. **`make`** builds per the Makefile. **`make install`** copies binaries, headers, libraries, docs into `--prefix`. Three steps; a hundred years of software follows them.
## configure — the system's interrogation
```sh
./configure --help             # every package's custom options
./configure --prefix=/usr \        # WHERE it installs — the big one
            --sysconfdir=/etc \    # config location
            --localstatedir=/var \ # state location
            --disable-static \     # don't ship .a libraries
            --enable-shared \
            --with-foo --without-bar   # feature toggles
```
`--prefix` decides *where everything lands*: `/usr` (system), `/usr/local` (local additions, the classic default), `/opt/package` (self-contained). The LFS prefix dance — `/tools`, `/usr`, `DESTDIR` — is this flag doing deep work.
**`make DESTDIR=$STAGING install`** — the packager's trick: install *believing* prefix is `/usr` but landing in `$STAGING/usr` — how packages get built for one root and assembled for another.
## The other build systems
| System | Liturgy | Found in |
| --- | --- | --- |
| **autotools** | `./configure && make && make install` | The classic — most tarballs |
| **cmake** | `cmake -B build -DCMAKE_INSTALL_PREFIX=/usr && cmake --build build` | KDE, modern C++ |
| **meson** | `meson setup build --prefix=/usr && ninja -C build` | GNOME, systemd-era |
| **plain make** | `make && make install` | Minimal projects |
| **cargo/go/npm** | the language's own | Rust, Go, Node projects |
cmake's `-B build` creates an **out-of-tree build dir** — the modern way; source tree stays pristine. Meson+ninja is the fastest. Autotools remains the most common on old-school tarballs — and the deepest to understand: `configure.ac` → `autoconf` → `configure` → `Makefile.in` → `make`.
## What configure actually detects
```sh
./configure ... 2>&1 | tee config.log     # keep the log — failures live there
tail -20 config.log                        # when it fails, the answer's here
```
`configure` compiles test programs — "checking for gcc... yes" means it ran a hello-world; "checking for foo.h... no" means a test compile failed. The fix is almost always a **missing -dev/-devel package**: `libfoo-dev` supplies the headers a build needs that the runtime `libfoo` doesn't. Debian's `-dev`, Red Hat's `-devel`, Slackware ships headers always — the host difference.
## Patches — the surgical fixes
```sh
patch -p1 < fix.patch          # apply — -p1 strips the a/ b/ prefixes
patch -R -p1 < fix.patch       # reverse — the undo
diff -u old.c new.c > my.patch # create one
diff -Naur old/ new/ > big.patch  # whole trees
```
LFS's build applies dozens of small patches — FHS placements, security fixes, cross-build fixes — each a surgical diff that upstream hasn't folded in yet.
## The configure internals — what it actually runs
```sh
./configure --help | less               # every option the package ships
cat config.log                          # the probe transcript — failures live here
less config.status                      # the record of what was detected
cat config.h                            # the generated feature macros
```
`configure` is a generated shell script — thousands of small test-compiles: "checking for gcc... yes" means it ran a hello-world; "checking foo.h usability... no" means a test compile failed and the config.log shows the *compiler's actual error*. `config.status --recheck` reruns; `config.status` regenerates the Makefiles.
## The DESTDIR/prefix grammar — the packager's two knobs
```sh
./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var
make
make install                        # writes to /usr, /etc — REAL
# vs:
make DESTDIR=/tmp/stage install     # writes to /tmp/stage/usr — STAGED
```
`--prefix` = where the software *believes* it lives (baked into paths); `DESTDIR` = where it *actually lands* (the packager's staging). LFS uses both — `--prefix=/usr` + `DESTDIR=$LFS` = "believe /usr, land in $LFS/usr" — exactly where the chroot needs it. The `--sysconfdir`/`--localstatedir` pair move `/etc` and `/var` away from `/usr/etc`/`/usr/var` (the classic wrong defaults).
## The meson + cmake grammar
```sh
# meson — the modern fast one
meson setup build --prefix=/usr --buildtype=release -Dfeature=enabled
ninja -C build
ninja -C build test
DESTDIR=/tmp/stage ninja -C build install
meson configure build -Doption=value   # reconfigure
# cmake — the heavyweight
cmake -B build -DCMAKE_BUILD_TYPE=Release \
      -DCMAKE_INSTALL_PREFIX=/usr \
      -DBUILD_TESTING=OFF -DWITH_X=ON
cmake --build build -j$(nproc)
cmake --install build --prefix /tmp/stage/usr
ctest --test-dir build                 # the tests
```
Both honor `DESTDIR`; meson's `-D` toggles the package's own options (`meson_options.txt` lists them); cmake's `-DWITH_*`/`-DBUILD_*` the same.
## The canonical builds — what the majors actually look like
```sh
# binutils/gcc/glibc — the toolchain trio (LFS chapter 3-5 grammar):
../configure --prefix=/usr --enable-shared --disable-werror
make -j$(nproc); make check || true; make install
# a typical autotools package:
./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var \
            --disable-static --docdir=/usr/share/doc/foo-1.2
make -j$(nproc); make check; make install
# a meson package:
meson setup --prefix=/usr --buildtype=release -Dopt=val build/
ninja -C build/; ninja -C build/ test; ninja -C build/ install
# a cmake package:
cmake -B build -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release \
      -DBUILD_TESTING=OFF
cmake --build build -j$(nproc); ctest --test-dir build; cmake --install build
# a kernel module's DKMS-style build:
make -C /lib/modules/$(uname -r)/build M=$PWD modules
make -C /lib/modules/$(uname -r)/build M=$PWD modules_install
# a python package:
pip install --prefix=/usr/local .
python -m build; pip install dist/*.whl
# a rust binary:
cargo build --release; install -Dm755 target/release/foo /usr/bin/foo
# a go binary:
go build -o foo ./cmd/foo; install -Dm755 foo /usr/bin/foo
```
Each ecosystem's liturgy is the same shape — configure the build dir, build, test, install — the verbs differ.
## Dependencies — the real work
The tarball itself is the easy half; the dependencies are the job:
```sh
./configure   # missing dep = the error is your answer
apt build-dep package        # Debian's dep-fetcher — installs every build-dep
ldd binary | grep 'not found' # runtime gaps
pkg-config --modversion foo  # is it visible to builds?
```
`apt build-dep`, `dnf builddep`, Slackware's "install everything" — each distro's answer to "install the deps this needs". On LFS, dependency management *is* the book's ordering — the build sequence is topological.
## Version sanity and the release hygiene
```sh
make V=1                      # verbose builds — the actual commands
./configure --version         # sometimes tells you what's expected
cat README INSTALL NEWS       # the three files always worth a skim
```
And the trust layer: `gpg --verify package.tar.xz.sig package.tar.xz`, `md5sum`/sha256 checks — the sources are the system's DNA; verify before compiling. This handbook's LFS chapters verify checksums before the first configure — chapter 2 makes it law.
## The install aftermath
```sh
make install DESTDIR=$D       # staged install — packager's form
make install                  # real install — needs root for /usr
ldconfig                      # refresh the .so registry after new libs
command -v newtool            # did it land in PATH?
make uninstall                # often supported — often doesn't exist
```
`checkinstall`/`make install` into `/usr/local` keeps hand-built software quarantined from the package manager's `/usr` — the classic hygiene.
## Where source builds go wrong
| Symptom | Cause |
| --- | --- |
| `configure: foo.h not found` | Missing `-dev`/`devel` package |
| `config.log` cryptic failure | Read the last 20 lines — always |
| Installed but `command not found` | `--prefix` landed outside PATH — `/usr/local/bin`? |
| `libtool` version fights | The tarball's ltmain vs the host's — `autoreconf -fi` |
| Build works, install fails on perms | `sudo make install` — or DESTDIR staging |
| Old build residue breaks rebuild | `make distclean` — or re-extract fresh |
| `make` fails only parallel | Racy Makefile — `-j1` |
| .la files breaking downstream | `rm` the `.la` files — libtool's legacy hazard |
## Exercises
1. Build a real tarball — `tar`, `configure`, `make`, DESTDIR-staged install into `/tmp/stage`.
2. `tee` a configure log; find the exact probe that failed for a missing lib.
3. `apt build-dep` or `dnf builddep` something — see the dep list as a set.
4. Write and apply a patch — `diff -u`, `patch -p1`, then `patch -R` it back.
5. Compare a cmake and an autotools build side by side — the different liturgies.
## See also
- [[C toolchain]] · [[LFS Cross-Toolchain]] · [[LFS System Packages]] · [[Linux]]
[[Category:Linux]]
[[Category:Handbook]]
[[Category:Compilers]]
+
[[Category:Linux Handbook]]