There is no particular reason to use an Arch ISO as your live environment. I just felt like it and had the ISO on my drive.
Required packages in the Arch live env:
git
base-devel
To install them, make space in the live env like so:
sudo mount -o remount,size=8G /run/archiso/cowspace
I recommend using an actually nice terminal (like st) through SSH to set up your ELFS system.
For that you need to set a password in the Arch VM, so that you can log into it with SSH, since the default password is empty and SSH really doesn't like that.
Then you need a directory in which our ELFS system will live:
For interactive use, I like cfdisk. So I used that, made an MBR partition table, partitioned /dev/vda with one partition, set it as bootable and of type Linux, and that's enough.
Then I formatted that partition with an ext4 filesystem and mounted it at /mnt.
Once that's done, we can move to getting a musl toolchain.
You can get premade ones here: https://musl.cc
I downloaded mine from here: https://musl.cc/x86_64-linux-musl-cross.tgz
curl --output x86_64-linux-musl-cross.tgz https://musl.cc/x86_64-linux-musl-cross.tgz
Then I set up a little shell script we can source to actually use the toolchain.
export PATH="/mnt/src/x86_64-linux-musl-cross/bin:$PATH"
export CC=x86_64-linux-musl-gcc
export LD=x86_64-linux-musl-gcc
export CXX=x86_64-linux-musl-g++
export AR=x86_64-linux-musl-ar
export RANLIB=x86_64-linux-musl-ranlib
export STRIP=x86_64-linux-musl-strip
export CFLAGS="-Os -pipe -fstack-protector-strong"
export LDFLAGS="-static"
Download the kernel sources:
curl --output linux-7.0.8.tar.xz https://cdn.kernel.org/pub/linux/kernel/v7.x/linux-7.0.8.tar.xz
Make a boot directory and build it:
# ensure necessary modules are really loaded
lsmod | awk '{print $1}' | xargs modprobe -a 2>/dev/null || true
# generate a config based on the loaded modules
# in a VM (and with our expectations) this is sufficient to get a working kernel
make localmodconfig
# ensure the build uses the musl cross toolchain
export CROSS_COMPILE=x86_64-linux-musl-
export ARCH=x86_64
# build
make -j$(nproc)
Then install it to the boot partition:
cp -v ./arch/x86_64/boot/bzImage /mnt/boot/vmlinuz-7.0.8
cp -v System.map /mnt/boot/System.map-7.0.8
And that's it. We have a kernel.
cd /mnt
mkdir sbin
mkdir -p usr/bin
mkdir -p usr/include
mkdir -p usr/lib
mkdir -p usr/share/man
mkdir etc
ln -s ./usr/bin ./bin
ln -s ./usr/lib ./lib
ln -s ./usr/lib ./lib64
We already have our cross toolchain. We can cannibalize that for a libc for the host.
Just go into where your x86_64-linux-musl-cross toolchain lives, and then go into x86_64-linux-musl.
Then execute:
cp -v -r ./include/* /mnt/usr/include/
cp -v -r ./lib/* /mnt/usr/lib/
For the suckless packages, the workflow is the same:
And now build the packages:
Suckless workflow.
Suckless workflow.
Unfortunately dash uses GNU autotools.
Dash uses some utilites in its build process that need to be compiled using your host compiler:
cd src
gcc -o mksyntax mksyntax.c
gcc -o mkinit mkinit.c
gcc -o mknodes mknodes.c
gcc -o mksignames mksignames.c
Run the configure script with these options:
./configure --prefix=/mnt/usr --enable-static
Then build once and let it fail.
Then go into the src directory again and do:
gcc -o mksyntax mksyntax.c
Then build again, and it will work this time.
While building you will get a linker error, that the symbol makedev was not found. That symbol is defined in sys/sysmacros.h, which smdev.c expects to be pulled in indirectly through sys/types.h or sys/stat.h.
And that works fine on glibc, but does not work in musl.
So in smdev.c, you have to add under the other sys/*.h includes:
#include <sys/sysmacros.h>
From there, the usual suckless workflow applies.
For some reason the nldev Makefile adds /usr/include and /usr/lib to your include and lib directories.
Remove that, then classic suckless workflow from there.
At the time of writing this, that repo had issues, so I couldn't clone it. Since it's not strictly necessary for booting, you can skip it.
Just the suckless workflow. Builds with no issues.
Nothing to build, since it's all scripts.
Open bin/svc, edit BASEDIR to be /etc/svc.d instead of /bin/svc.d
Then move the files:
cd bin
cp ./* /mnt/bin/
cd ..
cp -r svc.d /mnt/etc/
Sadly TCC uses GNU autotools.
You can configure it like so:
./configure --prefix=/mnt/usr --enable-static --sysincludepaths=/mnt/usr/include --libpaths=/mnt/usr/lib --crtprefix=/mnt/usr/lib64
The same issues as with dash apply, so before building execute this command:
gcc -DC2STR conftest.c -o c2str.exe
Build that then. The TCC tests will fail because you don't have a stdatomic.h header. That's fine, the compiler will still compile C code.
TODO: document EFISTUB
TODO: gather the motivation to document at least one of those BIOS bootloaders
You now have an Enlightened Linux From Scratch system.
You could've just installed Alpine Linux and compiled a custom kernel all along.
Please be so kind and donate to one of these distros, whose developers and maintainers do this bullshit for a living and are much better at it than I am: