Linux From Scratch on Raspberry Pi


Linux From Scratch (LFS) is a project providing instructions for building your own Linux system from scratch. If you have not already, I recommend you visiting their homepage

LFS has many flavors, and a few of them targets cross-compilation and embedded systems; the CLFS tracks. You will find more information about them here. This blog post is inspired by the CLFS Embbedded 1.x track, but as that track is not yet finished and also quite general, I will make a few shortcuts and hardware specific tweaks. Also, I will not go through the exact same steps as the original, so if you are trying to follow that at the same time, you might notice me jump around quite a bit. The end result should however be quite similar.

In short, we will do the following:

  • Create our own cross-compiler.
  • Build the root file system using two main components; uClibc and Busybox.
  • Build the Raspberry Pi specific kernel (this is actually cheating a little, since LFS is based on vanilla software).
  • Download hardware specific binary blobs for booting the Raspberry Pi (also cheating).
  • Prepare a SD-card and populate it with the binary sw, kernel and root file system.

One final piece of information. This post is quite condensed. If you want more information on a specific command or software, I recommend you to look up the corresponding section in the CLFS handbook:

Preparing the build environment

CLFS recommends creating a completely new user to get a clean build environment. Let’s do that:

# Add the clfs group
groupadd clfs

# Add the clfs user
useradd -s /bin/bash -g clfs -m -k /dev/null clfs

# Give clfs a password
passwd clfs

# Log in as the new user
su – clfs

Make sure you’re logged in as the clfs user, then continue with setting up the environment:

# Create build directories
mkdir -pv ~/build/clfs/{sources,firmware,tools,cross-tools,rootfs}

export CLFS=$HOME/build/clfs/rootfs
export CLFS_SRC=$HOME/build/clfs/sources
export CLFS_FW=$HOME/build/clfs/firmware
export CLFS_TOOLS=$HOME/build/clfs/tools
export CLFS_CROSS_TOOLS=$HOME/build/clfs/cross-tools

# Make sure the environment is set up every time you log in
# Create a bash_profile
cat > ~/.bash_profile << "EOF" exec env -i HOME=${HOME} TERM=${TERM} PS1='u:w$ ' /bin/bash EOF # And a bashrc cat > ~/.bashrc << "EOF" set +h umask 022 CLFS=$HOME/build/clfs/rootfs CLFS_SRC=$HOME/build/clfs/sources CLFS_FW=$HOME/build/clfs/firmware CLFS_TOOLS=$HOME/build/clfs/tools CLFS_CROSS_TOOLS=$HOME/build/clfs/cross-tools LC_ALL=POSIX PATH=${CLFS_CROSS_TOOLS}/bin:/bin:/usr/bin export CLFS CLFS_SRC CLFS_FW CLFS_TOOLS CLFS_CROSS_TOOLS LC_ALL PATH EOF [/bash] Now, lets download the source packages: [bash] cd $CLFS_SRC # Binutils wget # Busybox wget # CLFS bootscripts wget # GCC wget # GMP wget # iana-etc wget # MPC wget # MPFR wget # uClibc wget # Kernel git clone git:// # Busybox patch wget # iana-etc patch wget # uClibc patch wget cd $CLFS_FW # Broadcom firmware git clone git:// cd $CLFS_TOOLS # Extra tools git clone git:// [/bash] Finally, lets prepare the target file system by creating the directory structure according to FHS ( [bash] mkdir -pv ${CLFS}/{bin,boot,dev,{etc/,}opt,home,lib/{firmware,modules},mnt} mkdir -pv ${CLFS}/{proc,media/{floppy,cdrom},sbin,srv,sys} mkdir -pv ${CLFS}/var/{lock,log,mail,run,spool} mkdir -pv ${CLFS}/var/{opt,cache,lib/{misc,locate},local} install -dv -m 0750 ${CLFS}/root install -dv -m 1777 ${CLFS}{/var,}/tmp mkdir -pv ${CLFS}/usr/{,local/}{bin,include,lib,sbin,src} mkdir -pv ${CLFS}/usr/{,local/}share/{doc,info,locale,man} mkdir -pv ${CLFS}/usr/{,local/}share/{misc,terminfo,zoneinfo} mkdir -pv ${CLFS}/usr/{,local/}share/man/man{1,2,3,4,5,6,7,8} for dir in ${CLFS}/usr{,/local}; do ln -sv share/{man,doc,info} ${dir} done [/bash]

Creating the cross-compiler

Setup variables for creating a cross-compiler for the Raspberry Pi:

# Clear compiler flags
unset CFLAGS

# Set ABI
export CLFS_ABI=aapcs-linux

# Set host and target
export CLFS_HOST=$(echo ${MACHTYPE} | sed “s/-[^-]*/-cross/”)
export CLFS_TARGET=arm-unknown-linux-uclibcgnueabi

# Set architecture and endianess
export CLFS_ARCH=arm
export CLFS_ENDIAN=little

# Set specific ARM architecture
export CLFS_ARM_ARCH=armv6zk
export CLFS_ARM_MODE=arm

# Set hw float of type vfp
export CLFS_FLOAT=hard
export CLFS_FPU=vfp

# Add to bashrc
echo unset CFLAGS >> ~/.bashrc
echo unset CXXFLAGS >> ~/.bashrc
echo export CLFS_ABI=””${CLFS_ABI}”” >> ~/.bashrc
echo export CLFS_HOST=””${CLFS_HOST}”” >> ~/.bashrc
echo export CLFS_TARGET=””${CLFS_TARGET}”” >> ~/.bashrc
echo export CLFS_ARCH=””${CLFS_ARCH}”” >> ~/.bashrc
echo export CLFS_ENDIAN=””${CLFS_ENDIAN}”” >> ~/.bashrc
echo export CLFS_ARM_ARCH=””${CLFS_ARM_ARCH}”” >> ~/.bashrc
echo export CLFS_ARM_MODE=””${CLFS_ARM_MODE}”” >> ~/.bashrc
echo export CLFS_FLOAT=””${CLFS_FLOAT}”” >> ~/.bashrc
echo export CLFS_FPU=””${CLFS_FPU}”” >> ~/.bashrc

The next step builds the whole toolchain. However, I wouldn’t recommend simply copy-pasting the whole shebang into your console. Instead, do each section/software in turn, to make sure you follow what’s going on.

