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:
Initial_version_check

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:
Final_version_check

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:
image

Created in cfdisk:
cfdisk_table

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:
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. temp

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 

image

With all of this set, the command lsblk /dev/sdb -f should generate the following image

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:
md5_checksum_m2

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:
LFS_user_creation_with_directory_creation_above_m2

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:
lfs_bash_creation_pt1_m2

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):

  1. Turn off bash's hash function
  2. Set newly created files and directories to only be writable by owner, but readable/executable by anyone
  3. Set the LFS variable
  4. Set the LC_ALL variable (for the chroot environment)
  5. Set the LFS_TGT variable (important for building cross compiler and linker in the temporary toolchain)
  6. Set the PATH variable (for chapter 5)
  7. Add /bin to the PATH variable if not sym link
  8. Put $LFS/tools/bin ahead of the standard PATH (prioritizes cross-compiler)
  9. Set CONFIG_SITE variable (override contamination from host config items)
  10. Export the variables for use within any sub-shell

Screenshot of above commands:
lfs_bash_creation_pt3_m2

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:
lfs_bash_creation_pt4_m2

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):
SBU_m2

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:
Sanity_check_m2

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!): Milestone2_check_m2

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:
Successful_chroot_m3
Successful_chroot__2m3

(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):

  1. Removing the installed documentatoin
  • rm -rf /usr/share/{info,man,doc}/*
  1. Removing the libtool .la files
  • find /usr/{lib,libexec} -name \*.la -delete
  1. Removing the /tools directory
  • rm -rf /tools
  1. 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:
image

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):
image12

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:
image19
image15
image8
image7

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:
vim

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
    image9

And compared it with UTC time and it gained a match (see below), so nothing was needed to be done:
image18

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

image3

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

image10

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

image1

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:
image

Then I created a new virtual machine with a Custom configuration and the following essential non-default settings below:
image
image

(Navigated to the LFS partition from the clone of mothership) image

With this created VM, I could boot into my LFS:
image

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

image12

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: image

Sources (Not Linux From Scratch)