Fathom-OS Build Series: Chapter 8 Part 2 - The Toolchain

Part of the Fathom-OS Project Log.


This is Part 2 of Chapter 8, the core system build. Part 1 covered the API headers and core libraries through Pcre2. This part builds the toolchain group: the build tools, the testing trio, and the permanent Binutils plus the three math libraries that GCC depends on. Eleven packages, several with critical test suites.

References:


Resuming the Build: A Mount Cleanup

Every Chapter 8 session starts by remounting the virtual kernel filesystems and re-entering the chroot, since the snapshots are taken outside the chroot with everything unmounted. This session that resume hit a snag worth documenting.

After becoming root and confirming $LFS was set, the remount block reported an error on the sysfs mount: mount: /lfs/sys: sysfs already mounted on /sys. That “already mounted” message was the tell. Checking the actual state with findmnt showed the virtual filesystems were already mounted from a prior session, and the remount commands had stacked a second copy on top of most of them. Several mount points were doubled.

Mounting onto an already-mounted point stacks the mounts, which causes confusing failures later. The fix was to fully unmount every layer, verify clean, then remount once. Because things were stacked, some needed unmounting more than once, and the children (dev/pts, dev/shm) had to come off before the parent (dev) would release. Working one at a time and checking with findmnt after each step is what untangled it:

umount /lfs/dev/shm
umount /lfs/dev/pts
umount /lfs/dev
umount /lfs/sys
umount /lfs/proc
umount /lfs/run
findmnt | grep /lfs

Once findmnt showed only the /lfs root partition, a clean single remount and chroot entry worked.

Lesson: if the remount ever reports “already mounted,” stop and check findmnt before proceeding. Do not build on top of stacked mounts. Verify the mount state is clean at the start of every session.


The Build Tools

8.14 M4

A plain native build now, no cross-compilation flags like the Chapter 6 temporary version.

./configure --prefix=/usr
make
make check
make install

8.15 Bc

Bc uses a custom configure, not autotools, with a CC variable and the test target is make test rather than make check.

CC='gcc -std=c99' ./configure --prefix=/usr -G -O3 -r
make
make test
make install

All bc and dc tests passed.

8.16 Flex

Has a test suite, then two symlinks so programs expecting the older lex name find flex.

./configure --prefix=/usr --disable-static --docdir=/usr/share/doc/flex-2.6.4
make
make check
make install
ln -sv flex /usr/bin/lex
ln -sv flex.1 /usr/share/man/man1/lex.1

The Testing Trio

These three are installed specifically to support running the test suites of Binutils, GCC, and other packages. Installing three packages just for testing seems like a lot, but knowing the most important tools are working properly is worth it.

8.17 Tcl

The largest of the three at 2.9 SBU. Builds in the unix subdirectory, then a set of seds rewrite the build-directory paths in the config files to the install locations. The embedded package versions for this release are tdbc1.1.12 and itcl4.3.4 (these differ between Tcl point releases, so they must match the source being built).

SRCDIR=$(pwd)
cd unix
./configure --prefix=/usr --mandir=/usr/share/man --disable-rpath
make

After the config-file seds and unset SRCDIR, the test suite runs with a specific locale:

LC_ALL=C.UTF-8 make test

Result: Total 47153, Passed 43698, Skipped 3455, Failed 0. The skipped tests are for features not applicable here (Windows, big-endian, tests needing a server). Then install, with two library permission fixes so debug symbols can be stripped later, the private headers that Expect needs, the tclsh symlink, and a man page rename to avoid a Perl conflict.

8.18 Expect

Before building Expect, the book has you verify that PTYs work inside the chroot, because the test suites of Bash, Binutils, GCC and others depend on it:

python3 -c 'from pty import spawn; spawn(["echo", "ok"])'

This printed ok, confirming the devpts mount is healthy. Given the mount cleanup at the start of the session, this was a good thing to verify. Then a gcc15 compatibility patch, configure pointing at the Tcl install, build, test, install.

patch -Np1 -i ../expect-5.45.4-gcc15-1.patch
./configure --prefix=/usr --with-tcl=/usr/lib --enable-shared \
            --disable-rpath --mandir=/usr/share/man --with-tclinclude=/usr/include
make
make test
make install
ln -svf expect5.45.4/libexpect5.45.4.so /usr/lib

Tests: Total 29, Passed 29, Failed 0.

8.19 DejaGNU

The test framework GCC and Binutils use. Builds in a dedicated directory, generates two doc formats, runs a quick check, installs with docs.