# Linux headers
cd $CLFS_SRC/linux
make mrproper
make ARCH=${CLFS_ARCH} headers_check
make ARCH=${CLFS_ARCH} INSTALL_HDR_PATH=dest headers_install
cp -rv dest/include/* ${CLFS}/usr/include

tar -jxvf gmp-5.0.1.tar.bz2 && cd gmp-5.0.1
CPPFLAGS=-fexceptions ./configure
make check
make install
cd $CLFS_SRC && rm -rf gmp-5.0.1

tar -jxvf mpfr-3.0.0.tar.bz2 && cd mpfr-3.0.0
./configure –prefix=${CLFS_CROSS_TOOLS} –enable-shared
make install
cd $CLFS_SRC && rm -rf mpfr-3.0.0

tar -zxvf mpc-0.9.tar.gz && cd mpc-0.9
./configure –prefix=${CLFS_CROSS_TOOLS}
make install
cd $CLFS_SRC && rm -rf mpc-0.9

# Binutils
tar -jxvf binutils-2.21.1a.tar.bz2 && mkdir -v binutils-build && cd binutils-build
../binutils-2.21.1/configure –prefix=${CLFS_CROSS_TOOLS}
–target=${CLFS_TARGET} –with-sysroot=${CLFS} –disable-nls
–enable-shared –disable-multilib
make configure-host
make install
cp -v ../binutils-2.21.1/include/libiberty.h ${CLFS}/usr/include
cd $CLFS_SRC && rm -rf binutils-2.21.1 && rm -rf binutils-build

tar -jxvf gcc-4.6.0.tar.bz2 && mkdir -v gcc-build && cd gcc-build
AR=ar LDFLAGS=”-Wl,-rpath,${CLFS_CROSS_TOOLS}/lib”
../gcc-4.6.0/configure –prefix=${CLFS_CROSS_TOOLS}
–build=${CLFS_HOST} –host=${CLFS_HOST} –target=${CLFS_TARGET}
–with-sysroot=${CLFS} –disable-nls –disable-shared
–with-mpfr=${CLFS_CROSS_TOOLS} –with-gmp=${CLFS_CROSS_TOOLS}
–with-mpc=${CLFS_CROSS_TOOLS} –without-headers –with-newlib
–disable-decimal-float –disable-libgomp –disable-libmudflap
–disable-libssp –disable-threads –enable-languages=c,c++
–disable-multilib –with-abi=${CLFS_ABI} –with-arch=${CLFS_ARM_ARCH}
–with-mode=${CLFS_ARM_MODE} –with-float=${CLFS_FLOAT}
make all-gcc all-target-libgcc
make install-gcc install-target-libgcc
cd $CLFS_SRC && rm -rf gcc-4.6.0 && rm -rf gcc-build

# uClibc
tar -jxvf uClibc-0.9.31.tar.bz2 && cd uClibc-0.9.31
patch -Np1 -i ../uClibc-0.9.31-configs-2.patch
sed -i”.bak” ‘/_init, .-_init/d’ libc/sysdeps/linux/arm/crtn.S
sed -i”.bak” ‘/_fini, .-_fini/d’ libc/sysdeps/linux/arm/crtn.S
cp -v clfs/config.${CLFS_ARCH}.${CLFS_ENDIAN} .config
if [ “${CLFS_ABI}” == “aapcs” ] || [ “${CLFS_ABI}” == “aapcs-linux” ];
then sed -i s/CONFIG_ARM_OABI/CONFIG_ARM_EABI/g .config; fi
make oldconfig
make PREFIX=${CLFS} install
cd $CLFS_SRC && rm -rf uClibc-0.9.31

# GCC – second (final) iteration
tar -jxvf gcc-4.6.0.tar.bz2 && mkdir -v gcc-build && cd gcc-build
AR=ar LDFLAGS=”-Wl,-rpath,${CLFS_CROSS_TOOLS}/lib”
../gcc-4.6.0/configure –prefix=${CLFS_CROSS_TOOLS}
–build=${CLFS_HOST} –target=${CLFS_TARGET} –host=${CLFS_HOST}
–with-sysroot=${CLFS} –disable-nls –enable-shared
–enable-languages=c,c++ –enable-c99 –enable-long-long
–with-mpfr=${CLFS_CROSS_TOOLS} –with-gmp=${CLFS_CROSS_TOOLS}
–with-mpc=${CLFS_CROSS_TOOLS} –disable-multilib
–with-abi=${CLFS_ABI} –with-arch=${CLFS_ARM_ARCH}
–with-mode=${CLFS_ARM_MODE} –with-float=${CLFS_FLOAT}
make install
cp -v ${CLFS_CROSS_TOOLS}/${CLFS_TARGET}/lib/ ${CLFS}/lib
cd $CLFS_SRC && rm -rf gcc-4.6.0 && rm -rf gcc-build

Done! Now lets build the actual system…

Build the system

First, add the newly create cross-compiler to the environment:

echo export CC=””${CLFS_TARGET}-gcc”” >> ~/.bashrc
echo export CXX=””${CLFS_TARGET}-g++”” >> ~/.bashrc
echo export AR=””${CLFS_TARGET}-ar”” >> ~/.bashrc
echo export AS=””${CLFS_TARGET}-as”” >> ~/.bashrc
echo export LD=””${CLFS_TARGET}-ld”” >> ~/.bashrc
echo export RANLIB=””${CLFS_TARGET}-ranlib”” >> ~/.bashrc
echo export READELF=””${CLFS_TARGET}-readelf”” >> ~/.bashrc
echo export STRIP=””${CLFS_TARGET}-strip”” >> ~/.bashrc
source ~/.bashrc

Next, compile Busybox:

tar -jxvf busybox-1.18.4.tar.bz2 && cd busybox-1.18.4
patch -Np1 -i ../busybox-1.18.4-config-1.patch
cp -v clfs/config .config
make oldconfig
cp examples/ ${CLFS_CROSS_TOOLS}/bin
chmod 755 ${CLFS_CROSS_TOOLS}/bin/
cd $CLFS_SRC && rm -rf busybox-1.18.4

And finally, build iana-etc:

tar -jxvf iana-etc-2.30.tar.bz2 && cd iana-etc-2.30
patch -Np1 -i ../iana-etc-2.30-update-1.patch
make get
make DESTDIR=${CLFS} install
cd $CLFS_SRC && rm -rf iana-etc-2.30

Build the kernel

Build the Raspberry Pi specific kernel:

# Set cross-compiler target (notice the ‘-‘ in the end)

# Build kernel
cd $CLFS_SRC/linux
make mrproper
ARCH=arm make bcmrpi_cutdown_defconfig

# Do some magic with the Raspberry Pi kernel image creator
cd $CLFS_TOOLS/tools/mkimage
./ $CLFS_SRC/linux/arch/arm/boot/Image
cp -v kernel.img $CLFS/boot/

Copy boot firmware

Copy the binary files provided by Broadcom to the boot directory:

# cp -v $CLFS_FW/firmware/boot/{bootcode.bin,fixup.dat,fixup_cd.dat,start.elf,start_cd.elf} $CLFS/boot/

Install bootscripts

The CLFS-Bootscripts package contains a set of scripts to start/stop the CLFS system at bootup/shutdown.

tar -zxvf clfs-embedded-bootscripts-1.0-pre5.tar.bz2 && cd clfs-embedded-bootscripts-1.0-pre5
make DESTDIR=${CLFS} install-bootscripts
install -dv ${CLFS}/etc/init.d
ln -sv ../rc.d/startup ${CLFS}/etc/init.d/rcS
cd $CLFS_SRC && rm -rf clfs-embedded-bootscripts-1.0-pre5.tar.bz2

Add a few config files. Start with a /etc/mdev.conf file:

cat > ${CLFS}/etc/mdev.conf<< "EOF" # /etc/mdev/conf # Devices: # Syntax: %s %d:%d %s # devices user:group mode # null does already exist; therefore ownership has to be changed with command null root:root 0666 @chmod 666 $MDEV zero root:root 0666 grsec root:root 0660 full root:root 0666 random root:root 0666 urandom root:root 0444 hwrandom root:root 0660 # console does already exist; therefore ownership has to be changed with command #console root:tty 0600 @chmod 600 $MDEV && mkdir -p vc && ln -sf ../$MDEV vc/0 console root:tty 0600 @mkdir -pm 755 fd && cd fd && for x in 0 1 2 3 ; do ln -sf /proc/self/fd/$x $x; done fd0 root:floppy 0660 kmem root:root 0640 mem root:root 0640 port root:root 0640 ptmx root:tty 0666 # ram.* ram([0-9]*) root:disk 0660 >rd/%1
loop([0-9]+) root:disk 0660 >loop/%1
sd[a-z].* root:disk 0660 */lib/mdev/usbdisk_link
hd[a-z][0-9]* root:disk 0660 */lib/mdev/ide_links
md[0-9] root:disk 0660

tty root:tty 0666
tty[0-9] root:root 0600
tty[0-9][0-9] root:tty 0660
ttyS[0-9]* root:tty 0660
pty.* root:tty 0660
vcs[0-9]* root:tty 0660
vcsa[0-9]* root:tty 0660

ttyLTM[0-9] root:dialout 0660 @ln -sf $MDEV modem
ttySHSF[0-9] root:dialout 0660 @ln -sf $MDEV modem
slamr root:dialout 0660 @ln -sf $MDEV slamr0
slusb root:dialout 0660 @ln -sf $MDEV slusb0
fuse root:root 0666

# dri device
card[0-9] root:video 0660 =dri/

# alsa sound devices and audio stuff
pcm.* root:audio 0660 =snd/
control.* root:audio 0660 =snd/
midi.* root:audio 0660 =snd/
seq root:audio 0660 =snd/
timer root:audio 0660 =snd/

adsp root:audio 0660 >sound/
audio root:audio 0660 >sound/
dsp root:audio 0660 >sound/
mixer root:audio 0660 >sound/
sequencer.* root:audio 0660 >sound/

# misc stuff
agpgart root:root 0660 >misc/
psaux root:root 0660 >misc/
rtc root:root 0664 >misc/

# input stuff
event[0-9]+ root:root 0640 =input/
mice root:root 0640 =input/
mouse[0-9] root:root 0640 =input/
ts[0-9] root:root 0600 =input/

# v4l stuff
vbi[0-9] root:video 0660 >v4l/
video[0-9] root:video 0660 >v4l/

# dvb stuff
dvb.* root:video 0660 */lib/mdev/dvbdev

# load drivers for usb devices
usbdev[0-9].[0-9] root:root 0660 */lib/mdev/usbdev
usbdev[0-9].[0-9]_.* root:root 0660

# net devices
tun[0-9]* root:root 0600 =net/
tap[0-9]* root:root 0600 =net/

# zaptel devices
zap(.*) root:dialout 0660 =zap/%1
dahdi!(.*) root:dialout 0660 =dahdi/%1

# raid controllers
cciss!(.*) root:disk 0660 =cciss/%1
ida!(.*) root:disk 0660 =ida/%1
rd!(.*) root:disk 0660 =rd/%1

sr[0-9] root:cdrom 0660 @ln -sf $MDEV cdrom

# hpilo
hpilo!(.*) root:root 0660 =hpilo/%1

# xen stuff
xvd[a-z] root:root 0660 */lib/mdev/xvd_links

And a /etc/profile file:

cat > ${CLFS}/etc/profile<< "EOF" # /etc/profile # Set the initial path export PATH=/bin:/usr/bin if [ `id -u` -eq 0 ] ; then PATH=/bin:/sbin:/usr/bin:/usr/sbin unset HISTFILE fi # Setup some environment variables. export USER=`id -un` export LOGNAME=$USER export HOSTNAME=`/bin/hostname` export HISTSIZE=1000 export HISTFILESIZE=1000 export PAGER='/bin/more ' export EDITOR='/bin/vi' # End /etc/profile EOF [/bash] Create a softlink for the /etc/mtab file:
ln -svf ../proc/mounts ${CLFS}/etc/mtab

The passwd file allows us to login as root:

cat > ${CLFS}/etc/passwd << "EOF" root::0:0:root:/root:/bin/ash EOF [/bash] Add a groups file too: [bash] cat > ${CLFS}/etc/group << "EOF" root:x:0: bin:x:1: sys:x:2: kmem:x:3: tty:x:4: tape:x:5: daemon:x:6: floppy:x:7: disk:x:8: lp:x:9: dialout:x:10: audio:x:11: video:x:12: utmp:x:13: usb:x:14: cdrom:x:15: EOF [/bash] Setup logs: [bash] touch ${CLFS}/var/run/utmp ${CLFS}/var/log/{btmp,lastlog,wtmp} chmod -v 664 ${CLFS}/var/run/utmp ${CLFS}/var/log/lastlog [/bash] A /etc/inittab file:

cat > ${CLFS}/etc/inittab<< "EOF" # /etc/inittab ::sysinit:/etc/rc.d/startup tty1::respawn:/sbin/getty 38400 tty1 tty2::respawn:/sbin/getty 38400 tty2 tty3::respawn:/sbin/getty 38400 tty3 tty4::respawn:/sbin/getty 38400 tty4 tty5::respawn:/sbin/getty 38400 tty5 tty6::respawn:/sbin/getty 38400 tty6 # Put a getty on the serial line (for a terminal) # uncomment this line if your using a serial console #::respawn:/sbin/getty -L ttyS0 115200 vt100 ::shutdown:/etc/rc.d/shutdown ::ctrlaltdel:/sbin/reboot EOF [/bash] Create a /etc/HOSTNAME file:

echo "my-awesome-rasberry" > ${CLFS}/etc/HOSTNAME

And the /etc/hosts file. You might want to add additional hosts to this file:

cat > ${CLFS}/etc/hosts << "EOF" # Begin /etc/hosts (no network card version) my-awesome-raspberry localhost # End /etc/hosts (no network card version) EOF [/bash] Finally, setup network (this requires you to actually edit the files according to your network setup) in /etc/network.conf:

cat > ${CLFS}/etc/network.conf << "EOF" # /etc/network.conf # Global Networking Configuration # interface configuration is in /etc/network.d/ # set to yes to enable networking NETWORKING=yes # set to yes to set default route to gateway USE_GATEWAY=no # set to gateway IP address GATEWAY= # Interfaces to add to br0 bridge # Leave commented to not setup a network bridge # Substitute br0 for eth0 in the interface.eth0 sample below to bring up br0 # instead # bcm47xx with vlans: #BRIDGE_INTERFACES="eth0.0 eth0.1 wlan0" # Other access point with a wired eth0 and a wireless wlan0 interface: #BRIDGE_INTERFACES="eth0 wlan0" EOF [/bash] And one for eth0: [bash] mkdir ${CLFS}/etc/network.d && cat > ${CLFS}/etc/network.d/interface.eth0 << "EOF" # Network Interface Configuration # network device name INTERFACE=eth0 # set to yes to use DHCP instead of the settings below DHCP=no # IP address IPADDRESS= # netmask NETMASK= # broadcast address BROADCAST= EOF [/bash] /etc/udhcpc.conf:

cat > ${CLFS}/etc/udhcpc.conf << "EOF" #!/bin/sh # udhcpc Interface Configuration # Based on # udhcpc script edited by Tim Riker

[ -z “$1” ] && echo “Error: should be called from udhcpc” && exit 1


[ -n “$broadcast” ] && BROADCAST=”broadcast $broadcast”
[ -n “$subnet” ] && NETMASK=”netmask $subnet”

case “$1” in
if [ -f “$RESOLV_BAK” ]; then
/sbin/ifconfig $interface

/sbin/ifconfig $interface $ip $BROADCAST $NETMASK

if [ -n “$router” ] ; then
while route del default gw dev $interface ; do

for i in $router ; do
route add default gw $i dev $interface

if [ ! -f “$RESOLV_BAK” ] && [ -f “$RESOLV_CONF” ]; then

echo -n > $RESOLV_CONF
[ -n “$domain” ] && echo search $domain >> $RESOLV_CONF
for i in $dns ; do
echo nameserver $i >> $RESOLV_CONF

exit 0

chmod +x ${CLFS}/etc/udhcpc.conf


cat > ${CLFS}/etc/resolv.conf << "EOF" # Begin /etc/resolv.conf domain [Your Domain Name] nameserver [IP address of your primary nameserver] nameserver [IP address of your secondary nameserver] # End /etc/resolv.conf EOF [/bash]

Format SD-card

Now it’s time to format an SD-card to hold our newly created system. Since your newly created user clfs doesn’t have root access, you probably want to open a new terminal for this. Insert your SD-card and run

