August 2020 Winging Linux From Scratch with LLVM/Clang Instead Of GCC From a host Linux install create your LFS directory: $ mkdir ~/lfs Download the LLVM monorepo $ wget && tar xvf llvm-project-10.0.1.tar.xz Generate the Ninja build templates, build, and install $ cmake -G Ninja -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;libcxx;libcxxabi;libunwind;lldb;compiler-rt;lld;polly;debuginfo-test" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_DIRECTORY=/home/mike/lfs -DCMAKE_INSTALL_PREFIX=/home/mike/lfs ../llvm && ninja && ninja install TIL mrproper is used as an alternative to `make clean` ex: `make mrproper` which apparently is some old reference to a cleaning product I'm doing this in WSL2 so grab the kernel from TODO:(link to github) Clean it: $ make mrproper Copy the config: $ cp Microsoft/config-wsl .config Build the headers for glibc: $ make headers_install Apparently this can be just make headers on newer kernels Copy over the headers $ cp -a usr/include ~/lfs/usr Turns out we don't need the linux kernel headers if we're using MUSL which we are so *shrug* $ cd ~/lfs/usr/src && wget && tar xvf musl-1.2.1.tar.gz $ ./configure --disable-shared \ # static builds only, no dynamic linking --prefix=~/lfs/ $ make && make install At this point we probably need libstdc++ which is included with the GCC sources but we're just gonna keep on trucking without it until something needs it We need to get bootstrapped to the point we can build llvm and musl in our chroot, then we'll build bash... actually no, bash has to be present before the chroot. Things I think we'll need: - make - bash - m4? Make: $ cd ~/lfs/usr/src && wget && tar xvf make.* ... how the fuck do we make make without make? $ ./configure --prefix=/home/mike/lfs $ sh && ./make install # make && make install Turns out make includes a shell script you can use to build make with, which you can then use for any other make targets see Time for bash $ cd ~/lfs/usr/src && wget && tar xvf bash* $ ./configure --prefix=/home/mike/lfs Looks like maybe we need readline first? $ cd ~/lfs/usr/src && wget && tar xvf readline* # wow readline hasn't had a stable release in 15 years! Need to remember to use the -j flag for make moving forward to use more cores Let's see if this thing works so far, we're skipping ahead to chapter 6 of the LFS book to setup the chroot knowing full well we don't have an entirely bootstrapped system We need some initial devices and directories $ mkdir -pv ~/lfs/{dev,proc,sys,run} $ mknod -m 600 ~/lfs/dev/console c 5 1 $ mknod -m 666 ~/lfs/dev/null c 1 3 /dev/console and /dev/null need to be available before udevd has been started and additionally when linux is started with init=/bin/bash Let's mount some things $ sudo mount -v --bind /dev /home/mike/lfs/dev We have to bind mount /dev because udevd won't be running in our chroot so we have to use our already existing /dev directory Now we also need the remaining kernel virtual filesystems $ sudo mount -vt devpts devpts ~/lfs/dev/pts -o gid=5,mode=620 $ sudo mount -vt proc proc ~/lfs/proc $ sudo mount -vt sysfs sysfs ~/lfs/sys $ sudo mount -vt tmpfs tmpfs ~/lfs/run We also need to make /dev/shm if it is a symbolic link to /run/shm $ if [ -h ~/lfs/dev/shm ]; then mkdir -pv ~/lfs/$(readlink ~/lfs/dev/shm); fi ENTER THE CHROOT $ chroot /home/mike/lfs just kidding, I compared the bash version strings of my host and my LFS and noticed the host was 5.0.17 and mine was 5.0.0. I thought I must have grabbed the wrong bash version but then noticed there are patch directories that I'm going to need to apply so let's do that $ curl '[001-018]' | patch --verbose -p0 Should probably have checked those signature but whatever Ok we've patched so let's build again: $ make clean && make && make install $ sudo chroot /home/mike/lfs /bin/bash --login +h # the +h disables command hashing Ok so this fails with a can't find /bin/bash which definitely sounds incorrect. I noticed that the bash I built is dynamically linked against GCC's dynamic loader so I think I fucked up the build somehow $ ./configure --prefix=/home/mike/lfs --enable-static-link $ make clean && make && make install Should mention at this point I used the ubuntu alternatives system to specify CC and CPP as clang Ok cool, that was the problem, the chroot now works and I probably failed to staticly link a bunch of other shit. Alright so I'm missing GNU coreutils so I have no cat, no ls, and since I didn't bother with readline I can't even backspace. Let's fix the readline thing. $ ./configure --prefix=/home/mike/lfs $ make -j8 && make install back to bash... $ ./configure --prefix=/home/mike/lfs --enable-static-link --enable-readline $ make clean && LDFLAGS=~/lfs/lib make -j8 && make install welp, still can't backspace. *shrug emoji* let's see if we can build things aaaaaand we can't because make needs to be built staticly too $ ./configure --prefix=~/lfs CFLAGS="-static" $ make clean && make -j8 && make install that seems to have worked and may or may not be clang specific Back in the chroot we're missing /bin/sh so let's make a symlink. Shit. No ln command available. Exiting the chroot, I've downloaded coreutils into ~/lfs/usr/src and created a symlink of /bin/sh to /bin/bash $ wget $ cd ~/lfs/bin && ln -s /bin/bash sh Back in the chroot that got us a bit further, but we're gonna need sed $ wget $ ./configure --prefix=/home/mike/lfs CFLAGS="-static" $ make clean && make -j8 && make install Sed wasn't enough, coreutils wants `expr` and `chmod`, let's build coreutils outside the chroot. Don't know why I didn't do that before? For what it's worth as of the sed point this is like a week or two later so I don't know what old me was thinking. ok so my llvm compiler doesn't work within the chroot because I didn't setup dynamic linking ugh. Let's try to recompile staticly?