Skip to content

Instantly share code, notes, and snippets.

@nathanbw
Last active April 19, 2018 08:20
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nathanbw/36bcfb6cbf8770873c7d to your computer and use it in GitHub Desktop.
Save nathanbw/36bcfb6cbf8770873c7d to your computer and use it in GitHub Desktop.
LFS 7.7 Ubuntu 14.04 build notes

Building Linux From Scratch 7.7 (stable)

This document follows my journey into building Linux From Scratch 7.7, following the excellent Linux From Scratch book.

About the Author

I am Nathan Wallace, a Software Engineer who works for Pardot, a Salesforce company. None of the content of this document represents the opinion of my employer; this is a project I am undertaking on my own time for my own education. Salesforce is a great place to work, and aside from saying that, this document has nothing to do with Salesforce or Pardot. :-)

My experience with Linux started in 2002, when I first discovered Linux shortly after my family moved into the 21st century by subscribing to broadband internet service at our home in Oxford, Alabama. By 2004, I had downloaded and tried more than 30 different distributions, seeking to learn as much as I could about the system and how each distro was different.

I went to Auburn University, graduating with a B.S. in Computer Science in 2009, and took my first job developing embedded software for fiber optic switches. After 4 years "close the to metal" I decided to switch to my focus to developing software for the web (a great change of pace.)

In 2014 I decided to build LFS for the first time. Since I didn't want to limit my work to just the times when I was at home, I installed Slackware into a VirtualBox VM and got to work. I made pretty good progress until Chapter 6, where things stalled. I had a unit test failure while building binutils and at that point sort of ran out of steam.

This time, I hope that writing about my experience will give me the drive to go all the way through the book and arrive at a useful system. Along the way, I hope to learn a lot more of the details of how a Linux system is put together; gain some familiarity with a fairly "minimal" Linux system and its interdependencies, and maybe dig in and contribute to any area that catches my interest.

I may succeed or fail, but I hope my experience will be educational to myself and any others following along at home.

Environment

For this attempt at building LFS 7.7, I will be using an Ubuntu 14.04 VM, hosted on VirtualBox 4.3.30 on Mac OS X 10.10.5. The reasons for this potentially brittle and slow setup are many, but mostly come down to convenience.

Why OS X? My MacBook Pro is the computer I have with me most of the time, and I didn't want to be limited by access to the internet in order to build LFS (by building it on my server at home, and then needing a good internet connection to ssh in and work on it when I'm out of the house.)

Why a VM? I have a lot of development projects on my bare-metal OS X install, and didn't want to spare the disk space necessary for dual boot, so I'm hoping a VM will be sufficient for my education.

Why Ubuntu 14.04? That's the ISO I had laying around most recently, it's a Long Term Support release, and I haven't played with Ubuntu in years (I run Slackare as my sole Linux distro at home), so I figured it'd be a nice foray into the Ubuntu side of the house.

Potential Challenges

Time I'm expecting the birth of my first child in just a few days, so I doubt I'll have tons of time to play with LFS as a new parent. (This is also a big reason for why I don't have a dedicated box for LFS; it's easier to just pop open my laptop and play than have to be near my Slackware workstation in my home office.) Environment As you'll see in the section below on preparing the Ubuntu host, there are some differences between when I get with a stock Ubuntu 14.04 install and what LFS expects. This wacky environment may lead to subtle and hard-to-track-down bugs later in the process. I'm willing to spend the time figuring it out, and hopefully when I reach out on the forums, people will be supportive and helpful.

Preparing the Ubuntu 14.04 host

LFS provides a script for checking the versions of all needed dependencies the host system must have available. I've annotated the output of this script below:

bash, version 4.3.11(1)-release          # Required: Bash-3.2 or greater
/bin/sh -> /bin/bash                     # I had to manually change this symlink from pointing at /bin/dash to point at /bin/bash
Binutils: (GNU Binutils for Ubuntu) 2.24 # Required: Binutils-2.17 or greater
bison (GNU Bison) 3.0.2                  # Required: Bison-2.3 or greater
/usr/bin/yacc -> /usr/bin/bison.yacc     # I'm assuming this is fine
bzip2,  Version 1.0.6, 6-Sept-2010.      # Required: Bzip2-1.0.4 or greater
Coreutils:  8.21                         # Required: Coreutils-6.9 or greater
diff (GNU diffutils) 3.3                 # Required: diffutils 2.8.1 or greater
find (GNU findutils) 4.4.2               # Required: findutils 4.2.31 or greater
GNU Awk 4.0.1                            # Required: Gawk-4.0.1 or greater
/usr/bin/awk -> /usr/bin/gawk            # This is actually a symlink to /etc/alternatives/awk, which is a symlink to /usr/bin/gawk. I think it's okay
gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4  # Required: GCC-4.1.2 or greater but no greater than 4.9.2
g++ (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4  # Required: GCC-4.1.2 or greater but no greater than 4.9.2
(Ubuntu EGLIBC 2.19-0ubuntu6.6) 2.19     # See note below; I'm not sure if this is OK. I think it will be, though.
grep (GNU grep) 2.16                     # Required: Grep-2.5.1a or greater
gzip 1.6                                 # Required Gzip-1.3.12 or greater
Linux version 3.19.0-26-generic (buildd@lgw01-04) (gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1) ) #28~14.04.1-Ubuntu SMP Wed Aug 12 14:09:17 UTC 2015 # Looks good
m4 (GNU M4) 1.4.17          # Required: M4-1.4.10
GNU Make 3.81               # Required: Make-3.81
GNU patch 2.7.1             # Required: Patch-2.5.4
Perl version='5.18.2';      # Required: Perl-5.8.8
sed (GNU sed) 4.2.2         # Required: Sed-4.1.5
tar (GNU tar) 1.27.1        # Required: Tar-1.18
makeinfo (GNU texinfo) 5.2  # Required: Texinfo-4.7
xz (XZ Utils) 5.1.0alpha    # Required: Xz-5.0.0
g++ compilation OK

