LFS: Preparing the Build
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
| Symptom | Almost always |
|---|---|
make install wrote to /usr on the host | You were root — always build as lfs |
| Tools not found after install | set +h missing — bash cached old paths |
| Weird locale-dependent failures | LC_ALL unset — export POSIX |
| Host leaked into a build | .bash_profile lacking env -i — sterile env required |
/tools empty inside chroot | The /tools symlink wasn't made on the host side |
| Build can't write $LFS | Partition unmounted after reboot — fstab entry |
| Tarball fails to extract | Checksum it before — corrupt download |
Exercises
- Run the full version-check roster on your host; note every version that would disqualify it.
- Partition a scratch VM disk by hand —
gdisk,mkfs.ext4, mount,fstab, reboot, verify it returns. - Download five real upstream tarballs (zlib, file, coreutils…) into
$LFS/sources;md5sum -cthem. - As
lfs, deliberately break$PATH— then explain whyset +hexists. - Time a trivial
./configure && makeand compute your SBU multiplier intuition.
Timeline
| Step | What you did |
|---|---|
| Host | Verified a qualifying Linux with dev tools |
| Partition | Carved, formatted, mounted /mnt/lfs, persisted in fstab |
| Sources | ~90 tarballs, checksum-verified, in $LFS/sources |
| Staging | $LFS/tools + the /tools symlink |
| User | lfs with sterile env, LFS_TGT, MAKEFLAGS, set +h |
| Next | LFS 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.shconvention — the book's own host-qualification script - wget-list / md5sums manifests shipped with each LFS release