mkdir -v build
cd build
../configure --prefix=/usr
makeinfo --html --no-split -o doc/dejagnu.html ../doc/dejagnu.texi
makeinfo --plaintext       -o doc/dejagnu.txt  ../doc/dejagnu.texi
make check
make install
install -v -dm755  /usr/share/doc/dejagnu-1.6.3
install -v -m644   doc/dejagnu.{html,txt} /usr/share/doc/dejagnu-1.6.3

8.20 Pkgconf

The successor to pkg-config. Two compatibility symlinks at the end so it works as a drop-in replacement.

./configure --prefix=/usr --disable-static --docdir=/usr/share/doc/pkgconf-2.5.1
make
make install
ln -sv pkgconf   /usr/bin/pkg-config
ln -sv pkgconf.1 /usr/share/man/man1/pkg-config.1

The Permanent Toolchain

8.21 Binutils

The final permanent Binutils, 1.7 SBU. Builds in a dedicated directory. The test suite is marked critical, do not skip.

mkdir -v build
cd build
../configure --prefix=/usr --sysconfdir=/etc --enable-ld=default \
             --enable-plugins --enable-shared --disable-werror \
             --enable-64-bit-bfd --enable-new-dtags --with-system-zlib \
             --enable-default-hash-style=gnu
make tooldir=/usr
make -k check

The ld summary showed 3258 expected passes, 59 expected failures (these are intentional, not real failures), 3 untested, 37 unsupported. The book says one gprofng test is known to fail, and verifying by name confirmed exactly that:

grep '^FAIL:' $(find -name '*.log')

Output: a single gprofng/gprofng.log:FAIL: tmpdir/gp-gmon, the known failure. Nothing else. The critical test suite is clean. Then install and remove the static libraries.

Verifying the Binutils test result by name. Only the known gprofng failure, nothing else.

8.22 GMP

The arbitrary-precision math library. Critical test suite. A gcc15 compatibility sed first, then build, html docs, test, and a check that at least 199 tests passed.

sed -i '/long long t1;/,+1s/()/(...)/' configure
./configure --prefix=/usr --enable-cxx --disable-static --docdir=/usr/share/doc/gmp-6.3.0
make
make html
make check 2>&1 | tee gmp-check-log
awk '/# PASS:/{total+=$3} ; END{print total}' gmp-check-log

The pass count came back 199, meeting the book’s threshold.

8.23 MPFR

Multiple-precision floating point. Critical test suite, book expects all 198 to pass.

./configure --prefix=/usr --disable-static --enable-thread-safe --docdir=/usr/share/doc/mpfr-4.2.2
make
make html
make check

Result: TOTAL 198, PASS 198, FAIL 0. The test output also confirmed the toolchain lining up correctly: GCC 15.2.0, Glibc 2.43, GMP 6.3.0, with the build host’s processor detected.

8.24 MPC

Complex-number math. The last of the three math libraries.

./configure --prefix=/usr --disable-static --docdir=/usr/share/doc/mpc-1.3.1
make
make html
make check
make install
make install-html

A Note on Following the Right Book

One process note worth recording. The LFS site hosts several versions: the stable release tree at /lfs/view/13.0-systemd/ and a rolling development tree at /lfs/view/systemd/. They drift apart. The development tree had already moved to Tcl 8.6.18 with different embedded package versions, and it had reordered packages. Building against the wrong tree means version mismatches in the seds and commands.

The fix is to always build the package versions you downloaded and verified, from the stable book matching your release. Bookmark the stable URL with the version in the path, confirm the page header reads the plain version with no development suffix, and follow the book’s own Next links in order rather than jumping ahead. Checking the package number and version against the book before running each block catches any mismatch before it matters.


Snapshot

With the toolchain group complete, this is the checkpoint before the long run of system packages that follows. Exit the chroot, unmount the virtual filesystems one at a time, verify clean with findmnt (only the /lfs root partition should remain), then snapshot.


What Is Next

The next stretch is the long middle run of Chapter 8: the system libraries and utilities starting with Attr, Acl, Libcap, Libxcrypt, and Shadow, then the final permanent GCC with its full test suite, and onward through the bulk of the userland. That run is large enough that it will span more than one post.


More updates to follow as each build phase completes.

Previous: Chapter 8 Part 1: API and Core Libraries | Next: Chapter 8 Part 3: System Libraries and the Final GCC


All session notes and build logs are committed to the private repository at github.com/QuietWireDev/fathom-os.