I think everything above looks okay, with one potential red flag: this version of Ubuntu uses eglibc instead of glibc. After some reading, I find that eglibc was meant to be API and ABI compatible with glibc, and it seems (at a glance) that their versions correspond. I'm deciding to forge ahead, assuming that this difference will not be important. I recognize it very well may be, though, and so am noting it here for future reference.

Vanilla Ubuntu 14.04 is missing some of the required packages by default. I used this script provided by GitHub user josephabrahams to install the missing packages. In addition to installing some needed ubuntu packages (build-essential, bison, and gawk), the script also downloads and builds gmp, mpfr, and mpc from source and manually installs them into /usr. This is another portion of the environment that I'm worried may cause problems going forward. I may research more to see why these were downloaded/built outside of the package manager, but for now I want to continue ahead.

Preparing the LFS partition

I used cfdisk to create a 20000MB partition for the LFS root, and a 1470MB partition for swap. I didn't make swap or turn swap on since the host system already has a swap partition (I found it with cat /proc/swaps. I should check that chrooting in for building doesn't make that swap unavailable or do any other weirdness.

Downloading the sources

I downloaded the requisite to $LFS/tools, as mentioned in the book. After downloading all the sources and given checksum, I checked the md5sums of the downloaded packages with md5sum -c md5sums |grep -v OK (if that command doesn't output anything, then all the files checked out OK). After I verified the md5sums of the packages and patches, I initialized a git repo in the root of /tools so I could easily revert the directories to their pristine states.

Creating the lfs user

I created the lfs user with the commands in the book. After I created the user, I went back to $LFS/sources and used the following commands to change the ownership of the source packages to the lfs user: pushd $LFS/sources ; chmod -Rv lfs .git && chmod -Rv lfs * ; popd

In Ubuntu, there is a system-wide bashrc at /etc/bash.bashrc. The system will helpfully execute this script everytime you make a new shell. I noticed this near the top of this file:

# If not running interactively, don't do anything
[ -z "$PS1" ] && return

Simply not setting PS1 in the lfs user's .bash_profile (setting it in ~lfs/.bashrc instead) solved the problem of this file interfering with the otherwise-pristine environment of the lfs user.

After all that, env gives me the following output when I log in as the lfs user:

TERM=xterm-256color
LC_ALL=POSIX
LFS=/mnt/lfs
PATH=/tools/bin:/bin:/usr/bin
PWD=/home/lfs
LFS_TGT=x86_64-lfs-linux-gnu
PS1=Last command had exit code: $? at \D{%H:%M}\n\u@\h:\w\n$
SHLVL=1
HOME=/home/lfs
_=/usr/bin/env

On to building!

Building

Since my laptop has four physical CPUs, and the VM has four vCPUs, I plan to make the packages using the -j flag (make -j4) to (hopefully) slightly speed up the build process. The book warns that this may cause a build to fail; I'm hoping if it does, I'll notice immediately and re-run without -j4.

I remembered that I will likely be building the sources for each package multiple times. So, I unpacked all the tarballs at once and added the results to git (so I can easily revert to a pre-build state for all packages at once) like so:

time for file in *.tar.* ; do if [ $file != tzdata2015a.tar.gz ]; then tar xvf $file ; fi ; done # about 1m20s)
git add . # I should have known this would be a step I should have timed. 5 minutes or so?
git commit -m 'Pristine: All unpacked by lfs user'

Note that I ignored 'tzdata2015a.tar.gz; the root of the archive was not a single folder; so I'm sure I'm meant to unpack this later somewhere else.

In section 5.2 of the book (Toolchain Technical Notes), it recommends noting your system triplet and the name of the dynamic linker. My system triplet is x86_64-unknown-linux-gnu. Here is the dynamic linker for this system:

lfs@nathan-VirtualBox:/mnt/lfs/sources/binutils-2.25
$ readelf -l /usr/bin/gawk | grep interpreter
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]

With that, we're off to the races!

Binutils, pass 1

Building binutils gives me my base SBU:

uname -m # gives x86_64, so I manually make the lib dir and link given in the book:
mkdir -v /tools/lib && ln -sv lib /tools/lib64
time { ../binutils-2.25/configure --prefix=/tools --with-sysroot=$LFS --with-lib-path=/tools/lib --target=$LFS_TGT --disable-nls && make && make install ; }
# a lot of output happens here, then finally:
real	2m16.741s
user	1m35.028s
sys	0m12.004s

An SBU of a little over 2 minutes. Not bad! I forgot to use -j4 when building binutils, but I'm going to continue on with the build, believing that my SBU number is a little higher than what I should see if do parallelize make with -j4.

Since I have git set up for all the untarred source packages, returning to a pristine state in $LFS/sources is acheived with:

cd $LFS/sources
rm -rf binutils-* && git co binutils-\* # 'co' is my git alias for checkout
git s # s is my alias for status. Here I'm checking that I'm in fact back in the pristine state

Cross-GCC, pass 1

Used make -j4 for this step; build time was about 6 minutes. Not bad!

Glibc-2.21, Libstdc++

Used make -j4 for these steps.

Binutils, pass 2

I tried running this with make -j4, but it failed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment