Skip to content
ALB Wiki

LFS: Preparing the Build

This is an old revision of this page — revision 1 (2026-10-25 14:23:26 UTC). It may differ from the current revision.

Linux From Scratch begins before a single package compiles — with a host system, a dedicated partition, ninety source tarballs verified by checksum, and a build user wearing the right environment. This chapter is the setup the LFS book assumes and newcomers most often fumble: the physical preparation of the ground where a new operating system will be grown. Get this right and the build is stamina; get it wrong and nothing after it works.

The chicken-and-egg problem

You cannot compile an operating system without an operating system. The Linux you're building needs a host — an already-running Linux with a working compiler, core utilities, and disk space — to compile against, against which the new system's early pieces link. The host isn't cheating; it's how all software births. Cross-compilation's whole art is the careful severance of host influence — chapter 13 (the cross-toolchain) is where that severance is engineered. This chapter supplies the host.

Step 1 — The host system

Three valid hosts, in ascending realism:

  • A virtual machine — QEMU/KVM or VirtualBox, 2+ CPUs, 4 GB RAM, 30+ GB disk. The professional choice: snapshots let you rewind any mistake, and nothing you break is real.
  • A dedicated partition or spare machine — the fullest experience; real GRUB, real hardware detection, real consequences.
  • A live distribution on real hardware — possible but fragile; the live environment vanishes on reboot.

We use Slackware or Slint as the host throughout this handbook — its installer teaches partitioning by asking you to do it, its pkgtools leave the machinery visible, and it arrives with a complete development environment (gcc, make, binutils) already aboard. Any modern Linux works; the book's checks below tell you if yours qualifies.

Verify the host qualifies

The LFS book carries a version_check.sh ritual — the minimum versions the build requires. On your host, prove each:

bash --version | head -1          # >= 3.2
binutils: ld --version | head -1  # >= 2.13.1
bison --version | head -1
bzip2 --version
coreutils: chown --version | head -1  # >= 6.9
diffutils: diff --version | head -1
findutils: find --version | head -1   # >= 4.2.31
gawk --version | head -1              # >= 4.0.1 (gawk specifically, not mawk)
gcc --version | head -1               # >= 5.2
grep --version | head -1
gzip --version
uname -r                              # kernel >= 5.4
m4 --version | head -1
make --version | head -1              # >= 4.0
patch --version | head -1
perl -V:version                       # >= 5.8.8
python3 --version                     # >= 3.4
sed --version | head -1
tar --version | head -1               # >= 1.22
texinfo: makeinfo --version | head -1
xz --version

Every check must pass — the build's earliest packages lean on all of them. Slackware ships a clean pass out of the box; on Debian-family hosts apt install build-essential gawk bison texinfo closes the usual gaps.

Step 2 — The partition

The new system gets its own home — a dedicated partition it will fill:

# as root — find the target disk
fdisk -l
lsblk

# carve it — gdisk on GPT systems, fdisk on legacy
gdisk /dev/sda          # new partition, ~30G, type 8300 (Linux filesystem)

# format it
mkfs.ext4 /dev/sda3

# the staging ground
mkdir -pv /mnt/lfs
mount /dev/sda3 /mnt/lfs

A swap partition helps if your host is lean; an existing swap can be shared — swapon /dev/sda2 joins it to the build environment. On a VM, a second virtual disk (-hdb/virtio) is cleanest — zero risk to the host's own disk.

Make it persistent — the build reboots:

echo '/dev/sda3  /mnt/lfs  ext4  defaults  0 0' >> /etc/fstab

Step 3 — $LFS and the sources tree

Everything hangs off one environment variable, $LFS — the mountpoint of the partition:

export LFS=/mnt/lfs
mkdir -pv $LFS/sources
chmod -v a+wt $LFS/sources        # world-writable + sticky, /tmp-style

Download the book's package manifest — wget-list (the ~90 tarballs) and md5sums (their checksums) — into $LFS/sources, then fetch:

cd $LFS/sources
wget --input-file=wget-list --continue --directory-prefix=$LFS/sources
# verify every tarball against its checksum before building
pushd $LFS/sources && md5sum -c md5sums && popd

Check every checksum before building. A corrupt tarball discovered three chapters in is a weekend lost; md5sum -c catches it now. Where upstream ships GPG signatures, gpg --verify them too — the sources become the system's DNA.

Step 4 — The toolchain staging area

mkdir -pv $LFS/tools      # where the cross-toolchain will live
ln -sv $LFS/tools /       # /tools symlink — the trick the whole build pivots on

That symlink is subtle and load-bearing: /tools resolves to $LFS/tools, so paths baked into early packages point at /tools/... — which resolves identically inside the chroot later (where $LFS is /). It's how the build escapes its host's filesystem while still being built by it.

Step 5 — The lfs user

Build as a dedicated user, never root — one mis-typed make install as root can overwrite your host's system directories:

groupadd lfs
useradd -s /bin/bash -g lfs -m -k /dev/null lfs
passwd lfs

# hand the staging ground to lfs
chown -v lfs $LFS/{usr{,/*},lib,var,etc,bin,sbin,tools}
chown -v lfs $LFS/sources

Then set its environment — login as su - lfs and write the two files that make every build correct:

cat > ~/.bash_profile << "EOF"
exec env -i HOME=$HOME TERM=$TERM PS1='\u:\w\$ ' /bin/bash
EOF

env -i gives lfs a sterile environment — no inherited host variables leaking into the build.

cat > ~/.bashrc << "EOF"
set +h                     # no hashing — always re-find binaries fresh
umask 022                  # sane default permissions
LFS=/mnt/lfs
LC_ALL=POSIX               # predictable locale for reproducible builds
LFS_TGT=x86_64-lfs-linux-gnu   # the target triplet — our system's name
PATH=$LFS/tools/bin:$PATH  # our toolchain first, host's second
MAKEFLAGS='-j$(nproc)'     # parallel builds across all cores
export LFS LC_ALL LFS_TGT PATH MAKEFLAGS
EOF
source ~/.bash_profile

Each line earns its place: set +h disables bash's binary-path hash cache — critical when freshly-built tools replace earlier ones mid-build; LC_ALL=POSIX makes builds byte-reproducible; LFS_TGT is the target triplet every cross-compiled package is built --target against; MAKEFLAGS the parallelism knob that turns hours into minutes.

Step 6 — The final checks

su - lfs
echo $LFS $LFS_TGT          # must print /mnt/lfs and the triplet
which gcc                   # host's gcc — until tools/ exists
mount | grep lfs            # partition still mounted
df -h $LFS                  # space confirmed

Then, and only then, the build begins.

What an SBU is

The book measures build costs in SBUs — Standard Build Units: the time the first package (binutils pass 1) takes on your machine, used as the unit for every other package's estimate. "This package takes 5 SBU" means five times your binutils-1 build. On a modern multi-core host an SBU is a few minutes; measure yours once and every estimate in the book becomes concrete.

The two books — choose now

LFS ships two editions: SysVinit and systemd. The choice is your new system's PID-1 — made now because later chapters fork on it. For this handbook we follow SysVinit — matching Slackware/Slint's BSD-style rc scripts, and because rc.M is a file you can read while a systemd unit graph is not — with systemd's parallel path flagged wherever the books diverge. Either teaches the same machine.

Where builds go wrong here

SymptomAlmost always
make install wrote to /usr on the hostYou were root — always build as lfs
Tools not found after installset +h missing — bash cached old paths
Weird locale-dependent failuresLC_ALL unset — export POSIX
Host leaked into a build.bash_profile lacking env -i — sterile env required
/tools empty inside chrootThe /tools symlink wasn't made on the host side
Build can't write $LFSPartition unmounted after reboot — fstab entry
Tarball fails to extractChecksum it before — corrupt download

Exercises

  1. Run the full version-check roster on your host; note every version that would disqualify it.
  2. Partition a scratch VM disk by hand — gdisk, mkfs.ext4, mount, fstab, reboot, verify it returns.
  3. Download five real upstream tarballs (zlib, file, coreutils…) into $LFS/sources; md5sum -c them.
  4. As lfs, deliberately break $PATH — then explain why set +h exists.
  5. Time a trivial ./configure && make and compute your SBU multiplier intuition.

Timeline

StepWhat you did
HostVerified a qualifying Linux with dev tools
PartitionCarved, formatted, mounted /mnt/lfs, persisted in fstab
Sources~90 tarballs, checksum-verified, in $LFS/sources
Staging$LFS/tools + the /tools symlink
Userlfs with sterile env, LFS_TGT, MAKEFLAGS, set +h
NextLFS I — the cross-toolchain: binutils → gcc → glibc

References

  • linuxfromscratch.org — LFS book (SysV & systemd editions), chapters 2–4: host requirements, preparing a partition, packages & patches, final preparations
  • The version_check.sh convention — the book's own host-qualification script
  • wget-list / md5sums manifests shipped with each LFS release

See also

  • Linux — chapter 1: the landscape and the handbook map
  • Speakup — the eyes-free Linux path
This page was last edited 2026-10-25 14:23:26 UTC by ALB Team. What links here