# sudo fdisk -l

Disk /dev/mmcblk0: 1977 MB, 1977614336 bytes
4 heads, 16 sectors/track, 60352 cylinders, total 3862528 sectors
Units = sectors of 1 * 512 = 512 bytesSector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x000dbfc6


You probably have at least your /dev/sda disk showing up in the output of fdisk as well. Make sure you identify the correct device for the SD-card, in this case it is /dev/mmcblk0. One way is to unplug the SD-card and re-run fdisk -l.

Run fdisk against the newly discovered device:
# sudo fdisk /dev/mmcblk0
Configure the device according to your own liking, just make sure to make the boot and root partitions sufficiently large. One suggestion is listed in the layout below. See man fdisk for more information on how to use the disk command.
Device Boot Start End Blocks Id System
/dev/mmcblk0p1 * 2048 206847 102400 c W95 FAT32 (LBA)
/dev/mmcblk0p2 206848 2664447 1228800 83 Linux
/dev/mmcblk0p3 2664448 3862527 599040 82 Linux swap / Solaris
Next, format the partitions you’ve just created:
sudo mkfs.vfat /dev/mmcblk0p1
sudo mkfs.ext4 /dev/mmcblk0p2
sudo mkswap /dev/mmcblk0p3
Finally, mount the newly created file systems:
sudo mkdir -pv /mnt/clfs
sudo mount /dev/mmcblk0p2 /mnt/clfs
sudo mkdir -pv /mnt/clfs/boot
sudo mount -t vfat /dev/mmcblk0p1 /mnt/clfs/boot

Populate the SD-card

While still logged in as a user with root access, populate the root file system:
# sudo cp -rv /home/clfs/build/clfs/rootfs/* /mnt/clfs

Create a /etc/fstab file:

sudo sh -c ‘cat > /mnt/clfs/etc/fstab << "EOF" # Begin /etc/fstab # file system mount-point type options dump fsck # order /dev/mmcblk0p1 /boot vfat defaults 1 2 /dev/mmcblk0p2 / ext4 defaults 0 1 /dev/mmcblk0p3 none swap sw 0 0 proc /proc proc defaults 0 0 sysfs /sys sysfs defaults 0 0 devpts /dev/pts devpts gid=4,mode=620 0 0 shm /dev/shm tmpfs defaults 0 0 # End /etc/fstab EOF' [/bash] Now we need only to add one final file: [bash] sudo sh -c 'cat > /mnt/clfs/boot/cmdline.txt << "EOF" root=/dev/mmcblk0p2 rootdelay=2 EOF' [/bash] Thats it! Unmount your SD-card partitions, move the card to the Raspberry Pi and boot it up! Most file snippets are also available in this Gist.

