Part of the Fathom-OS Project Log.
Chapter 6 cross-compiles a set of basic utilities using the cross-toolchain built in Chapter 5. These tools install into their final locations in the LFS filesystem but cannot be used yet. Basic tasks still rely on the host’s tools through this whole chapter. They only become usable in Chapter 7 after entering the chroot environment, but every package here has to be built first. This is 17 packages built in sequence, so the whole chapter is covered in one post.
References:
Before You Start: The Pre-Flight Check
Same as Chapter 5, every package in this chapter must be built as the lfs user with the correct environment. If you SSH in, you land as your normal user, not lfs. Switch with a login shell and verify before doing anything:
su - lfs
echo $LFS && echo $LFS_TGT && echo $MAKEFLAGS && umask
You want /lfs, x86_64-lfs-linux-gnu, -j10, 0022. The book repeats the warning that improper LFS setting combined with building as root can render the machine unusable, so this check is not optional.
A Note on Book Versions
Partway through this chapter I noticed the online book showing a newer package version than what I had downloaded. For example, the development version of the book listed Coreutils-9.11 while my verified source from Chapter 3 was 9.10.
This is not a problem and the fix is simple: follow the stable book that matches your release, not the development book. The stable 13.0-systemd book at linuxfromscratch.org/lfs/view/13.0-systemd/ is frozen at the exact package versions you downloaded and verified. The development book runs ahead as maintainers test newer point releases for the next version. Always build the versions you downloaded and verified, since the whole package set was tested together as a known-good combination. Mixing in a newer point release breaks that guarantee.
Lesson: bookmark the stable book matching your sources, not the development tree.
The Universal Build Workflow
Same pattern as Chapter 5 for every package: change to $LFS/sources, extract with tar, enter the directory, build and install, then return and delete the source. The key difference in this chapter is the configure flags now use the cross-compilation pattern, --host=$LFS_TGT and --build=$(config.guess), which tells the build system to use the cross-compiler to produce binaries for the LFS machine. Installs use DESTDIR=$LFS to land in the LFS filesystem.
The Packages
The routine utility builds are listed below with their key commands. Each followed the standard extract, configure, make, make DESTDIR=$LFS install, then remove-source workflow. Build times are small (most 0.1 SBU) unless noted.
6.2 M4
./configure --prefix=/usr --host=$LFS_TGT --build=$(build-aux/config.guess)
make
make DESTDIR=$LFS install
6.3 Ncurses
Builds a tic program on the host first, then the main package. Creates a libncurses.so symlink and edits curses.h to use the wide-character data structures.
mkdir build
pushd build
../configure --prefix=$LFS/tools AWK=gawk
make -C include
make -C progs tic
install progs/tic $LFS/tools/bin
popd
./configure --prefix=/usr --host=$LFS_TGT --build=$(./config.guess) \
--mandir=/usr/share/man --with-manpage-format=normal \
--with-shared --without-normal --with-cxx-shared \
--without-debug --without-ada --disable-stripping AWK=gawk
make
make DESTDIR=$LFS install
ln -sv libncursesw.so $LFS/usr/lib/libncurses.so
sed -e 's/^#if.*XOPEN.*$/#if 1/' -i $LFS/usr/include/curses.h
6.4 Bash
Uses --without-bash-malloc to avoid a known segfault issue, and creates the sh symlink.
./configure --prefix=/usr --build=$(sh support/config.guess) \
--host=$LFS_TGT --without-bash-malloc
make
make DESTDIR=$LFS install
ln -sv bash $LFS/bin/sh
6.5 Coreutils
Enables hostname (needed by the Perl test suite later) and moves chroot to its final location since some programs hardcode the path.
./configure --prefix=/usr --host=$LFS_TGT --build=$(build-aux/config.guess) \
--enable-install-program=hostname \
--enable-no-install-program=kill,uptime
make
make DESTDIR=$LFS install
mv -v $LFS/usr/bin/chroot $LFS/usr/sbin
mkdir -pv $LFS/usr/share/man/man8
mv -v $LFS/usr/share/man/man1/chroot.1 $LFS/usr/share/man/man8/chroot.8
sed -i 's/"1"/"8"/' $LFS/usr/share/man/man8/chroot.8
6.6 Diffutils
Supplies gl_cv_func_strcasecmp_works=y directly because the check cannot run during cross-compilation.
./configure --prefix=/usr --host=$LFS_TGT \
gl_cv_func_strcasecmp_works=y \
--build=$(./build-aux/config.guess)
make
make DESTDIR=$LFS install
6.7 File
Builds a temporary file command on the host first (it must match the version being built), then compiles pointing at it with FILE_COMPILE. Removes the libtool archive.
mkdir build
pushd build
../configure --disable-bzlib --disable-libseccomp \
--disable-xzlib --disable-zlib
make
popd
./configure --prefix=/usr --host=$LFS_TGT --build=$(./config.guess)
make FILE_COMPILE=$(pwd)/build/src/file
make DESTDIR=$LFS install
rm -v $LFS/usr/lib/libmagic.la
6.8 Findutils
./configure --prefix=/usr --localstatedir=/var/lib/locate \
--host=$LFS_TGT --build=$(build-aux/config.guess)
make
make DESTDIR=$LFS install
6.9 Gawk
Removes some unneeded files first.
sed -i 's/extras//' Makefile.in
./configure --prefix=/usr --host=$LFS_TGT --build=$(build-aux/config.guess)
make
make DESTDIR=$LFS install
6.10 Grep
./configure --prefix=/usr --host=$LFS_TGT --build=$(./build-aux/config.guess)
make
make DESTDIR=$LFS install
6.11 Gzip
./configure --prefix=/usr --host=$LFS_TGT
make
make DESTDIR=$LFS install
6.12 Make
./configure --prefix=/usr --host=$LFS_TGT --build=$(build-aux/config.guess)
make
make DESTDIR=$LFS install
6.13 Patch
./configure --prefix=/usr --host=$LFS_TGT --build=$(build-aux/config.guess)
make
make DESTDIR=$LFS install
6.14 Sed
./configure --prefix=/usr --host=$LFS_TGT --build=$(./build-aux/config.guess)
make
make DESTDIR=$LFS install
6.15 Tar
./configure --prefix=/usr --host=$LFS_TGT --build=$(build-aux/config.guess)
make
make DESTDIR=$LFS install
6.16 Xz
Removes the libtool archive.
./configure --prefix=/usr --host=$LFS_TGT --build=$(build-aux/config.guess) \
--disable-static --docdir=/usr/share/doc/xz-5.8.2
make
make DESTDIR=$LFS install
rm -v $LFS/usr/lib/liblzma.la
6.17 Binutils Pass 2
A major toolchain build at 0.4 SBU. Applies a libtool workaround first, then builds in a separate directory and removes libtool archives and static libraries at the end.
sed '6031s/$add_dir//' -i ltmain.sh
mkdir -v build
cd build
../configure --prefix=/usr --build=$(../config.guess) --host=$LFS_TGT \
--disable-nls --enable-shared --enable-gprofng=no \
--disable-werror --enable-64-bit-bfd --enable-new-dtags \
--enable-default-hash-style=gnu
make
make DESTDIR=$LFS install
rm -v $LFS/usr/lib/lib{bfd,ctf,ctf-nobfd,opcodes,sframe}.{a,la}
6.18 GCC Pass 2
The final and largest build of the chapter at 4.5 SBU, needing 6 GB of disk. Unpacks GMP, MPFR, MPC again, applies the x86_64 lib fix and a POSIX threads override, then builds.
tar -xf ../mpfr-4.2.2.tar.xz
mv -v mpfr-4.2.2 mpfr
tar -xf ../gmp-6.3.0.tar.xz
mv -v gmp-6.3.0 gmp
tar -xf ../mpc-1.3.1.tar.gz
mv -v mpc-1.3.1 mpc
case $(uname -m) in
x86_64)
sed -e '/m64=/s/lib64/lib/' -i.orig gcc/config/i386/t-linux64
;;
esac
sed '/thread_header =/s/@.*@/gthr-posix.h/' \
-i libgcc/Makefile.in libstdc++-v3/include/Makefile.in
mkdir -v build
cd build
../configure --build=$(../config.guess) --host=$LFS_TGT --target=$LFS_TGT \
--prefix=/usr --with-build-sysroot=$LFS \
--enable-default-pie --enable-default-ssp --disable-nls \
--disable-multilib --disable-libatomic --disable-libgomp \
--disable-libquadmath --disable-libsanitizer --disable-libssp \
--disable-libvtv --enable-languages=c,c++ \
LDFLAGS_FOR_TARGET=-L$PWD/$LFS_TGT/libgcc
make
make DESTDIR=$LFS install
ln -sv gcc $LFS/usr/bin/cc
Issue Caught: Stale Build Directory
When I ran mkdir -v build for GCC Pass 2, it failed with cannot create directory 'build': File exists. A build directory was already present inside the freshly extracted GCC source, full of configured files with timestamps from an earlier session.
The most likely cause is that the GCC source from the Chapter 5 Libstdc++ step was not fully removed, so tonight’s tar extraction unpacked over a leftover tree that still had its old build directory. I cannot say for certain the earlier cleanup was skipped, but the timestamps line up with that session.
The fix is important: a stale, already-configured build directory will corrupt the new build. Do not configure into it. Check the contents first, then clear and recreate it clean:
cd ..
rm -rf build
mkdir -v build
cd build
Lesson for anyone following along: before configuring any package that builds in a build directory, confirm that directory is empty. If mkdir build ever reports the directory already exists, stop and clear it rather than building into whatever was left behind.
Snapshot
With the temporary tools cross-compiled, this is a good point to snapshot before entering the chroot in Chapter 7. A clean rollback point here means the whole temporary toolchain does not have to be rebuilt if something goes wrong later.
What Is Next
The temporary tools are built and installed in the LFS filesystem but cannot be used yet. Chapter 7 enters the chroot environment, where these tools finally become usable and are used to build the additional temporary tools needed before the core system build in Chapter 8.
More updates to follow as each build phase completes.
Previous: Chapter 5: Compiling a Cross-Toolchain | Next: Chapter 7: Entering Chroot and Building Additional Temporary Tools
All session notes and build logs are committed to the private repository at github.com/QuietWireDev/fathom-os.



