SYS 300 Linux From Scratch - Oliver-Mustoe/Oliver-Mustoe-Tech-Journal GitHub Wiki
In this page I will detail my experience working through Linux From Scratch
Specifications:
Version of the book I am using: Version 11.2-systemd
Host OS: Windows 10
Virtualization software: VMware Workstation 16
I setup a mothership VM, where I would build the Linux system, with the following specifications:
- VM Name: MOTHERSHIP-SYS300
- OS: Xubuntu 20.04
- RAM: 8GB
- Processor: 1 (2 cores)
- Disks: 2 50GB
-
- Second disk labeled "LFS.vmdk"
- BIOS Boot
Chapter 2. Preparing the Host System
After setting up my mothership OS I ran a sudo apt update
and copied the following code into script version-check.sh (not my own creation, came from book but stored on Github for convenience) on the mothership (checks for right versions/software):
#!/bin/bash
# Simple script to list version numbers of critical development tools
export LC_ALL=C
bash --version | head -n1 | cut -d" " -f2-4
MYSH=$(readlink -f /bin/sh)
echo "/bin/sh -> $MYSH"
echo $MYSH | grep -q bash || echo "ERROR: /bin/sh does not point to bash"
unset MYSH
echo -n "Binutils: "; ld --version | head -n1 | cut -d" " -f3-
bison --version | head -n1
if [ -h /usr/bin/yacc ]; then
echo "/usr/bin/yacc -> `readlink -f /usr/bin/yacc`";
elif [ -x /usr/bin/yacc ]; then
echo yacc is `/usr/bin/yacc --version | head -n1`
else
echo "yacc not found"
fi
echo -n "Coreutils: "; chown --version | head -n1 | cut -d")" -f2
diff --version | head -n1
find --version | head -n1
gawk --version | head -n1
if [ -h /usr/bin/awk ]; then
echo "/usr/bin/awk -> `readlink -f /usr/bin/awk`";
elif [ -x /usr/bin/awk ]; then
echo awk is `/usr/bin/awk --version | head -n1`
else
echo "awk not found"
fi
gcc --version | head -n1
g++ --version | head -n1
grep --version | head -n1
gzip --version | head -n1
cat /proc/version
m4 --version | head -n1
make --version | head -n1
patch --version | head -n1
echo Perl `perl -V:version`
python3 --version
sed --version | head -n1
tar --version | head -n1
makeinfo --version | head -n1 # texinfo version
xz --version | head -n1
echo 'int main(){}' > dummy.c && g++ -o dummy dummy.c
if [ -x dummy ]
then echo "g++ compilation OK";
else echo "g++ compilation failed"; fi
rm -f dummy.c dummy
Which resulted in:
So I then had to install the un-acquired software with the command:
sudo sudo apt install binutils bison diffutils findutils gawk gcc g++ make m4 texinfo -y
And also added a symbolic link between bash and /bin/sh with the command:
sudo ln -sf bash /bin/sh
With this set I got a clean run of version-check.sh:
With that set, I used the following command to check for what my "LFS.vmdk" disk had been called in the mothership:
lsblk
Which resulted in the disk being labeled the name sdb
(full path /dev/sdb
)
I then became root, sudo su
or sudo -i
, and partitioned the sdb
disk with the command:
cfdisk /dev/sdb
In cfdisk
, I setup the following partition table (followed highly recommended partitions from the book section 2.4):
In a spreadsheet:
Created in cfdisk
:
Then, after writing and exiting cfdisk
, I used the following commands to create the filesystem (“-L” is for labeling, MAKE SURE TO SET THE RIGHT PARTITIONS TO THE RIGHT TYPE/LABEL -- reference spreadsheet and lsblk
):
mkfs.ext2 /dev/sdb2 -L BOOTLFS
-
- Sets the type of the partition to ext2, suitable for small infrequently updated partitions, labels it "BOOTLFS"
mkfs.ext4 /dev/sdb3 -L ROOTLFS
-
- Sets the type of the partition to ext4, labels it "ROOTLFS"
mkfs.ext4 /dev/sdb4 -L HOMELFS
-
- Sets the type of the partition to ext4, labels it "HOMELFS"
File system created:
Then I set the $LFS environment variable for my user (differs from book so that it does not need to be reset when changing users):
echo “export LFS=/mnt/lfs” >> ~/.bashrc
source ~/.bashrc
echo $LFS
-
- Checks if the variable is working
I would repeat the above commands for root.
Then I mounted the LFS partitions/enabled the swap partition with the commands:
mkdir -pv $LFS
mount -v -t ext4 /dev/sdb3 $LFS
mkdir -v $LFS/home
mount -v -t ext4 /dev/sdb4 $LFS/home
/sbin/swapon -v /dev/sdb5
After this, I deviated from the book to setup automatic mounting so I could restart the system during the build process.
I used the command sudo blkid
to get the UUID of sdb5
swap partition, I copied this number.
I then finally set the needed partitions to mount/enable on reboot in the “/etc/fstab” file with the following text added (tabs inbetween items):
/dev/sdb3 /mnt/lfs ext4 defaults 1 1
/dev/sdb4 /mnt/lfs/home ext4 defaults 1 1
UUID="{UUID of sdb5}" none swap sw 0 0
With all of this set, the command lsblk /dev/sdb -f
should generate the following
Chapter 3. Packages and Patches
NOTE: All commands run as root
With my partitions set, I used the following command (see note) to make a directory where I will download all of my packages and patches needed in future chapters with the command:
mkdir -v $LFS/sources
Then I would make the directory writable and sticky with the following command:
chmod -v a+wt $LFS/sources
(NOTE: I originally missed the above chmod
command and did it later, but as it was prescribed in this chapter, I feel it should still go here.)
I then made this pastebin based on the wget-list-systemd from the book. I made the pastebin to update the packages expat, Python, and zlib.
I then used wget
to download the pastebin as "wget-list-systemd" with the command:
wget -O wget-list-systemd https://pastebin.com/raw/XCYCKVip
I then used that to download all of the packages and patches with the command:
wget --input-file=wget-list-systemd --continue --directory-prefix=$LFS/sources
To double check, I downloaded a "md5sums" file in the $LFS/sources
directory to verify all of the correct packages are downloaded with the following commands:
wget https://www.linuxfromscratch.org/lfs/view/stable-systemd/md5sums
pushd $LFS/sources
md5sum -c md5sums
popd
NOTE: The above commands will result in 4 listed files not being able to be read, this is since I upgraded from when the "md5sums" list was made. Below is a screenshot showing that 4 packages are missing, and using egrep
, that they are in fact not missing:
NOTE 2: I would later upgrade Python from 3.10.7 to 3.10.8 with the following commands (included making this python pastebin):
rm $LFS/sources/python-3.10.7-docs-html.tar.bz2
rm $LFS/sources/Python-3.10.7.tar.xz
wget -O python-update https://pastebin.com/raw/6k4Y6DLC
wget --input-file=python-update --continue --directory-prefix=$LFS/sources
Chapter 4. Final Preparations
NOTE: All commands run as root
After getting the needed packages and files, I created the required directory layout with the following commands:
mkdir -pv $LFS/{etc,var} $LFS/usr/{bin,lib,sbin}
for i in bin lib sbin; do ln -sv usr/$i $LFS/$i; done
case $(uname -m) in x86_64) mkdir -pv $LFS/lib64 ;; esac
I then made a separate directory for the cross-complier with the command:
mkdir -pv $LFS/tools
After this I would create an lfs user who is a member of the lfs group (with a home directory, bash shell, no ```/etc/skel`` directory copying, no password) with the commands:
groupadd lfs
useradd -s /bin/bash -g lfs -m -k /dev/null lfs
I then used the following commands to make the lfs user the directory owner of $LFS, thereby giving full access to everything in $LFS, with the commands:
chown -v lfs $LFS/{usr{,/*},lib,var,etc,bin,sbin,tools}
case $(uname -m) in x86_64) chown -v lfs $LFS/lib64 ;; esac
Below is a screenshot showing the previous commands in this chapter used:
With these commands finished, I could login as lfs with the command:
su - lfs
While I was logged in as lfs, I created a new ~/.bash_profile
with the following commands to ensure no bad environmental variables from the host system go into the build environment (ensuring a clean environment):
cat > ~/.bash_profile << "EOF"
exec env -i HOME=$HOME TERM=$TERM PS1='\u:\w\$ ' /bin/bash
EOF
Screenshot of above commands:
I then created a .bashrc file with the following commands:
cat > ~/.bashrc << "EOF"
set +h
umask 022
LFS=/mnt/lfs
LC_ALL=POSIX
LFS_TGT=$(uname -m)-lfs-linux-gnu
PATH=/usr/bin
if [ ! -L /bin ]; then PATH=/bin:$PATH; fi
PATH=$LFS/tools/bin:$PATH
CONFIG_SITE=$LFS/usr/share/config.site
export LFS LC_ALL LFS_TGT PATH CONFIG_SITE
EOF
The settings in the new .bashrc explained (descending order, set +h
is 1):
- Turn off bash's hash function
- Set newly created files and directories to only be writable by owner, but readable/executable by anyone
- Set the LFS variable
- Set the LC_ALL variable (for the chroot environment)
- Set the LFS_TGT variable (important for building cross compiler and linker in the temporary toolchain)
- Set the PATH variable (for chapter 5)
- Add
/bin
to the PATH variable if not sym link - Put
$LFS/tools/bin
ahead of the standard PATH (prioritizes cross-compiler) - Set CONFIG_SITE variable (override contamination from host config items)
- Export the variables for use within any sub-shell
Screenshot of above commands:
I also did the following command to check for the presence /etc/bash.bashrc
(and moving if it is) with the command:
[ ! -e /etc/bash.bashrc ] || mv -v /etc/bash.bashrc /etc/bash.bashrc.NOUSE
I then used the following command to complete the environment with sourcing the user profile using the following command:
source ~/.bash_profile
Below screenshot shows the completed lfs user:
Chapter 5. Compiling a Cross-Toolchain
After completing the environmental setup, I compiled several programs for a cross-toolchain. For each program compiled below is included its name, directory my commands start in, pass (if needed), all commands run during compilation, and a short summary of the commands below.
Binutil - Pass 1 (from $LFS/sources, put in time to measure SBU):
tar -xf binutils-2.39.tar.xz
mv binutils-2.39 binutils
cd binutils
mkdir -v build
cd build
time { ../configure --prefix=$LFS/tools --with-sysroot=$LFS --target=$LFS_TGT --disable-nls --enable-gprofng=no --disable-werror && make && make install; }
Binutil summary: Extracted and changed the directory name to remove version number from package. Then entered and created a dedicated build directory, where I prepared the package to be compiled (prep install of the Binutil programs in the $LFS/tools
directory, look at $LFS for the target of the system libraries, adjust Binutil build system for building a cross linker, disable internationalization/building gprofn, and finally prevent the build from stopping from warnings). With the packaged configured I compiled/installed the packaged.
NOTE: With using the time command, found SBU was about 2 minutes flat (see screenshot below):
GCC (from $LFS/sources)
tar -xf gcc-12.2.0.tar.xz
mv gcc-12.2.0 gcc
cd gcc
tar -xf ../mpfr-4.1.0.tar.xz
mv -v mpfr-4.1.0 mpfr
tar -xf ../gmp-6.2.1.tar.xz
mv -v gmp-6.2.1 gmp
tar -xf ../mpc-1.2.1.tar.gz
mv -v mpc-1.2.1 mpc
case $(uname -m) in x86_64) sed -e '/m64=/s/lib64/lib/' -i.orig gcc/config/i386/t-linux64 ;; esac
mkdir -v build
cd build
../configure --target=$LFS_TGT --prefix=$LFS/tools --with-glibc-version=2.36 --with-sysroot=$LFS --with-newlib --without-headers --disable-nls --disable-shared--disable-multilib--disable-decimal-float --disable-threads --disable-libatomic --disable-libgomp --disable-libquadmath --disable-libssp--disable-libvtv--disable-libstdcxx --enable-languages=c,c++
make
make install
cd ..
cat gcc/limitx.h gcc/glimits.h gcc/limity.h > `dirname $($LFS_TGT-gcc -print-libgcc-file-name)`/install-tools/include/limits.h
GCC summary: Extracted and changed the directory name to remove version number from package. Then entered, unpacked GMP, MPFR, and MPC packages in the directory (as well as removing their version numbers), set the default directory for 64-bit libraries to "lib" (x86_64 hosts only), and created a dedicated build directory. In the build directory, I prepared the package to be compiled (specify version of gblic, ensure inhibit_libc constant is definied when building libgcc, no headers, use GCC internal libraries statically, disable multilib config, disable other features that will fail to compile, set C and C++ compilers to be built). With the packaged configured I compiled/installed the packaged. Finally, I moved out of the build directory and created a full version of the internal headers (same as what GCC would do in normal circumstances.)
Linux-5.19.2 (from $LFS/sources)
tar -xf linux-5.19.2.tar.xz
cd linux-5.19.2
make mrproper
make headers
find usr/include -type f ! -name '*.h' -delete
cp -rv usr/include $LFS/usr
Linux summary: Extracted and entered the Linux folder, made sure there was no stale files embedded, and extracted the user-visible kernel headers from the source.
Glibc-2.36 (from $LFS/sources)
tar -xf glibc-2.36.tar.xz
cd glibc-2.36
case $(uname -m) in i?86) ln -sfv ld-linux.so.2 $LFS/lib/ld-lsb.so.3 ;; x86_64) ln -sfv ../lib/ld-linux-x86-64.so.2 $LFS/lib64; ln -sfv ../lib/ld-linux-x86-64.so.2 $LFS/lib64/ld-lsb-x86-64.so.3 ;; esac
patch -Np1 -i ../glibc-2.36-fhs-1.patch
mkdir -v build
cd build
echo "rootsbindir=/usr/sbin" > configparms
../configure --prefix=/usr --host=$LFS_TGT --build=$(../scripts/config.guess) --enable-kernel=3.2 --with-headers=$LFS/usr/include libc_cv_slibdir=/usr/lib
make
make DESTDIR=$LFS install
sed '/RTLDLIST=/s@/usr@@g' -i $LFS/usr/bin/ldd
echo 'int main(){}' | $LFS_TGT-gcc -xc -
readelf -l a.out | grep ld-linux
$LFS/tools/libexec/gcc/$LFS_TGT/12.2.0/install-tools/mkheaders
Gblic summary: Extracted and entered the folder. Then I created a sym link for LSB complaince/created a compatibility sym link for proper operation of dynamic library loader. Afterwards I applied the FHS patch, created and moved into a dedicated build directory, and ensured that the ldconfig and sln utilities were installed. Then I prepared for compilation (configure Glib's build system to itself be cross-compiled with the cross-linker and cross compiler in $LFS/tools
, compile the library for 3.2+ Linux kernals, use headers recently installed in $LFS/usr/include
, and finally install library in /usr/lib.) Then I compiled/installed the package, as well as fixing the hardcoded path to the exec loader in ldd script. I THEN DID THE SANITY CHECK (SEE SCREENSHOT BELOW, DIFFERS FROM BOOK ACCORDING TO ERRATA) and finalized the installation of the limits.h header.
Sanity check screenshot:
Libstdc++ (from $LFS/sources)
cd gcc
mkdir -v build2
cd build2
../libstdc++-v3/configure --host=$LFS_TGT --build=$(../config.guess)--prefix=/usr --disable-multilib --disable-nls --disable-libstdcxx-pch--with-gxx-include-dir=/tools/$LFS_TGT/include/c++/12.2.0
make
make DESTDIR=$LFS install
rm -v $LFS/usr/lib/lib{stdc++,stdc++fs,supc++}.la
Libstdc++ summary: Entered the GCC folder, created a new build folder, prepared for compilation (specified to use newly created cross compiler, prevented installation of precompiled files, installed directory for include files.) With the packaged configured I compiled/installed the packaged. Finally I removed the libtool archive files.
With all of this complete, the following test should work (see screenshot, MUST BE IN THE SAME DIRECTORY, milestone2.cpp
must be filled with that information before running commands!):
Later, I would cleanup the extracted directories (NOT GBLIC) with the following commands from $LFS/sources
:
rm -rf binutils
rm -rf gcc
rm -rf linux-5.19.2
Chapter 6. Cross Compiling Temporary Tools
In this chapter, I cross-compiled basic utilities using my the previously built cross-toolchain. All commands for building the basic utilities start in $LFS/sources
unless otherwise specified. Below is the build commands I ran for each utility:
M4-1.4.19:
tar -xf m4-1.4.19.tar.xz
cd m4-1.4.19
./configure --prefix=/usr --host=$LFS_TGT --build=$(build-aux/config.guess)
make
make DESTDIR=$LFS install
Ncurses-6.3:
tar -xf ncurses-6.3.tar.xz
cd ncurses-6.3
sed -i s/mawk// configure
mkdir build
pushd build
../configure
make -C include
make -C progs tic
popd
./configure --prefix=/usr --host=$LFS_TGT --build=$(./config.guess) --mandir=/usr/share/man --with-manpage-format=normal --with-shared --without-normal --with-cxx-shared --without-debug --without-ada --disable-stripping --enable-widec
make
make DESTDIR=$LFS TIC_PATH=$(pwd)/build/progs/tic install
echo "INPUT(-lncursesw)" > $LFS/usr/lib/libncurses.so
Bash-5.1.16:
tar -xf bash-5.1.16.tar.gz
cd bash-5.1.16
./configure --prefix=/usr --build=$(support/config.guess) --host=$LFS_TGT --without-bash-malloc
make
make DESTDIR=$LFS install
ln -sv bash $LFS/bin/sh
Coreutils-9.1:
tar -xf coreutils-9.1.tar.xz
cd coreutils-9.1
./configure --prefix=/usr --host=$LFS_TGT --build=$(build-aux/config.guess) --enable-install-program=hostname --enable-no-install-program=kill,uptime
make
make DESTDIR=$LFS install
mv -v $LFS/usr/bin/chroot $LFS/usr/sbin
mkdir -pv $LFS/usr/share/man/man8
mv -v $LFS/usr/share/man/man1/chroot. $LFS/usr/share/man/man8/chroot.8
sed -i 's/"1"/"8"/ $LFS/usr/share/man/man8/chroot.8
Diffutils-3.8:
tar -xf diffutils-3.8.tar.xz
cd diffutils-3.8
./configure --prefix=/usr --host=$LFS_TGT
make
make DESTDIR=$LFS install
File-5.42:
tar -xf file-5.42.tar.gz
cd file-5.42
mkdir build
pushd build
../configure --disable-bzlib --disable-libseccomp --disable-xzlib --disable-zlib
make
popd
./configure --prefix=/usr --host=$LFS_TGT --build=$(./config.guess)
make FILE_COMPILE=$(pwd)/build/src/file
make DESTDIR=$LFS install
rm -v $LFS/usr/lib/libmagic.la
Findutils-4.9.0:
tar -xf findutils-4.9.0.tar.xz
cd findutils-4.9.0
./configure --prefix=/usr --localstatedir=/var/lib/locate --host=$LFS_TGT --build=$(build-aux/config.guess)
make
make DESTDIR=$LFS install
Gawk-5.1.1:
tar -xf gawk-5.1.1.tar.xz
cd gawk-5.1.1
sed -i 's/extras//' Makefile.in
./configure --prefix=/usr --host=$LFS_TGT --build=$(build-aux/config.guess)
make
make DESTDIR=$LFS install
Grep-3.7:
tar -xf grep-3.7.tar.xz
cd grep-3.7
./configure --prefix=/usr --host=$LFS_TGT
make
make DESTDIR=$LFS install
Gzip-1.12:
tar -xf gzip-1.12.tar.xz
cd gzip-1.12
./configure --prefix=/usr --host=$LFS_TGT
make
make DESTDIR=$LFS install
Make-4.3:
tar -xf make-4.3.tar.gz
cd make-4.3
./configure --prefix=/usr --host=$LFS_TGT --build=$(./config.guess) --mandir=/usr/share/man --with-manpage-format=normal --with-shared --without-normal --with-cxx-shared --without-debug --without-ada --disable-stripping --enable-widec
make
make DESTDIR=$LFS install
Patch-2.7.6:
tar -xf patch-2.7.6.tar.gz
cd patch-2.7.6
./configure --prefix=/usr --host=$LFS_TGT --build=$(build-aux/config.guess)
make
make DESTDIR=$LFS install
Sed-4.8:
tar -xf sed-4.8.tar.gz
cd sed-4.8
./configure --prefix=/usr --host=$LFS_TGT
make
make DESTDIR=$LFS install
Tar-1.34:
tar -xf tar-1.34.tar.gz
cd tar-1.34
./configure --prefix=/usr --host=$LFS_TGT --build=$(build-aux/config.guess)
make
make DESTDIR=$LFS install
Xz-5.2.6:
tar -xf xz-5.2.6.tar.gz
cd xz-5.2.6
./configure --prefix=/usr --host=$LFS_TGT --build=$(build-aux/config.guess) --disable-static --docdir=/usr/share/doc/xz-5.2.6
make
make DESTDIR=$LFS install
rm -v $LFS/usr/lib/liblzma.la
Binutils-2.39 - Pass 2:
tar -xf binutils-2.39.tar.gz
cd binutils-2.39
sed '6009s/$add_dir//' -i ltmain.sh
mkdir -v build
cd build
../configure --prefix=/usr --build=$(../config.guess) --host=$LFS_TGT --disable-nls --enable-shared --enable-gprofng=no --disable-werror --enable-64-bit-bfd
make
make DESTDIR=$LFS install
rm -v $LFS/usr/lib/lib{bfd,ctf,ctf-nobfd,opcodes}.{a,la}
GCC-12.2.0 - Pass 2:
tar -xf gcc-12.2.0.tar.gz
cd gcc-12.2.0
tar -xf ../mpfr-4.1.0.tar.xz
mv -v mpfr-4.1.0 mpfr
tar -xf ../gmp-6.2.1.tar.xz
mv -v gmp-6.2.1 gmp
tar -xf ../mpc-1.2.1.tar.gz
mv -v mpc-1.2.1 mpc
case $(uname -m) in x86_64) sed -e '/m64=/s/lib64/lib/' -i.orig gcc/config/i386/t-linux64 ;; esac
sed '/thread_header =/s/@.*@/gthr-posix.h/' -i libgcc/Makefile.in libstdc++-v3/include/Makefile.in
mkdir -v build
cd build
../configure --build=$(../config.guess) --host=$LFS_TGT --target=$LFS_TGT LDFLAGS_FOR_TARGET=-L$PWD/$LFS_TGT/libgcc --prefix=/usr --with-build-sysroot=$LFS --enable-initfini-array --disable-nls --disable-multilib --disable-decimal-float --disable-libatomic --disable-libgomp --disable-libquadmath --disable-libssp --disable-libvtv --enable-languages=c,c++
make
make DESTDIR=$LFS install
ln -sv gcc $LFS/usr/bin/cc
(NOTE: I originally messed up this step and needed to re-run the ../configure
command, the run make distclean
and the run make
and the commands required below.)
Chapter 7. Entering Chroot and Building Additional Temporary Tools
In this chapter, I built the remaining missing bits of the temp system (tools needed by build machinery.) I also made use of a "chroot" environment for building. Until inside the chroot environment, all commands I run are as root.
First I changed the ownership of $LFS/*
directories to root to prevent possible malicious manipulation with the lfs user with the commands:
chown -R root:root $LFS/{usr,lib,var,etc,bin,sbin,tools}
case $(uname -m) in x86_64) chown -R root:root $LFS/lib64 ;; esac
And then I used the following command to create directories for the file systems to be mounted:
mkdir -pv $LFS/{dev,proc,sys,run}
With those set, I manually mounted and populated /dev on the new system with bind mounting the MOTHERSHIP's /dev directory with the command.
mount -v --bind /dev $LFS/dev
I then used the following commands to mount the virtual kernel filesystems not already set:
mount -v --bind /dev/pts $LFS/dev/pts
mount -vt proc proc $LFS/proc
mount -vt sysfs sysfs $LFS/sys
mount -vt tmpfs tmpfs $LFS/run
I also used the following command to create a needed directory if /dev/shm
is a sym link to /run/shm
:
if [ -h $LFS/dev/shm ]; then mkdir -pv $LFS/$(readlink $LFS/dev/shm); fi
I then needed to re-set my sym link for $LFS/lib64/ld-linux-x86-64.so.2
since it had not been made earlier, this is a departure from the book as the link was SUPPOSED to be made earlier, but for some reason had not in my case (misspelling?) I did this with the following command (run from $LFS/lib64
):
ln -sfv ../lib/ld-linux-x86-64.so.2 $LFS/lib64
With my link re-set, I could use the following command to enter the chroot environment!:
chroot "$LFS" /usr/bin/env -i \
HOME=/root \
TERM="$TERM" \
PS1='(lfs chroot) \u:\w\$ ' \
PATH=/usr/bin:/usr/sbin \
/bin/bash --login
Screenshots showing the link process/chroot working:
(NOTE: If I wanted to shutdown MOTHERSHIP now, I would need to re-mount the bind mount for /dev and the other unmounted virtual kernel filesystems!!!)
From here, all commands run will be inside the chroot environment!
Then I created some root-level directories needed with the command:
mkdir -pv /{boot,home,mnt,opt,srv}
Afterwards I created the required subdirectories below root level with the following commands:
mkdir -pv /etc/{opt,sysconfig}
mkdir -pv /lib/firmware
mkdir -pv /media/{floppy,cdrom}
mkdir -pv /usr/{,local/}{include,src}
mkdir -pv /usr/local/{bin,lib,sbin}
mkdir -pv /usr/{,local/}share/{color,dict,doc,info,locale,man}
mkdir -pv /usr/{,local/}share/{misc,terminfo,zoneinfo}
mkdir -pv /usr/{,local/}share/man/man{1..8}
mkdir -pv /var/{cache,local,log,mail,opt,spool}
mkdir -pv /var/lib/{color,misc,locate}
ln -sfv /run /var/run
ln -sfv /run/lock /var/lock
install -dv -m 0750 /root
install -dv -m 1777 /tmp /var/tmp
I then created a sym link to satisify utilities that expect /etc/mtab
to be present:
ln -sv /proc/self/mounts /etc/mtab
After that, I created a basic /etc/hosts
file with the commands:
cat > /etc/hosts << EOF
127.0.0.1 localhost $(hostname)
::1 localhost
EOF
And I created a /etc/passwd
file and a /etc/group
file for the user "root" to be able to login with the commands:
# /etc/passwd
cat > /etc/passwd << "EOF"
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/dev/null:/usr/bin/false
daemon:x:6:6:Daemon User:/dev/null:/usr/bin/false
messagebus:x:18:18:D-Bus Message Daemon User:/run/dbus:/usr/bin/false
systemd-journal-gateway:x:73:73:systemd Journal Gateway:/:/usr/bin/false
systemd-journal-remote:x:74:74:systemd Journal Remote:/:/usr/bin/false
systemd-journal-upload:x:75:75:systemd Journal Upload:/:/usr/bin/false
systemd-network:x:76:76:systemd Network Management:/:/usr/bin/false
systemd-resolve:x:77:77:systemd Resolver:/:/usr/bin/false
systemd-timesync:x:78:78:systemd Time Synchronization:/:/usr/bin/false
systemd-coredump:x:79:79:systemd Core Dumper:/:/usr/bin/false
uuidd:x:80:80:UUID Generation Daemon User:/dev/null:/usr/bin/false
systemd-oom:x:81:81:systemd Out Of Memory Daemon:/:/usr/bin/false
nobody:x:65534:65534:Unprivileged User:/dev/null:/usr/bin/false
EOF
# /etc/group
cat > /etc/group << "EOF"
root:x:0:
bin:x:1:daemon
sys:x:2:
kmem:x:3:
tape:x:4:
tty: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:
adm:x:16:
messagebus:x:18:
systemd-journal:x:23:
input:x:24:
mail:x:34:
kvm:x:61:
systemd-journal-gateway:x:73:
systemd-journal-remote:x:74:
systemd-journal-upload:x:75:
systemd-network:x:76:
systemd-resolve:x:77:
systemd-timesync:x:78:
systemd-coredump:x:79:
uuidd:x:80:
systemd-oom:x:81:
wheel:x:97:
users:x:999:
nogroup:x:65534:
EOF
I also added a temporary regular user with the following commands:
echo "tester:x:101:101::/home/tester:/bin/bash" >> /etc/passwd
echo "tester:x:101:" >> /etc/group
install -o tester -d /home/tester
Afterwards I initialized the log files, with proper permissions, with the commands:
touch /var/log/{btmp,lastlog,faillog,wtmp}
chgrp -v utmp /var/log/lastlog
chmod -v 664 /var/log/lastlog
chmod -v 600 /var/log/btmp
Next I built several additional temporary tools (all while in chroot/starting in the /sources
directory). Below is the commands that I ran for each tool:
Gettext (in chroot enviro: /sources):
tar -xf gettext-0.21.tar.xz
cd gettext-0.21
./configure --disable-shared
make
cp -v gettext-tools/src/{msgfmt,msgmerge,xgettext} /usr/bin
Bison (in chroot enviro: /sources):
tar -xf bison-3.8.2.tar.xz
cd bison-3.8.2
./configure --prefix=/usr --docdir=/usr/share/doc/bison-3.8.2
make
make install
Perl (in chroot enviro: /sources):
tar -xf perl-5.36.0.tar.xz
cd perl-5.36.0
sh Configure -des -Dprefix=/usr -Dvendorprefix=/usr -Dprivlib=/usr/lib/perl5/5.36/core_perl -Darchlib=/usr/lib/perl5/5.36/core_perl -Dsitelib=/usr/lib/perl5/5.36/site_perl -Dsitearch=/usr/lib/perl5/5.36/site_perl -Dvendorlib=/usr/lib/perl5/5.36/vendor_perl -DVendorarch=/usr/lib/perl5/5.36/vendor_perl
make
make install
Python (in chroot enviro: /sources):
tar -xf Python-3.10.8.tar.xz
cd Python-3.10.8
./configure --prefix=/usr --enable-shared --without-ensurepip
make
make install
Texinfo (in chroot enviro: /sources):
tar -xf texinfo-6.8.tar.xz
cd texinfo-6.8
./configure --prefix=/usr
make
make install
Util-linux (in chroot enviro: /sources):
tar -xf util-linux-2.38.1.tar.xz
cd util-linux-2.38.1
mkdir -pv /var/lib/hwclock
./configure ADJTIME_PATH=/var/lib/hwclock/adjtime --libdir=/usr/lib --docdir=/usr/share/doc/util-linux-2.38.1 --disable-chfn-csh --disable-login --disable-nologin --disable-su --disable-setpriv --disable-runuser --disable-pylibmount --disable-static --without-python runstatedir=/run
make
make install
Then I cleaned up the system by (commands underneath):
- Removing the installed documentatoin
rm -rf /usr/share/{info,man,doc}/*
- Removing the libtool .la files
find /usr/{lib,libexec} -name \*.la -delete
- Removing the
/tools
directory
rm -rf /tools
- Removing the extracted directories created in chapter 6/7 (book did this as building, decided to do it at the end to prevent accidental deletion)
find /sources/ -maxdepth 1 | egrep '[^z][:digit:](/Oliver-Mustoe/Oliver-Mustoe-Tech-Journal/wiki/:digit:)$' | xargs rm -r
I also decided to not backup, but did take a snapshot.
With this, I can go into my chroot environment (where it will tell me im root) and can see the system size is around 2GB after cleaning (df -h
) as seen in the screenshot below:
Chapter 8. Installing Basic System Software
NOTE: To avoid confusion in this and later chapters, all commands run until the logout sequence in chapter 11 are run in the chroot environment UNLESS SPECIFIED! So when referring to "/etc" for example, I am referring to "/mnt/lfs/etc".
In this chapter, I installed all of the software for my LFS system. Below includes the packages name, and the build instructions (All start in chroot "/sources", extracting package, navigating into the folder, preparing for compilation, compiling, making sure compilation is successful with test suite, and install) for the package. Some packages contain instructions that are wildly outside of this scope and if that is the case then instructions are provided in the code in the form of comments/explanations below the code:
Man-pages-5.13:
tar -xf man-pages-5.13.tar.xz
cd man-pages-5.13
make prefix=/usr install
Iana-Etc-20220812:
tar -xf iana-etc-20220812.tar.gz
cd iana-etc-20220812
cp services protocols /etc
Glibc-2.36
tar -xf glibc-..tar.xz
cd glibc-.
patch -Np -i ../glibc-.-fhs-.patch
mkdir -v build
cd build
echo "rootsbindir=/usr/sbin" > configparms
../configure --prefix=/usr --disable-werror --enable-kernel=. --enable-stack-protector=strong --with-headers=/usr/include libc_cv_slibdir=/usr/lib
make
# Test suite/skip unneeded activities
make check
touch /etc/ld.so.conf
sed '/test-installation/s@$(PERL)@echo not running@' -i ../Makefile
# Install
make install
# Fix hardcoded path to executable loader in “ldd” script
sed '/RTLDLIST=/s@/usr@@g' -i /usr/bin/ldd
# Install config file and runtime directory for “nscd”
cp -v ../nscd/nscd.conf /etc/nscd.conf
mkdir -pv /var/cache/nscd
# Install systemd support files for “nscd”
install -v -Dm644 ../nscd/nscd.tmpfiles /usr/lib/tmpfiles.d/nscd.conf
install -v -Dm644 ../nscd/nscd.service /usr/lib/systemd/system/nscd.service
# Decided to install all locales found in “glibc-2.36/localedata/SUPPORTED” / some not in SUPPORTED for later tests
make localedata/install-locales
localedef -i POSIX -f UTF-8 C.UTF-8 2> /dev/null || true
localedef -i ja_JP -f SHIFT_JIS ja_JP.SJIS 2> /dev/null || true
# Create new nsswitch.conf
cat > /etc/nsswitch.conf << "EOF"
# Begin /etc/nsswitch.conf
passwd: files
group: files
shadow: files
hosts: files dns
networks: files
protocols: files
services: files
ethers: files
rpc: files
# End /etc/nsswitch.conf
EOF
# Setup and install time zone data
tar -xf ../../tzdata2022c.tar.gz
ZONEINFO=/usr/share/zoneinfo
mkdir -pv $ZONEINFO/{posix,right}
for tz in etcetera southamerica northamerica europe africa antarctica \
asia australasia backward; do
zic -L /dev/null -d $ZONEINFO ${tz}
zic -L /dev/null -d $ZONEINFO/posix ${tz}
zic -L leapseconds -d $ZONEINFO/right ${tz}
done
cp -v zone.tab zone1970.tab iso3166.tab $ZONEINFO
zic -d $ZONEINFO -p America/New_York
unset ZONEINFO
# Determine timezone (outside of chroot)/set “localtime” file (“America/New_York” would be changed if in different zone)
timedatectl
ln -sfv /usr/share/zoneinfo/America/New_York /etc/localtime
# Add needed directories to dynamic loader’s search path
cat > /etc/ld.so.conf << "EOF"
# Begin /etc/ld.so.conf
/usr/local/lib
/opt/lib
EOF
# Extra capabilities not added
Zlib-1.2.12:
tar -xf zlib-1.2.13.tar.xz
cd zlib-1.2.13
./configure --prefix=/usr
make
make check
make install
rm -fv /usr/lib/libz.a
Bzip2-1.0.8:
patch -Np1 -i ../bzip2-1.0.8-install_docs-1.patch
sed -i 's@\(ln -s -f \)$(PREFIX)/bin/@\1@' Makefile
sed -i "s@(PREFIX)/man@(PREFIX)/share/man@g" Makefile
make -f Makefile-libbz2_so
make clean
make
make PREFIX=/usr install
cp -av libbz2.so.* /usr/lib
ln -sv libbz2.so.1.0.8 /usr/lib/libbz2.so
cp -v bzip2-shared /usr/bin/bzip2
for i in /usr/bin/{bzcat,bunzip2}; do ln -sfv bzip2 $i; done
rm -fv /usr/lib/libbz2.a
Xz-5.2.6:
tar -xf xz-5.2.6.tar.xz
cd xz-5.2.6
./configure --prefix=/usr --disable-static --docdir=/usr/share/doc/xz-5.2.6
make
make check
make install
Zstd-1.5.2:
tar -xf zstd-1.5.2.tar.gz
cd zstd-1.5.2
patch -Np1 -i ../zstd-1.5.2-upstream_fixes-1.patch
make prefix=/usr
make check
make prefix=/usr install
rm -v /usr/lib/libzstd.a
File-5.42:
tar -xf file-5.42.tar.gz
cd file-5.42
./configure --prefix=/usr
make
make check
make install
Readline-8.1.2
tar -xf readline-8.1.2.tar.gz
cd readline-8.1.2
sed -i '/MV.*old/d' Makefile.in
sed -i '/{OLDSUFF}/c:' support/shlib-install
./configure --prefix=/usr --disable-static --with-curses --docdir=/usr/share/doc/readline-8.1.2
make SHLIB_LIBS="-lncursesw"
make SHLIB_LIBS="-lncursesw" install
M4-1.4.19:
tar -xf m4-1.4.19.tar.xz
cd m4-1.4.19
./configure --prefix=/usr
make
make check
make install
Bc-6.0.1:
tar -xf bc-6.0.1.tar.xz
cd bc-6.0.1
CC=gcc ./configure --prefix=/usr -G -O3 -r
make
make test
make install
Flex-2.6.4:
tar -xf flex-2.6.4.tar.gz
cd flex-2.6.4
./configure --prefix=/usr --docdir=/usr/share/doc/flex-2.6.4 --disable-static
make
make check
make install
ln -sv flex /usr/bin/lex
Tcl-8.6.12:
tar -xf tcl8.6.12-src.tar.gz
cd tcl8.6.12
tar -xf ../tcl8.6.12-html.tar.gz --strip-components=1
SRCDIR=$(pwd)
cd unix
./configure --prefix=/usr --mandir=/usr/share/man
Make
# Remove references to the build directory
sed -e "s|$SRCDIR/unix/pkgs/tdbc1.1.3|/usr/lib/t|" -e "s|$SRCDIR|/usr/include|" -i tclConfig.sh
sed -e "s|$SRCDIR/unix/pkgs/tdbc1.1.3|/usr/lib/tdbc1.1.3|" -e "s|$SRCDIR/pkgs/tdbc1.1.3/generic|/usr/include|" -e "s|$SRCDIR/pkgs/tdbc1.1.3/library|/usr/lib/tcl8.6|" -e "s|$SRCDIR/pkgs/tdbc1.1.3|/usr/include|" -i pkgs/tdbc1.1.3/tdbcConfig.sh
sed -e "s|$SRCDIR/unix/pkgs/itcl4.2.2|/usr/lib/itcl4.2.2|" -e "s|$SRCDIR/pkgs/itcl4.2.2/generic|/usr/include|" -e "s|$SRCDIR/pkgs/itcl4.2.2|/usr/include|" -i pkgs/itcl4.2.2/itclConfig.sh
unset SRCDIR
#
make test
make install
# Make installed directory writable so debugging symbols can be removed
chmod -v u+w /usr/lib/libtcl8.6.so
#
# Install Tcl headers
make install-private-headers
#
ln -sfv tclsh8.6 /usr/bin/tclsh
# Rename for Perl man conflict
mv /usr/share/man/man3/{Thread,Tcl_Thread}.3
# Install documentation
mkdir -v -p /usr/share/doc/tcl-8.6.12
cp -v -r ../html/* /usr/share/doc/tcl-8.6.12
Expect-5.45.4:
tar -xf expect5.45.4.tar.gz
cd expect5.45.4
./configure --prefix=/usr --with-tcl=/usr/lib --enable-share --mandir=/usr/share/man --with-tclinclude=/usr/include
make
make test
make install
ln -svf expect5.45.4/libexpect5.45.4.so /usr/lib
DejaGNU-1.6.3:
tar -xf dejagnu-1.6.3.tar.gz
cd dejagnu-1.6.3
mkdir -v build
cd build
../configure --prefix=/usr
makeinfo --html --no-split -o doc/dejagnu.html ../doc/dejagnu.texi
makeinfo --plaintext -o doc/dejagnu.txt ../doc/dejagnu.texi
make install
install -v -dm755 /usr/share/doc/dejagnu-1.6.3
install -v -m644 doc/dejagnu.{html,txt} /usr/share/doc/dejagnu-1.6.3
make check
Binutils-2.39:
tar -xf binutils-2.39.tar.xz
cd binutils-2.39
expect -c "spawn ls"
# STOP HERE, IF THE ABOVE COMMAND DOES NOT YIELD “spawn ls” THEN SOMETHING IS WRONG
mkdir -v build
cd build
../configure --prefix=/usr --sysconfdir=/etc --enable-gold --enable-ld=default --enable-plugins --enable-shared --disable-werror --enable-64-bit-bfd --with-system-zlib
make tooldir=/usr
make -k check
make tooldir=/usr install
rm -fv /usr/lib/lib{bfd,ctf,ctf-nobfd,opcodes}.a
**BINUTILS NOTE: Got the following error when trying to test the results (make -k check
):
ERROR: compilation of test program in jsynprog failed
ERROR: comparison of results in mttest failed
Tried restarting the build (from tar -xf
) but still got the same issue, but according to this forum post, and the following LFS build logs, this does not seem to be an issue:
https://www.linuxfromscratch.org/lfs/build-logs/11.2/i7-1065G7/test-logs/816-binutils-2.39
https://www.linuxfromscratch.org/lfs/build-logs/11.2/Intel-CoreDuo-T2600/test-logs/816-binutils-2.39
https://www.linuxfromscratch.org/lfs/build-logs/11.2/AMD3900X/test-logs/816-binutils-2.39
Binutils expect test output (picture taken after install, worked before as per LFS instructions):
Here also issued the following command to check for all of the folders in the directory, then deleted these built directories with the second command:
find /sources/ -maxdepth 1 | egrep '[^z][:digit:](/Oliver-Mustoe/Oliver-Mustoe-Tech-Journal/wiki/:digit:)$'
find /sources/ -maxdepth 1 | egrep '[^z][:digit:](/Oliver-Mustoe/Oliver-Mustoe-Tech-Journal/wiki/:digit:)$' | xargs rm -r
GMP-6.2.1:
tar -xf gmp-6.2.1.tar.xz
cd gmp-6.2.1
./configure --prefix=/usr --enable-cxx --disable-static --docdir=/usr/share/doc/gmp-6.2.1
make
make html
make check 2>&1 | tee gmp-check-log
awk '/# PASS:/{total+=$3}; END{print total}' gmp-check-log
make install
make install-html
MPFR-4.1.0:
tar -xf mpfr-4.1.0.tar.xz
cd mpfr-4.1.0
./configure --prefix=/usr --disable-static --enable-thread-safe --docdir=/usr/share/doc/mpfr-4.1.0
make
make html
make check
make install
make install-html
MPC-1.2.1:
tar -xf mpc-1.2.1.tar.gz
cd mpc-1.2.1
./configure --prefix=/usr --disable-static --docdir=/usr/share/doc/mpc-1.2.1
make
make html
make check
make install
make install-html
Attr-2.5.1:
tar -xf attr-2.5.1.tar.gz
cd attr-2.5.1
./configure --prefix=/usr --disable-static --sysconfdir=/etc --docdir=/usr/share/doc/attr-2.5.1
make
make check
make install
Acl-2.3.1:
tar -xf acl-2.3.1.tar.xz
cd acl-2.3.1
./configure --prefix=/usr --disable-static --docdir=/usr/share/doc/acl-2-3-1
make
make install
Libcap-2.65:
tar -xf libcap-2.65.tar.xz
cd libcap-2.65
sed -i '/install -m.*STA/d' libcap/Makefile
make prefix=/usr lib=lib
make test
make prefix=/usr lib=lib install
Shadow-4.12.2:
tar -xf shadow-4.12.2.tar.xz
cd shadow-4.12.2
# Disable the installation of groups/prevent installation of man pages that already exist
sed -i 's/groups$(EXEEXT) //' src/Makefile.in
find man -name Makefile.in -exec sed -i 's/groups\.1 / /' {} \;
find man -name Makefile.in -exec sed -i 's/getspnam\.3 / /' {} \;
find man -name Makefile.in -exec sed -i 's/passwd\.5 / /' {} \;
#
# Enable SHA-512 encryption/ Change obsolete mailbox location/ Get rid of obsolete symlinks
sed -e 's:#ENCRYPT_METHOD DES:ENCRYPT_METHOD SHA512:' -e 's:/var/spool/mail:/var/mail:' -e '/PATH=/{s@/sbin:@@;s@/bin:@@}' -i etc/login.defs
#
touch /usr/bin/passwd
./configure --sysconfdir=/etc --disable-static --with-group-name-max-length=32
make
make exec_prefix=/usr install
make -C man install-man
# Enable shadowed passwords
pwconv
#
# Enable shadowed group passwords
grpconv
#
# Create the directory “/etc/default/useradd”
mkdir -p /etc/default
useradd -D --gid 999
#
# Set root password
passwd root
GCC-12.2.0:
tar -xf gcc-12.2.0.tar.xz
cd gcc-12.2.0
# Change directory names for 64-bit libraries to “lib”
case $(uname -m) in x86_64) sed -e '/m64=/s/lib64/lib/' -i.orig gcc/config/i386/t-linux64 ;; esac
mkdir -v build
cd build
../configure --prefix=/usr LD=ld --enable-languages=c,c++ --disable-multilib --disable-bootstrap --with-system-zlib
make
ulimit -s 32768
chown -Rv tester .
su tester -c "PATH=$PATH make -j2 -k check"
# Checked this against https://www.linuxfromscratch.org/lfs/build-logs/11.2/, looked good
../contrib/test_summary | grep -A7 Summ
#
make install
# Changed ownership/ create required symlinks
chown -v -R root:root /usr/lib/gcc/$(gcc -dumpmachine)/12.2.0/include{,-fixed}
ln -svr /usr/bin/cpp /usr/lib
ln -sfv ../../libexec/gcc/$(gcc -dumpmachine)/12.2.0/liblto_plugin.so /usr/lib/bfd-plugins/
# Sanity checks (see below)
echo 'int main(){}' > dummy.c
cc dummy.c -v -Wl,--verbose &> dummy.log
readelf -l a.out | grep ': /lib'
grep -o '/usr/lib.*/crt[1in].*succeeded' dummy.log
grep -B4 '^ /usr/include' dummy.log
grep 'SEARCH.*/usr/lib' dummy.log |sed 's|; |\n|g'
grep "/lib.*/libc.so.6 " dummy.log
grep found dummy.log
rm -v dummy.c a.out dummy.log
# Move a misplaced file
mkdir -pv /usr/share/gdb/auto-load/usr/lib
mv -v /usr/lib/*gdb.py /usr/share/gdb/auto-load/usr/lib
Successful sanity checks:
Here also issued the following command to check for all of the folders in the directory, then deleted these built directories with the second command:
find /sources/ -maxdepth 1 | egrep '[^z][:digit:](/Oliver-Mustoe/Oliver-Mustoe-Tech-Journal/wiki/:digit:)$'
find /sources/ -maxdepth 1 | egrep '[^z][:digit:](/Oliver-Mustoe/Oliver-Mustoe-Tech-Journal/wiki/:digit:)$' | xargs rm -r
Pkg-config-0.29.2:
tar -xf pkg-config-0.29.2.tar.gz
cd pkg-config-0.29.2
./configure --prefix=/usr --with-internal-glib --disable-host-tool --docdir=/usr/share/doc/pkg-config-0.29.2
make
make check
make install
Ncurses-6.3:
tar -xf ncurses-6.3.tar.gz
cd ncurses-6.3
./configure --prefix=/usr --mandir=/usr/share/man --with-shared --without-debug --without-normal --with-cxx-shared --enable-pc-files --enable-pc-files --enable-widec --with-pkg-config-libdir=/usr/lib/pkgconfig
make
# Install a specific package that is needed, remove a useless static archive
make DESTDIR=$PWD/dest install
install -vm755 dest/usr/lib/libncursesw.so.6.3 /usr/lib
rm -v dest/usr/lib/libncursesw.so.6.3
cp -av dest/* /
# Application trick for wide-character libraries with symlinks and linker scripts
for lib in ncurses form panel menu ; do rm -vf /usr/lib/lib${lib}.so; echo "INPUT(-l${lib}w)" > /usr/lib/lib${lib}.so; ln -sfv ${lib}w.pc /usr/lib/pkgconfig/${lib}.pc; done
rm -vf /usr/lib/libcursesw.so
echo "INPUT(-lncursesw)" > /usr/lib/libcursesw.so
ln -sfv libncurses.so /usr/lib/libcurses.so
mkdir -pv /usr/share/doc/ncurses-6.3
cp -v -R doc/* /usr/share/doc/ncurses-6.3
Sed-4.8:
tar -xf sed-4.8.tar.xz
cd sed-4.8
./configure --prefix=/usr
make
make html
chown -Rv tester .
su tester -c "PATH=$PATH make check"
make install
install -d -m755 /usr/share/doc/sec-4.8
install -m644 doc/sed.html /usr/share/doc/sed-4.8
Psmisc-23.5:
tar -xf psmisc-23.5.tar.xz
cd psmisc-23.5
./configure --prefix=/usr
make
make install
Gettext-0.21:
tar -xf gettext-0.21.tar.xz
cd gettext-0.21
./configure --prefix=/usr --disable-static --docdir=/usr/share/doc/gettext-0.21
make
make check
make install
chmod -v 0755 /usr/lib/preloadable_libintl.so
Bison-3.8.2:
tar -xf bison-3.8.2.tar.xz
cd bison-3.8.2
./configure --prefix=/usr --docdir=/usr/share/doc/bison-3.8.2
make
make install
Grep-3.7:
tar -xf grep-3.7.tar.xz
cd grep-3.7
./configure --prefix=/usr
make
make check
make install
Bash-5.1.16:
tar -xf bash-5.1.16.tar.gz
cd bash-5.1.16
./configure --prefix=/usr --docdir=/usr/share/doc/bash-5.1.16
make
make install
exec /usr/bin/bash --login
Libtool-2.4.7:
tar -xf libtool-2.4.7.tar.xz
cd libtool-2.4.7
./configure --prefix=/usr
make
make install
rm -fv /usr/lib/libltdl.a
GDBM-1.23:
tar -xf libtool-2.4.7.tar.xz
cd libtool-2.4.7
./configure --prefix=/usr
make
make install
rm -fv /usr/lib/libltdl.a
Gperf-3.1:
tar -xf gdbm-1.23.tar.gz
cd gdbm-1.23
./configure --prefix=/usr --disable-static --enable-libgdbm-compat
make
make check
make install
Expat-2.4.8:
tar -xf expat-2.5.0.tar.xz
cd expat-2.5.0
./configure --prefix=/usr --disable-static --docdir=/usr/share/doc/expat-2.5.0
make
make check
make install
Inetutils-2.3:
tar -xf inetutils-2.3.tar.xz
cd inetutils-2.3
./configure --prefix=/usr --bindir=/usr/bin --localstatedir=/var --disable-logger --disable-whois --disable-rcp --disable-rexec --disable-rlogin --disable-rsh --disable-servers
make
make check
make install
mv -v /usr/{,s}bin/ifconfig
Less-590:
tar -xf less-590.tar.gz
cd less-590
./configure --prefix=/usr --sysconfdir=/etc
make
make install
Perl-5.36.0:
tar -xf perl-5.36.0.tar.xz
cd perl-5.36.0
export BUILD_ZLIB=False
export BUILD_BZIP2=0
sh Configure -des -Dprefix=/usr -Dvendorprefix=/usr -Dprivlib=/usr/lib/perl5/5.36/core_perl -Darchlib=/usr/lib/perl5/5.36/core_perl -Dsitelib=/usr/lib/perl5/5.36/site_perl -Dsitearch=/usr/lib/perl5/5.36/site_perl -Dvendorlib=/usr/lib/perl5/5.36/vendor_perl -Dvendorarch=/usr/lib/perl5/5.36/vendor_perl -Dman1dir=/usr/share/man/man1 -Dman3dir=/usr/share/man/man3 -Dpager="/usr/bin/less -isR" -Duseshrplib -Dusethreads
make
make test
make install
unset BUILD_ZLIB BUILD_BZIP2
XML::Parser-2.46:
tar -xf XML-Parser-2.46.tar.gz
cd XML-Parser-2.46
perl Makefile.PL
make
make test
make install
Intltool-0.51.0:
tar -xf intltool-0.51.0.tar.gz
cd intltool-0.51.0
sed -i 's:\\\${:\\\$\\{:' intltool-update.in
./configure --prefix=/usr
make
make check
make install
install -v -Dm644 doc/I18N-HOWTO /usr/share/doc/intltool-0.51.0/I18N-HOWTO
Autoconf-2.71:
tar -xf autoconf-2.71.tar.xz
cd autoconf-2.71
./configure --prefix=/usr
make
make check TESTSUITEFLAGS=-j2
make install
Automake-1.16.5:
tar -xf automake-1.16.5.tar.xz
cd automake-1.16.5
./configure --prefix=/usr --docdir=/usr/share/doc/automake-1.16.5
make
make -j4 check
make install
OpenSSL-3.0.5:
tar -xf openssl-3.0.5.tar.gz
cd openssl-3.0.5
./config --prefix=/usr --openssldir=/etc/ssl --libdir=lib shared zlib-dynamic
make
make test
sed -i '/INSTALL_LIBS/s/libcrypto.a libssl.a//' Makefile
make MANSUFFIX=ssl install
mv -v /usr/share/doc/openssl /usr/share/doc/openssl-3.0.5
Kmod-30:
tar -xf kmod-30.tar.xz
cd kmod-30
./configure --prefix=/usr --sysconfdir=/etc --with-openssl --with-xz --with-zstd --with-zlib
make
make install
for target in depmod insmod modinfo modprobe rmmod; do ln -sfv ../bin/kmod /usr/sbin/$target; done
ln -sfv kmod /usr/bin/lsmod
Libelf from Elfutils-0.187:
tar -xf elfutils-0.187.tar.bz2
cd elfutils-0.187
./configure --prefix=/usr --disable-debuginfod --enable-libdebuginfod=dummy
make
make check
make -C libelf install
install -vm644 config/libelf.pc /usr/lib/pkgconfig
rm /usr/lib/libelf.a
Libffi-3.4.2:
tar -xf libffi-3.4.2.tar.gz
cd libffi-3.4.2
./configure --prefix=/usr --disable-static --with-gcc-arch=native --disable-exec-static-tramp
make
make check
make install
Python-3.10.8:
# NOTE - Had to reinstall this once (did the same commands up until “make install”. I also did not install the documentation)
tar -xf Python-3.10.8.tar.xz
cd Python-3.10.8
./configure --prefix=/usr --enable-shared --with-system-expat --with-system-ffi --enable-optimizations
make
make install
cat > /etc/pip.conf << EOF
[global]
root-user-action = ignore
disable-pip-version-check = true
EOF
Wheel-0.37.1:
tar -xf wheel-0.37.1.tar.gz
cd wheel-0.37.1
pip3 install --no-index $PWD
Ninja-1.11.0:
tar -xf ninja-1.11.0.tar.gz
cd ninja-1.11.0
sed -i '/int Guess/a \
int j = 0;\
char* jobs = getenv( "NINJAJOBS" );\
if ( jobs != NULL ) j = atoi( jobs );\
if ( j > 0 ) return j;\
' src/ninja.cc
python3 configure.py --bootstrap
./ninja ninja_test
./ninja_test --gtest_filter=-SubprocessTest.SetWithLots
install -vm755 ninja /usr/bin/
install -vDm644 misc/bash-completion /usr/share/bash-completion/completions/ninja
install -vDm644 misc/zsh-completion /usr/share/zsh/site-functions/_ninja
Meson-0.63.1:
tar -xf meson-0.63.1.tar.gz
cd meson-0.63.1
pip3 wheel -w dist --no-build-isolation --no-deps $PWD
pip3 install --no-index --find-links dist meson
install -vDm644 data/shell-completions/bash/meson /usr/share/bash-completion/completions/meson
install -vDm644 data/shell-completions/zsh/meson /usr/share/zsh/site-functions/_meson
install -vDm644 data/shell-completions/zsh/_meson /usr/share/zsh/site-functions/_meson
Coreutils-9.1:
tar -xf coreutils-9.1.tar.xz
cd coreutils-9.1
patch -Np1 -i ../coreutils-9.1-i18n-1.patch
autoreconf -fiv
FORCE_UNSAFE_CONFIGURE=1 ./configure --prefix=/usr --enable-no-install-program=kill,uptime
make
make install
mv -v /usr/bin/chroot /usr/sbin
mv -v /usr/share/man/man1/chroot.1 /usr/share/man/man8/chroot.8
sed -i 's/"1"/"8"/' /usr/share/man/man8/chroot.8
Check-0.15.2:
tar -xf check-0.15.2.tar.gz
cd check-0.15.2
./configure --prefix=/usr --disable-static
make
make check
make docdir=/usr/share/doc/check-0.15.2 install
Diffutils-3.8:
tar -xf diffutils-3.8.tar.xz
cd diffutils-3.8
./configure --prefix=/usr
make
make check
make install
Gawk-5.1.1:
# Did not install documentation
tar -xf gawk-5.1.1.tar.xz
cd gawk-5.1.1
sed -i 's/extras//' Makefile.in
./configure --prefix=/usr
make
make check
make install
Findutils-4.9.0:
rm -rf findutils-4.9.0
tar -xf findutils-4.9.0.tar.xz
cd findutils-4.9.0
case $(uname -m) in i?86) TIME_T_32_BIT_OK=yes ./configure --prefix=/usr --localstatedir=/var/lib/locate ;; x86_64) ./configure --prefix=/usr --localstatedir=/var/lib/locate ;; esac
make
chown -Rv tester .
su tester -c "PATH=$PATH make check"
make install
Groff-1.22.4:
tar -xf groff-1.22.4.tar.gz
cd groff-1.22.4
PAGE=letter ./configure --prefix=/usr
make -j1
make install
GRUB-2.06:
tar -xf grub-2.06.tar.xz
cd grub-2.06
./configure --prefix=/usr --sysconfdir=/etc --disable-efiemu --disable-werror
make
make install
mv -v /etc/bash_completion.d/grub /usr/share/bash-completion/completions
Gzip-1.12:
tar -xf gzip-1.12.tar.xz
cd gzip-1.12
./configure --prefix=/usr
make
make check
make install
IPRoute2-5.19.0:
tar -xf iproute2-5.19.0.tar.xz
cd iproute2-5.19.0
sed -i /ARPD/d Makefile
rm -fv man/man8/arpd.8
make NETNS_RUN_DIR=/run/netns
make SBINDIR=/usr/sbin install
Kbd-2.5.1:
tar -xf kbd-2.5.1.tar.xz
cd kbd-2.5.1
patch -Np1 -i ../kbd-2.5.1-backspace-1.patch
sed -i '/RESIZECONS_PROGS=/s/yes/bo/' configure
sed -i 's/resizecons.8 //' docs/man/man8/Makefile.in
./configure --prefix=/usr --disable-vlock
make
make check
make install
Libpipeline-1.5.6:
tar -xf libpipeline-1.5.6.tar.gz
cd libpipeline-1.5.6
./configure --prefix=/usr
make
make check
make install
Make-4.3:
tar -xf make-4.3.tar.gz
cd make-4.3
./configure --prefix=/usr
make
make check
make install
Patch-2.7.6:
tar -xf patch-2.7.6.tar.xz
cd patch-2.7.6
./configure --prefix=/usr
make
make check
make install
Tar-1.34:
tar -xf tar-1.34.tar.xz
cd tar-1.34
FORCE_UNSAFE_CONFIGURE=1 ./configure --prefix=/usr
make
make check
make install
make -C doc install-html docdir=/usr/share/doc/tar-1.34
Texinfo-6.8:
tar -xf texinfo-6.8.tar.xz
cd texinfo-6.8
./configure --prefix=/usr
make
make check
make install
make TEXMF=/usr/share/texmf install-tex
Vim-9.0.0228:
tar -xf vim-9.0.0228.tar.gz
cd vim-9.0.0228
echo '#define SYS_VIMRC_FILE "/etc/vimrc"' >> src/feature.h
./configure --prefix=/usr
make
chown -Rv tester .
su tester -c "LANG=en_US.UTF-8 make -j1 test" &> vim-test.log
grep 'ALL DONE' vim-test.log
make install
# Create links for typing “vi” in the terminal to summon vim, man page as well. Correct documentation as well.
ln -sv vim /usr/bin/vi
for L in /usr/share/man/{,*/}man1/vim.1; do ln -sv vim.1 $(dirname $L)/vi.1; done
ln -sv ../vim/vim90/doc /usr/share/doc/vim-9.0.0228
VIM test:
MarkupSafe-2.1.1:
tar -xf MarkupSafe-2.1.1.tar.gz
cd MarkupSafe-2.1.1
pip3 wheel -w dist --no-build-isolation --no-deps $PWD
pip3 install --no-index --no-user --find-links dist Markupsafe
Jinja2-3.1.2:
tar -xf Jinja2-3.1.2.tar.gz
cd Jinja2-3.1.2
pip3 wheel -w dist --no-build-isolation --no-deps $PWD
pip3 install --no-index --no-user --find-links dist Jinja2
Systemd-251:
tar -xf systemd-251.tar.gz
cd systemd-251
patch -Np1 -i ../systemd-251-glibc_2.36_fix-1.patch
sed -i -e 's/GROUP="render"/GROUP="video"/' -e 's/GROUP="sgx", //' rules.d/50-udev-default.rules.in
mkdir -p build
cd build
meson --prefix=/usr --buildtype=release -Ddefault-dnssec=no -Dfirstboot=false -Dinstall-tests=false -Dldconfig=false -Dsysusers=false -Drpmmacrosdir=no -Dhomed=false -Duserdb=false -Dman=false -Dmode=release -Dpamconfdir=no -Ddocdir=/usr/share/doc/systemd-251 ..
ninja
ninja install
tar -xf ../../systemd-man-pages-251.tar.xz --strip-components=1 -C /usr/share/man
# Create file for “systemd-journald”
Systemd-machine-id-setup
# Setup basic target structure/Disable service for upgrading binary distros
systemctl preset-all
systemctl disable systemd-sysupdate
D-Bus-1.14.0:
tar -xf dbus-1.14.0.tar.xz
cd dbus-1.14.0
./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var --runstatedir=/run --disable-static --disable-doxygen-docs --disable-xml-docs --docdir=/usr/share/doc/dbus-1.1.14.0 --with-system-socket=/run/dbus/system_bus_socket
make
make install
ln -sfv /etc/machine-id /var/lib/dbus
Man-DB-2.10.2:
tar -xf dbus-1.14.0.tar.xz
cd dbus-1.14.0
./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var --runstatedir=/run --disable-static --disable-doxygen-docs --disable-xml-docs --docdir=/usr/share/doc/dbus-1.1.14.0 --with-system-socket=/run/dbus/system_bus_socket
make
make install
ln -sfv /etc/machine-id /var/lib/dbus
Procps-ng-4.0.0:
tar -xf procps-ng-4.0.0.tar.xz
cd procps-ng-4.0.0
./configure --prefix=/usr --docdir=/usr/share/doc/procps-ng-4.0.0 --disable-static --disable-kill --with-systemd
make
make check
make install
Util-linux-2.38.1:
tar -xf util-linux-2.38.1.tar.xz
cd util-linux-2.38.1
./configure ADJTIME_PATH=/var/lib/hwclock/adjtime --bindir=/usr/bin --libdir=/usr/lib --sbindir=/usr/sbin --docdir=/usr/share/doc/util-linux-2.38.1 --disable-chfn-chsh --disable-login --disable-nologin --disable-su --disable-setpriv --disable-runuser --disable-pylibmount --disable-static --without-python
make
make install
E2fsprogs-1.46.5:
tar -xf e2fsprogs-1.46.5.tar.gz
cd e2fsprogs-1.46.5
mkdir -v build
cd build
../configure --prefix=/usr --sysconfdir=/etc --enable-elf-shlibs --disable-libblkid --disable-libuuid --disable-uuidd --disable-fsck
make
make check
make install
rm -fv /usr/lib/{libcom_err,libe2p,libext2fs,libss}.a
# Unzip and update the system dir file
gunzip -v /usr/share/info/libext2fs.info.gz
install-info --dir-file=/usr/share/info/dir /usr/share/info/libext2fs.info
I would also decide not to strip the debugging symbols. After all of this installation I would issue the following commands to cleanup from building (erasing build directories, removing libtool archive files, and deleting the tester user):
find /sources/ -maxdepth 1 | egrep '[^z][:digit:](/Oliver-Mustoe/Oliver-Mustoe-Tech-Journal/wiki/:digit:)$'
find /sources/ -maxdepth 1 | egrep '[^z][:digit:](/Oliver-Mustoe/Oliver-Mustoe-Tech-Journal/wiki/:digit:)$' | xargs rm -r
rm -rf /tmp/*
find /usr/lib /usr/libexec -name \*.la -delete
userdel -r tester
Chapter 9. System Configuration
In this chapter I configured necessary configuration files and systemd services. NOTE: throughout the chapter, I decided not to disable any systemd services.
I would run the following commands to setup DHCP, my /etc/resolv.conf, my hostname, and a /etc/hosts file. My DHCP configuration was changed when I booted the system and the /etc/hosts config and the hostname was changed in chapter 10 here:
DHCP
cat > /etc/systemd/network/10-eth-dhcp.network << "EOF"
[Match]
Name=ens33
[Network]
DHCP=ipv4
[DHCP]
UseDomains=true
EOF
resolv.conf
cat > /etc/resolv.conf << "EOF"
# Begin
nameserver 8.8.8.8
nameserver 8.8.4.4
# End
EOF
old hostname
echo "LFS" > /etc/hostname
old hosts
cat > /etc/hosts << "EOF"
# Begin
127.0.0.1 localhost.localdomain localhost
127.0.1.1 lfs.example.org LFS
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
# End
EOF
I then checked my system clock with:
Hwclock –locatime –show
And compared it with UTC time and it gained a match (see below), so nothing was needed to be done:
Decided not to configure the console, and set the following for my locale.conf, inputrc, and shells:
locale.conf
cat > /etc/locale.conf << "EOF"
LANG=en_US.utf8
EOF
inputrc
cat > /etc/inputrc << "EOF"
# Begin
# Allow wrap to the next line
set horizontal-scroll-mode Off
# Enable 8-bit input
set meta-flag On
set input-meta On
# Turns off 8th bit stripping
set convert-meta Off
# Keep the 8th bit for display
set output-meta On
# No bell
set bell-style none
# Following maps the escape sequence of the value
# contained in the 1st argument to the readline specific functions
"\eOd": backward-word
"\eOc": forward-word
# Linux console
"\e[1~": beginning-of-line
"\e[4~": end-of-line
"\e[5~": beginning-of-history
"\e[6~": end-of-history
"\e[3~": delete-char
"\e[2~": quoted-insert
# xterm
"\eOH": beginning-of-line
"\eOF": end-of-line
# Konsole
"\e[H": beginning-of-line
"\e[F": end-of-line
# End
shells
cat > /etc/shells << "EOF"
# Begin
/bin/sh
/bin/bash
# End
EOF
I would then leave the default behaviors of systemd intact, such as clearing the screen at boot time.
Chapter 10. Making the LFS System Bootable
In this chapters, I configured the final pieces to make my LFS system bootable.
First I would create a /etc/fstab file with the following commands (since this system will be transported from the mothership onto another VM, used "sda" instead of "sdb". I would also make use of the partition spreadsheet made in chapter 2 and lsblk
to find what goes where.):
cat > /etc/fstab << "EOF"
# Begin
# file system mount-point type options dump fsck
# order
/dev/sda3 / ext4 defaults 1 1
/dev/sda4 /home ext4 defaults 1 1
/dev/sda5 swap swap pri=1 0 0
# End
EOF
I would then install the linux kernel with the commands below from the "/sources" directory:
tar -xf linux-5.19.2.tar.xz
cd linux-5.19.2
# DO KERNEL INSTALL BELOW
make
make modules_install
# Mounted my boot partition
mount /dev/sdb2 /boot
#
cp -iv arch/x86_64/boot/bzImage /boot/vmlinuz-5.19.2-lfs-11.2-systemd
cp -iv System.map /boot/System.map-5.19.2
cp -iv .config /boot/config-5.19.2
install -d /usr/share/doc/linux-5.19.2
cp -r Documentation/* /usr/share/doc/linux-5.19.2
KERNEL INSTALL
Downloaded instructors kernel config from here, then dragged it onto the VM's desktop, then copied it to the right directory with the commands (screenshot shows process):
cp config-5.19.2 .config
sudo cp .config /mnt/lfs/sources/linux-5.19.2/.config
Then I configured the Linux Module Load Order with the commands:
install -v -m755 -d /etc/modprobe.d
cat > /etc/modprobe.d/usb.conf << "EOF"
# Begin /etc/modprobe.d/usb.conf
install ohci_hcd /sbin/modprobe ehci_hcd ; /sbin/modprobe -i ohci_hcd ; true
install uhci_hcd /sbin/modprobe ehci_hcd ; /sbin/modprobe -i uhci_hcd ; true
# End /etc/modprobe.d/usb.conf
EOF
Then I configured GRUB with the commands:
grub-install /dev/sdb
cat > /boot/grub/grub.cfg << "EOF"
# BEGIN GRUB
set default=0
set timeout=5
insmod ext2
set root=(hd0,2)
menuentry "GNU/Linux, Linux 5.19.2-lfs-11.2-systemd" {
linux /vmlinuz-5.19.2-lfs-11.2-systemd root=/dev/sda3 ro
}
# END GRUB
EOF
Then I would correct my hostname and /etc/hosts like the following:
echo "LFS-Oliver" > /etc/hostname
cat > /etc/hosts << "EOF"
# Begin
127.0.0.1 localhost.localdomain localhost
127.0.1.1 LFS-Oliver
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
# End
EOF
Chapter 11. The End
In this chapter I would setup my LFS installation to boot and have the capabilities required of Milestone 5.
With chapter 10 done, I would completely logout and unmount all of LFS partitions with the commands:
logout
umount -v $LFS/dev/pts
umount -v $LFS/dev
umount -v $LFS/run
umount -v $LFS/proc
umount -v $LFS/sys
umount -v $LFS/usr
umount -v $LFS/home
umount -v $LFS/boot
umount -v $LFS
I would then shutdown mothership, created a full clone of mother ship (right click the VM > Manage > Clone... > Current state > Full clone > Named "Clone of mothership2 (chapter 11)"). The clone should look like this:
Then I created a new virtual machine with a Custom configuration and the following essential non-default settings below:
(Navigated to the LFS partition from the clone of mothership)
With this created VM, I could boot into my LFS:
I would then do the following change to my DHCP config to enable networking (used ip a
to get my interface name of "enp2s1":
systemctl restart systemd-networkd
And I would then execute the following commands to setup the different types of releases on the system:
echo 11.2-systemd > /etc/lfs-release
cat > /etc/lsb-release << "EOF"
DISTRIB_ID="LFS"
DISTRIB_RELEASE="11.2-systemd"
DISTRIB_CODENAME="Oliver"
DISTRIB_DESCRIPTION="LFS"
EOF
cat > /etc/os-release << "EOF"
NAME="Linux From Scratch"
VERSION="11.2-systemd"
ID=lfs
PRETTY_NAME="Linux From Scratch 11.2-systemd"
VERSION_CODENAME="Oliver"
EOF
With all of this set, I can execute the following to show the completed LFS system: