This guide will take you through the Pi specific steps of an LFS build.
We're going to work our way through the development version of LFS, while paying extra attention to the steps where the instructions differ for the Pi. It is therefore recommended that you keep the LFS book open in another browser tab. You'll find a pointer to the corresponding section of the LFS book at each step. The LFS book steps that are not mentioned can be assumed to work on the Pi exactly as printed.
This guide was tested and verified on an 32GB SanDisk SD card with Raspbian Buster (2020-05-27) as the host system but most Linux distributions should be able to work as a host platform for your LFS build as long as the required tools can be added. The minimum SD card size is probably 4GB. If you use the PiLFS base image, you're all set and you save a few hours on the total build time with more free space for your build compared to Raspbian.
Grand total build time is anywhere from 60 hours on RPi 1 to 8 hours on RPi 4.
The first thing you have to decide before you start building is whether you're going to create an additional partition to hold your LFS system or use a PC to help finalize your SD card after a complete build.
The new partition method:
This is your only option if you don't have access to a PC with an SD card slot that can mount and modify an ext4 file system. You will add a new partition to the SD card, build your LFS system, then make the bootloader use your new LFS partition as the root filesystem.
The PC reshuffle method:
With this method you will build a complete LFS system inside a regular directory on the existing partition of the SD card. After completion, you'll move the SD card over to a PC, mount it, erase everything except your LFS directory, and finally move your LFS system into place to the root of the card. Thus replacing the old distribution with your own.
When booting up a new distribution for the first time, you probably had the choice of resizing the partition to fit the space available on your SD card. With the two above methods in mind, you need to decide if you should resize your existing partition or not - if you're adding a new partition, you shouldn't. But if you're going with the PC reshuffle method, you should.
Perhaps you've already done the resizing a long time ago and now you're thinking about shrinking the partition to make room for a new one. In that case you're on your own... it's probably a lot easier to just re-image the card.
It's a good idea to have the maximum amount of RAM available for building. Either use raspi-config to change your memory split to 16 or change it manually by adding
/boot/config.txt and reboot.
If you're building on a Pi with 256MB of RAM you'll need some swap space.
If you're on Raspbian, set a root password with
sudo passwd root and login as root.
Now, if you run the
version-check.sh script on Raspbian you'll see that there are four packages missing from the requirements. Let's add those:
apt install bison gawk m4 texinfo
So if you've decided on the new partition method, use fdisk or cfdisk to do some work on your SD card's partition table:
mmcblk0p1 is the FAT32 partition that is mounted under /boot and contains the bootloader and Linux kernel.
mmcblk0p2 contains the host system.
Hopefully you'll see some Free Space at the bottom of the table. Select it and make a New Primary partition with whatever space is left. You then need to Write the changes to disk before exiting. You may need to reboot at this point for Linux to see your new partition.
What about swap partitions?
There is no need to create a dedicated swap partition! A swap file can be added at any time later on and is more flexible while offering the same performance.
Use the following command to create an ext4 file system on the new partition:
mkfs.ext4 -m 1 -L MyLFS /dev/mmcblk0p3
This is where your choice of build method comes into play again. If you're building on a new partition, do this:
mkdir -pv $LFS
mount -v -t ext4 /dev/mmcblk0p3 $LFS
If on the other hand you're building in a regular directory for the PC reshuffle method, you would just do this:
mkdir -pv $LFS
Since the Pi needs a slightly different set of packages and patches, we use our own PiLFS wget-list-sysv to grab everything (including the build scripts etc):
mkdir -v $LFS/sources
chmod -v a+wt $LFS/sources
wget --input-file=wget-list-sysv --continue --directory-prefix=$LFS/sources
Again, you need to change
LFS=/lfs if you are not building on a new partition.
Most importantly, the LFS_TGT variable needs to be changed to
Alright, this is the moment of truth. Will you make your way through chapter 5 slow and steady, or just execute the build script and go do something else for a few hours? This is for you to decide ... I've done both :)
Also, here is where you might want to start a tmux or screen session. Because if you break your ssh connection or your router has a hickup, your build will just stop.
You'll want to edit the
ch5-build.sh script first to set your Pi model at the top. Then we start the build like so:
chmod +x ch5-build.sh
The script will report your SBU time after the first binutils build has finished, mine is around 4 minutes on the RPi 4.
For those brave souls who are working through the chapter by hand, check out the about page and read the build scripts to figure out what's going on.
Cool, you've made it this far.
Before you enter the chroot and start your build, you'll want to edit the
ch7-build.sh script to set a couple of optional parameters at the top. Then enter the chroot and execute the script:
chmod +x ch7-build.sh
As you may be aware the Pi doesn't have a way of keeping time between reboots. When it boots, it has no idea what time it is until it can fetch the correct time from an NTP server.
To address this issue and a few other Pi specific things, I've bundled a few bootscripts together from different sources into a tarball for easy installation. I recommend that you add these four scripts:
make install-networkfix install-swapfix install-fake-hwclock install-switch-cpu-governor
First up is an fstab suitable for the new partition method. Here we take the old distribution's partition and turn it into a dedicated space for the user's home directories (you'll have to erase the old content after the first boot obviously).
/dev/mmcblk0p1 /boot vfat defaults 0 0 /dev/mmcblk0p2 /home ext4 defaults,noatime 0 1 /dev/mmcblk0p3 / ext4 defaults,noatime 0 2 #/swapfile swap swap pri=1 0 0 proc /proc proc nosuid,noexec,nodev 0 0 sysfs /sys sysfs nosuid,noexec,nodev 0 0 devpts /dev/pts devpts gid=5,mode=620 0 0 tmpfs /run tmpfs defaults 0 0 devtmpfs /dev devtmpfs mode=0755,nosuid 0 0 tmpfs /dev/shm tmpfs nosuid,nodev 0 0
If you're going with the PC reshuffle method, your fstab would instead look something like this:
/dev/mmcblk0p1 /boot vfat defaults 0 0 /dev/mmcblk0p2 / ext4 defaults,noatime 0 1 #/swapfile swap swap pri=1 0 0 proc /proc proc nosuid,noexec,nodev 0 0 sysfs /sys sysfs nosuid,noexec,nodev 0 0 devpts /dev/pts devpts gid=5,mode=620 0 0 tmpfs /run tmpfs defaults 0 0 devtmpfs /dev devtmpfs mode=0755,nosuid 0 0 tmpfs /dev/shm tmpfs nosuid,nodev 0 0
While you could potentially build your own Linux kernel as a part of your LFS build, I would strongly recommend that you ensure your system boots properly with the Raspberry Pi Foundation's kernel first.
There is no GRUB on the Pi, and we rely instead on the Raspberry Pi Foundation's bootloader to boot us up.
If you added a new LFS partition, exit the chroot at this point and edit
/boot/cmdline.txt. You need to change
root=/dev/mmcblk0p3 so that the bootloader will use your new LFS partition as the root filesystem.
Some components on the Raspberry Pi board, like Wi-Fi and Bluetooth controllers, require firmware binary blobs to be loaded at boot time. These are files stored in
/lib/firmware and the easiest way to obtain them is to simply copy them from Raspbian or the PiLFS base image.
So there you have it. Your system is now bootable. If you're like me, you'll want to add a couple of things before you take the plunge though. I would at least add dhcpcd, wget, OpenSSH and ntp so that you can easily start building more packages from Beyond LFS/PiLFS once inside your new shiny LFS system.
Now I'll take you through the process of fixing up your SD card on a Linux PC.
On my netbook, the SD card shows up as
/dev/sdb, so I mount the data partition like so:
mount /dev/sdb2 /mnt
Then I erase everything except the
/lfs directory, like so:
shopt -s extglob
rm -rf !(lfs)
And now we do the old switcheroo:
mv /mnt/lfs/* /mnt
The mv command will preserve all the file permissions by default, but if you'd like to copy your LFS system around instead, don't forget to add the preserve permissions flag to cp, i.e.
Perhaps you too would like to share your SD card image with friends or the internet at large? The tricky part of preparing an SD card image is that a straight image copy using dd would take the same size as your whole SD card. Here's how to prepare an SD card image from the ground up:
First, make sure you have a complete copy of all the files that are going to go on the card, including the stuff that goes onto the FAT32 partition like the bootloader and kernel.
Next, we're going to recreate the partition table from scratch. I prefer to use Parted for partition editing because of its automatic alignment feature. Erase whatever is on your card, then create a nice layout:
Don't edit the wrong disk ... triple-check! :)
mkpart primary fat32 4 273
This creates the FAT32 boot partition, following Raspbian's layout, 268MB in size.
Next we'll create our data partition:
mkpart primary ext4 273 2000
Here we're aiming for an image that could fit snuggly on a 2GB SD card.
Now if you print the table, you should have something like this:
Number Start End Size Type File system Flags
1 4194kB 273MB 268MB primary fat32 lba
2 273MB 2000MB 1727MB primary ext4
Now that we have our partition layout, let's format the partitions, like so:
mkdosfs -F 32 -n Pi-Boot -v /dev/sdb1
mkfs.ext4 -m 1 -L MyLFS /dev/sdb2
Then copy all the binaries into place:
mount /dev/sdb1 /mnt
cp -rvp bootfiles/* /mnt
mount /dev/sdb2 /mnt
cp -rvp lfsfiles/* /mnt
Alright, with our card prepared, this is where the magic happens. We're using dd to make an image of the card but we want to stop reading exactly where our ext4 partition ends:
dd if=/dev/sdb of=mylfs.img bs=1M count=2000
So you'll want to set the
count to wherever your ext4 partition ends. That's all there is to it.