This Post Has 33 Comments

  1. Patrick McMorris

    Hey this is great post and great timing.

    I’m just reading the Embedded Linux Primer and have a Pi sitting in front of me and was wondering how to set up some cross compiling. Doing the LFS walkthrough has been on my list for a while now and I didn’t even know there was a CLFS. Needless to say I was pretty excited and started working though this condensed version right away.

    Unfortunately, I’ve already hit a few snags most of which I’ve dealt with already.

    1)The first one is that the page doesn’t load properly and there is an error message where the script should be: “Could not embed GitHub Gist 4573205: API Rate Limit Exceeded for”. When I go to git directly I can see the missing ones. But it would be nice if the names started with 1_, 2_, … to make the ordering clear.
    2) There is a path error in one of the scripts that results in a file not found error regarding ../binutils-2.21/configure
    3) The given version of gcc 4.6.0 doesn’t compile with the newer gcc versions like 4.7 for some reason. I found a patch or use 4.6.3 which is fixed. But my real question is why not 4.7.2 etc. Are there issues to be avoided there too?
    4) For uClibc, executing make oldconfig issues a warning and enters interactive mode and expects answers to many technical questions like which ABI to use etc. Is that normal or has something gone wrong in the patch or the sed stuff? Still working on this one.
    5) It would be nice if there was a step to prep the dev system prior to starting to make sure all the needed packages were installed. My Ubuntu box came with most of the stuff listed on the LFS site already (except gawk). But building also required m4 and the download stuff needed git. Both very common and easy to sort out one I knew where things went wrong

    I’m only part way through it but already its a big leap forward for me. Thanks!

    1. Patrick McMorris

      Oh, and a couple of the inline script file generation commands didn’t work as expected because substitution wasn’t happening. For example the line:
      was in my .bashrc file as is, which wasn’t helpful. The small ones I just switched over to echo commands but I’m not a bash expert and dont really know how to get substitution to work when using << "EOF"

    2. Patrick McMorris

      Minor bug in the resolv.conf script as there is an extra quote character at the end that prevents the EOF from being recognized.

  2. Tomas Nilsson

    Hi Patrick,

    thanks for your feedback! Sorry about the errors, but since the post is quite large with lots of copying of code, there’s bound to be some glitches. I will definitely go through your findings and update the post.

  3. Tomas Nilsson

    #1 – Never seen that type of error. I’m sending it to our blog admin so he can have a look at it…

    #2 – Fixed error in gist

    #3 – Creating cross-compilers is a hairy business. All versions of the included software must work together for that particular host and target. It is more common that a given combination of software for a cross-compiler fail to build than actually succeeds. That’s why I’m sticking to the versions suggested by the CLFS book (as close as I can).

    #4 – I get similar output from make oldconfig as you do, but the default values suggested to me all work well. If you can post your output somewhere where I can look at it maybe I can see what is wrong.

    #5 – Yeah, I thought of that, but since there are a lot of different Linux hosts out there, that would claim too much of the blog post. I’m using Gentoo Linux myself. Maybe you can add the needed packages for Ubuntu as a comment, and I can list them in the introduction.

    #second post – You are correct. The cat > somestring << "EOF" is called a heredoc ( ). In order for variable expansion to work in heredocs, the quotation marks must be removed. I found errors in ~/.bashrc. If you find any other, please let me know. I have updated the post and they should work now.

    #third post – Fixed!

    1. Tomas

      Hi Moci,

      thanks for the info. I’ll try your patch the next time I redo this tutorial.

      / Tomas

  4. nizar lazuardy f

    hi patrick, are you compile this source from pc desktop or raspberry pi ??. thanks :)

  5. Gabriel

    Thank you for this very helpful tutorial.
    Anyway, I ‘am following these steps and I get an error when I try to execute the following command:
    make ARCH=${CLFS_ARCH} headers_check
    it returns:
    make: *** No rule to make target `header_check’. Stop.
    Other thing:
    When executing this line it is looking for the .config file that is not present. Is it the good procedure or do we have to get this .config in the /arch/arm/configs directory?

    thank you!

  6. Ariel

    Right now it seems like Expression Engine is the top blogging platform
    out there right now. (from what I’ve read) Is that what you are using on your blog?

  7. Antoine

    That’s exactly what I was looking for! Thanks a lot. You have an error at the beginning of Install bootscript section :

    tar -zxvf clfs-embedded-bootscripts-1.0-pre5.tar.bz2

    1. Tomas Nilsson

      @Antoine, ah you mean the z flag should be replaced by a j flag? You’re correct…

  8. vibe

    Thank you for this excellent article! It was easy to follow the steps and my cross-compiled Linux works like a charm :)

    Yesterday I got the same error as Patrick when loading this page (Could not embed GitHub Gist 4573205: API Rate Limit Exceeded…), today it works again.

    1. Tomas Nilsson

      Yeah, according to our blog admin it happens when a lot of people reads blogs on that links to gists. We’re trying to find a good solution for this…

  9. ALexi

    i was following this tutorial until i got this error, when i did cd $CLFS_SRC/linux :
    su – : cd: /home/clfs/build/clfs/sources/linux: No such file or directory.

    I did everything perfect until now, do you know where it can come from?

    Thank you

    1. Tomas Nilsson

      @ALexi, it seems you forgot to clone the linux kernel repository. After cloning it should be available under $CLFS_SRC/linux


      1. ALexi

        @Tomas Nilsson, thank you for your answer! I understood that this was the problem, but since yesterday, i’m becoming crazy trying to install git! I try to download sources and install them but i always have some errors about a directory with python or something :/ I’m sorry if it’s stupid questions but i’m new to LFS, an trying to build a system for my raspi :)

        Thank you

        1. Tomas Nilsson

          @ALexi, that sounds strange. Git should not have any python dependencies. What host os are you using?

          1. ALexi

            @Tomas Nilsson, I’m building clfs directly on the live lfs CD, maybe that’s why? I have a linux mint on my computer, maybe i can install git on it and then copy it on my Virtual Machine?

            Thank you for your answers!! :)

  10. arun


    how to create custom os for the raspberrty pi means how to create a root file system and kernel compilation for raspberry pi.

  11. SFOS

    Hello community,

    I got a error with GCC at that point:

    – make all-gcc all-target-libgcc

    The error is:

    gtype-desc.c:8829:18: error: subscripted value is neither array nor pointer nor vector
    gtype-desc.c:8948:36: error: subscripted value is neither array nor pointer nor vector
    gtype-desc.c:9032:31: error: subscripted value is neither array nor pointer nor vector
    gtype-desc.c:9053:31: error: subscripted value is neither array nor pointer nor vector
    gtype-desc.c:9060:31: error: subscripted value is neither array nor pointer nor vector
    gtype-desc.c:9067:31: error: subscripted value is neither array nor pointer nor vector
    make[1]: *** [gtype-desc.o] Fehler 1
    make[1]: Leaving directory `/home/clfs/build/clfs/sources/gcc-build/gcc’
    make: *** [all-gcc] Fehler 2

    can you help me?

    Thanks in advance…

  12. Kaushik Shrestha

    I tried gcc-4.6.0 as well as gcc-4.7.3 mentioned in CLFS-Embbedded track but each time I got this error during second(final) build of gcc:

    In file included from /home/clfs/build/clfs/sources/gcc-4.7.3/libstdc++-v3/include/precompiled/stdc++.h:47:0:
    /home/clfs/build/clfs/sources/gcc-build/arm-unknown-linux-uclibcgnueabi/libstdc++-v3/include/cstdio:136:11: error: ‘::tmpnam’ has not been declared
    make[4]: *** [arm-unknown-linux-uclibcgnueabi/bits/stdc++.h.gch/O2ggnu++0x.gch] Error 1
    make[4]: Leaving directory `/home/clfs/build/clfs/sources/gcc-build/arm-unknown-linux-uclibcgnueabi/libstdc++-v3/include’
    make[3]: *** [all-recursive] Error 1
    make[3]: Leaving directory `/home/clfs/build/clfs/sources/gcc-build/arm-unknown-linux-uclibcgnueabi/libstdc++-v3′
    make[2]: *** [all] Error 2
    make[2]: Leaving directory `/home/clfs/build/clfs/sources/gcc-build/arm-unknown-linux-uclibcgnueabi/libstdc++-v3′
    make[1]: *** [all-target-libstdc++-v3] Error 2
    make[1]: Leaving directory `/home/clfs/build/clfs/sources/gcc-build’
    make: *** [all] Error 2

  13. Nat

    I got the same errors as Kaushik Shrestha.
    At the “make” line for the 2nd pass of the GCC installations, it says “error: ‘::tmpnam’ has not been declared. I am using gcc.4.6.0, and have applied the patch recommended in your reply to SFOS.
    What needs to be done to get past this problem?

  14. Nat

    For future reference, I found the problem! Instead of typing “make oldconfig” when building GCC (2nd pass), type “make config”. Enter all the settings in “oldconfig”, but enable “SuSv3 macros” and “SuSv4 obsolescent functions”. Otherwise, it won’t build.
    (This is using uClibc., and patch uClibc.

  15. mouhammed

    i want to ask you something, i am currently working on Version GIT-0.0.1-20130724-arm if i compiled the linux kernel 3.8.0 and follow there instructions about the compilation would that be a problem to boot the system on a raspberry-pi
    Thanks in advance

  16. eech

    Anyone tried to compile GCC to run natively on the pi with the above created rootfs? I got gmp/mpfr/mpc/binutils done without to much problems, but stuck on GCC?


    1. Nat

      Yeah, I had that problem. It turned out to be my $PATH was set incorrectly. I’m assuming the first iteration of GCC worked fine, but the 2nd fails? As soon as the 1st is complete, you need to find the new ARM compiler and add it to your PATH, like this:
      export PATH=$PATH:/home/clfs/build/clfs/cross-tools/bin/
      Hopefully that fixes it!

  17. Rajen


    I am going through this post and I get the following error when compiling Uclibc:

    make: arm-unknown-linux-uclibcgnueabi-gcc: Command not found
    make: arm-unknown-linux-uclibcgnueabi-gcc: Command not found
    MKDIR include/bits
    GEN include/bits/sysnum.h
    extra/scripts/ 31: extra/scripts/ arm-unknown-linux-uclibcgnueabi-gcc: not found
    extra/scripts/ 27: extra/scripts/ arm-unknown-linux-uclibcgnueabi-gcc: not found
    ERROR: Could not generate syscalls.
    Make sure that you have proper kernel headers.
    Your .config in KERNEL_HEADERS=”” was set to:
    make: *** [include/bits/sysnum.h] Error 1

    I have run make clean and started again and ensured that CONFIG_ARM_EABI is set to true in the .config file.

    Any ideas?



  18. Vladimir

    Have same problem as Rajen… Any comments?

  19. dev

    how to build GUI…

  20. It’s a shame you don’t have a donate button! I’d most certyainly donate
    too this brilliant blog! I guess for now i’ll settle for book-marking and adding your
    RSS feed to my Google account. I look frward to new updates and
    wioll talk about this site with my Facebook group. Talk soon!

Leave a Reply