clfs

clfs.git
git clone git://git.lenczewski.org/clfs.git
Log | Files | Refs | README

commit 3e7e3c3bc99000a4f2b7f05b6c76ee816d3112e0
parent be6c2c188a854c48f8cf832acbb52d27cca008cc
Author: MikoĊ‚aj Lenczewski <mblenczewski@gmail.com>
Date:   Tue,  9 Apr 2024 11:13:54 +0000

Refactor config.sh, add iniial initramfs building to stage4.sh

Diffstat:
Aclfs-env.sh | 28++++++++++++++++++++++++++++
Mclfs.sh | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Dconfig.sh | 56--------------------------------------------------------
Denv-clfs.sh | 28----------------------------
Mstage2.sh | 12++++++------
Mstage3.sh | 7++++---
Mstage4.sh | 100++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Atargets/aarch64-linux-musl-config.sh | 21+++++++++++++++++++++
Atargets/aarch64-linux-musl-qemu.sh | 27+++++++++++++++++++++++++++
9 files changed, 239 insertions(+), 112 deletions(-)

diff --git a/clfs-env.sh b/clfs-env.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +. "$(dirname $0)/targets/$TARGET-config.sh" + +# switch to cross-toolchain +export HOSTCC=$(which cc) +export HOSTCXX=$(which c++) +export HOSTLD=$(which ld) + +export ADDR2LINE=$CROSSTOOLS/bin/llvm-addr2line +export AR=$CROSSTOOLS/bin/llvm-ar +export AS=$CROSSTOOLS/bin/llvm-as +export CC=$TARGET-cc +export CPP=$CROSSTOOLS/bin/llvm-cpp +export CXX=$TARGET-c++ +export LD=$TARGET-ld +export NM=$CROSSTOOLS/bin/llvm-nm +export OBJCOPY=$CROSSTOOLS/bin/llvm-objcopy +export OBJDUMP=$CROSSTOOLS/bin/llvm-objdump +export RANLIB=$CROSSTOOLS/bin/llvm-ranlib +export READELF=$CROSSTOOLS/bin/llvm-readelf +export STRIP=$CROSSTOOLS/bin/llvm-strip +export STRINGS=$CROSSTOOLS/bin/llvm-strings + +export PATH="$CROSSTOOLS/bin:$PATH" + +# disable command path hashing to pick up new tools +set +h diff --git a/clfs.sh b/clfs.sh @@ -1,8 +1,23 @@ #!/bin/sh -. "$(dirname $0)/config.sh" +ROOT="$(realpath $(dirname $0))" -# $ROOT now holds the realpath to the directory containing clfs.sh +TARGETS="$ROOT/targets" +TARGET="${TARGET:-aarch64-linux-musl}" + +# clfs directory definitions +SOURCES="$ROOT/sources" +CROSSTOOLS="$ROOT/crosstools" +CLFS="$ROOT/clfs" + +WORK="$CLFS/work" +SYSROOT="$CLFS/sysroot" +INITRAMFS="$CLFS/initramfs" +BOOTROOT="$CLFS/bootroot" + +. "$TARGETS/$TARGET-config.sh" + +set -e # clean old clfs build rm -rf $CLFS @@ -10,7 +25,32 @@ rm -rf $CLFS # fetch sources mkdir -p $SOURCES -set -e +# package definitions +LLVM_VER_MAJOR="18" +LLVM_VER="18.1.0" +LLVM_DIR="llvm-project-$LLVM_VER.src" +LLVM_PKG="$LLVM_DIR.tar.xz" +LLVM_SRC="https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VER/$LLVM_PKG" + +LINUX_VER="6.7.8" +LINUX_DIR="linux-$LINUX_VER" +LINUX_PKG="$LINUX_DIR.tar.xz" +LINUX_SRC="https://www.kernel.org/pub/linux/kernel/v6.x/$LINUX_PKG" + +MUSL_VER="1.2.5" +MUSL_DIR="musl-$MUSL_VER" +MUSL_PKG="$MUSL_DIR.tar.gz" +MUSL_SRC="https://musl.libc.org/releases/$MUSL_PKG" + +TOYBOX_VER="0.8.9" +TOYBOX_DIR="toybox-$TOYBOX_VER" +TOYBOX_PKG="$TOYBOX_DIR.tar.gz" +TOYBOX_SRC="https://landley.net/toybox/downloads/$TOYBOX_PKG" + +IANA_ETC_VER="20240305" +IANA_ETC_DIR="iana-etc-$IANA_ETC_VER" +IANA_ETC_PKG="$IANA_ETC_DIR.tar.gz" +IANA_ETC_SRC="https://github.com/Mic92/iana-etc/releases/download/$IANA_ETC_VER/$IANA_ETC_PKG" # usage: FETCH <src> <pkg> <dir> FETCH() { @@ -30,22 +70,38 @@ FETCH $IANA_ETC_SRC $IANA_ETC_PKG $IANA_ETC_DIR # TODO: do we necessarily want this much noise when running clfs.sh? # set -x -mkdir -p $CLFS $WORK $SYSROOT $INITRAMFS $KERNEL +# start clfs build proper +mkdir -p $CLFS $WORK $SYSROOT $INITRAMFS $BOOTROOT + +CLEAN_WORKDIR() { + rm -rf "$WORK" + mkdir -p "$WORK" +} # build our cross-compilation tools (clang + lld) cd "$ROOT" -. "$ROOT/stage1.sh" +. ./stage1.sh + +CLEAN_WORKDIR # build necessary sysroot to cross-compile c and c++ programs for target cd "$ROOT" -. "$ROOT/stage2.sh" +. ./stage2.sh + +CLEAN_WORKDIR # cross-compile userland for target cd "$ROOT" -. "$ROOT/stage3.sh" +. ./stage3.sh + +CLEAN_WORKDIR # cross-compile initramfs and kernel for target cd "$ROOT" -. "$ROOT/stage4.sh" +. ./stage4.sh echo "Done!" + +# run +[ -f "$TARGETS/$TARGET-qemu.sh" ] && \ + . "$TARGETS/$TARGET-qemu.sh" diff --git a/config.sh b/config.sh @@ -1,56 +0,0 @@ -#!/bin/sh - -ROOT="$(realpath $(dirname $0))" - -# clfs target toolchain and kernel definitions -TARGET="aarch64-linux-musl" - -CMAKE_SYSTEM_NAME="Linux" -CMAKE_SYSTEM_PROCESSOR="aarch64" - -MESON_SYSTEM="linux" -MESON_CPU_FAMILY="aarch64" -MESON_CPU="aarch64" -MESON_ENDIAN="little" - -LINUX_ARCH="arm64" -LINUX_HOSTCC_OPTS="LLVM=1" # NOTE: LLVM=1 is needed if your hostcc is clang -LINUX_CONFIG="$ROOT/kconfig" - -# clfs directory definitions -SOURCES="$ROOT/sources" -CROSSTOOLS="$ROOT/crosstools" -CLFS="$ROOT/clfs" - -WORK="$CLFS/work" -SYSROOT="$CLFS/sysroot" -INITRAMFS="$CLFS/initramfs" -KERNEL="$CLFS/kernel" - - -# package definitions -LLVM_VER_MAJOR="18" -LLVM_VER="18.1.0" -LLVM_DIR="llvm-project-$LLVM_VER.src" -LLVM_PKG="$LLVM_DIR.tar.xz" -LLVM_SRC="https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VER/$LLVM_PKG" - -LINUX_VER="6.7.8" -LINUX_DIR="linux-$LINUX_VER" -LINUX_PKG="$LINUX_DIR.tar.xz" -LINUX_SRC="https://www.kernel.org/pub/linux/kernel/v6.x/$LINUX_PKG" - -MUSL_VER="1.2.5" -MUSL_DIR="musl-$MUSL_VER" -MUSL_PKG="$MUSL_DIR.tar.gz" -MUSL_SRC="https://musl.libc.org/releases/$MUSL_PKG" - -TOYBOX_VER="0.8.9" -TOYBOX_DIR="toybox-$TOYBOX_VER" -TOYBOX_PKG="$TOYBOX_DIR.tar.gz" -TOYBOX_SRC="https://landley.net/toybox/downloads/$TOYBOX_PKG" - -IANA_ETC_VER="20240305" -IANA_ETC_DIR="iana-etc-$IANA_ETC_VER" -IANA_ETC_PKG="$IANA_ETC_DIR.tar.gz" -IANA_ETC_SRC="https://github.com/Mic92/iana-etc/releases/download/$IANA_ETC_VER/$IANA_ETC_PKG" diff --git a/env-clfs.sh b/env-clfs.sh @@ -1,28 +0,0 @@ -#!/bin/sh - -. "$(dirname $0)/config.sh" - -# switch to cross-toolchain -export HOSTCC=$(which cc) -export HOSTCXX=$(which c++) -export HOSTLD=$(which ld) - -export ADDR2LINE=$CROSSTOOLS/bin/llvm-addr2line -export AR=$CROSSTOOLS/bin/llvm-ar -export AS=$CROSSTOOLS/bin/llvm-as -export CC=$TARGET-cc -export CPP=$CROSSTOOLS/bin/llvm-cpp -export CXX=$TARGET-c++ -export LD=$TARGET-ld -export NM=$CROSSTOOLS/bin/llvm-nm -export OBJCOPY=$CROSSTOOLS/bin/llvm-objcopy -export OBJDUMP=$CROSSTOOLS/bin/llvm-objdump -export RANLIB=$CROSSTOOLS/bin/llvm-ranlib -export READELF=$CROSSTOOLS/bin/llvm-readelf -export STRIP=$CROSSTOOLS/bin/llvm-strip -export STRINGS=$CROSSTOOLS/bin/llvm-strings - -export PATH="$CROSSTOOLS/bin:$PATH" - -# disable command path hashing to pick up new tools -set +h diff --git a/stage2.sh b/stage2.sh @@ -1,6 +1,6 @@ #!/bin/sh -. "$(dirname $0)/env-clfs.sh" +. "$(dirname $0)/clfs-env.sh" echo "Building $TARGET sysroot..." @@ -73,7 +73,7 @@ endian = '$MESON_ENDIAN' EOF # create FHS-compliant sysroot directories -mkdir -pv \ +mkdir -v \ $SYSROOT/bin \ $SYSROOT/dev \ $SYSROOT/etc \ @@ -90,10 +90,10 @@ mkdir -pv \ $SYSROOT/usr \ $SYSROOT/var -mkdir -pv \ +mkdir -v \ $SYSROOT/etc/opt -mkdir -pv \ +mkdir -v \ $SYSROOT/usr/bin \ $SYSROOT/usr/include \ $SYSROOT/usr/lib \ @@ -102,7 +102,7 @@ mkdir -pv \ $SYSROOT/usr/share \ $SYSROOT/usr/src -mkdir -pv \ +mkdir -v \ $SYSROOT/usr/local/bin \ $SYSROOT/usr/local/etc \ $SYSROOT/usr/local/games \ @@ -113,7 +113,7 @@ mkdir -pv \ $SYSROOT/usr/local/share \ $SYSROOT/usr/local/src -mkdir -pv \ +mkdir -v \ $SYSROOT/var/cache \ $SYSROOT/var/lib \ $SYSROOT/var/local \ diff --git a/stage3.sh b/stage3.sh @@ -1,6 +1,6 @@ #!/bin/sh -. "$(dirname $0)/env-clfs.sh" +. "$(dirname $0)/clfs-env.sh" echo "Building $TARGET userland..." @@ -9,8 +9,9 @@ echo "Building toybox..." cp -r $SOURCES/$TOYBOX_DIR $WORK/$TOYBOX_DIR cd $WORK/$TOYBOX_DIR -make LDFLAGS="--static" distclean defconfig toybox -make PREFIX=$SYSROOT install +make distclean +make defconfig +make PREFIX=$SYSROOT install -j$(nproc) # build iana-etc echo "Building iana-etc..." diff --git a/stage4.sh b/stage4.sh @@ -1,27 +1,105 @@ #!/bin/sh -. "$(dirname $0)/env-clfs.sh" +. "$(dirname $0)/clfs-env.sh" echo "Building $TARGET initramfs and kernel..." -if false; then +# build initramfs +echo "Building $TARGET initramfs..." -mkdir -p $BOOTROOT $INITRAMFS +mkdir -v \ + $INITRAMFS/bin \ + $INITRAMFS/dev \ + $INITRAMFS/etc \ + $INITRAMFS/mnt \ + $INITRAMFS/proc \ + $INITRAMFS/root \ + $INITRAMFS/run \ + $INITRAMFS/sbin \ + $INITRAMFS/sys \ + $INITRAMFS/usr -# build initramfs +mkdir -v \ + $INITRAMFS/mnt/root + +mkdir -v \ + $INITRAMFS/usr/bin \ + $INITRAMFS/usr/sbin + +# TODO: does `mount -t devtmpfs none /dev` remove the need for this? if not, +# should we build a custom cpio archive using the kernel gen_init_cpio tool? +# cp -a /dev/null /dev/console /dev/tty $INITRAMFS/dev + +# build static toybox for initramfs +echo "Building static toybox for initramfs..." +cp -r $SOURCES/$TOYBOX_DIR $WORK/$TOYBOX_DIR +cd $WORK/$TOYBOX_DIR + +make distclean +make defconfig +make LDFLAGS="--static" PREFIX=$INITRAMFS install -j$(nproc) + +cat > $INITRAMFS/init <<'EOF' +#!/bin/toybox sh + +rescue_shell() { + echo "$1 : dropping to a rescue shell." + exec /bin/toybox sh +} + +mount -t devtmpfs none /dev || rescue_shell "mounting /dev failed" +mount -t proc none /proc || rescue_shell "mounting /proc failed" +mount -t sysfs none /sys || rescue_shell "mounting /sys failed" +mount -t tmpfs none /run || rescue_shell "mounting /run failed" + +# TODO: parse out kernel commandline +init="/sbin/init" +root="" +mount_ro_rw="ro" + +for p in $(read -r < /proc/cmdline); do + case $p in + init=*) init="${param#init=} ;; + root=*) root="${param#root=} ;; + ro) mount_ro_rw="ro" ;; + rw) mount_ro_rw="rw" ;; + esac +done + +[ "${root:-z}" = "z" ] && rescue_shell "no root specified, cannot mount" + +mount -o "$mount_ro_rw" "$root" /mnt/root || rescue_shell "mounting rootfs failed" + +umount /dev /proc /sys /run + +exec switch_root /mnt/root "$init" || \ + rescue_shell "failed to switch_root to /mnt/root with init=$init" +EOF + +chmod +x $INITRAMFS/init +# build cpio archive +echo "Building $TARGET initrd cpio archive..." +( cd $INITRAMFS ; find . | cpio -o -H newc --quiet ) > $BOOTROOT/$INITRD # build linux-kernel -cd $SOURCES/$LINUX_DIR +echo "Building $TARGET $LINUX_DIR kernel..." +if [ -f "$TARGETS/$TARGET-kconfig" ]; then + cp -r $SOURCES/$LINUX_DIR $WORK/$LINUX_DIR + cd $WORK/$LINUX_DIR -make HOSTCC=$HOSTCC ARCH=$LINUX_ARCH mrproper -make HOSTCC=$HOSTCC ARCH=$LINUX_ARCH CROSS_COMPILE=$TARGET- -make HOSTCC=$HOSTCC ARCH=$LINUX_ARCH CROSS_COMPILE=$TARGET- \ - INSTALL_MOD_PATH=$SYSROOT modules_install + cp "$TARGETS/$TARGET-kconfig" .config -cp -v arch/$LINUX_ARCH/boot/bzImage $BOOTROOT/linuxstub.efi -cp -rv arch/$LINUX_ARCH/boot/dts $BOOTROOT/ + make HOSTCC=$HOSTCC ARCH=$LINUX_ARCH mrproper + make HOSTCC=$HOSTCC ARCH=$LINUX_ARCH CROSS_COMPILE=$TARGET- + make HOSTCC=$HOSTCC ARCH=$LINUX_ARCH CROSS_COMPILE=$TARGET- \ + INSTALL_MOD_PATH=$SYSROOT modules_install + cp -v arch/$LINUX_ARCH/boot/bzImage $BOOTROOT/$KERNEL + [ -d arch/$LINUX_ARCH/boot/dts ] && \ + cp -rv arch/$LINUX_ARCH/boot/dts $BOOTROOT/ +else + echo "No kconfig given ($TARGETS/$TARGET-kconfig missing), skipping building kernel." fi echo "Built $TARGET initramfs and kernel!" diff --git a/targets/aarch64-linux-musl-config.sh b/targets/aarch64-linux-musl-config.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +TARGET="aarch64-linux-musl" + +CMAKE_SYSTEM_NAME="Linux" +CMAKE_SYSTEM_PROCESSOR="aarch64" + +MESON_SYSTEM="linux" +MESON_CPU_FAMILY="aarch64" +MESON_CPU="aarch64" +MESON_ENDIAN="little" + +LINUX_ARCH="arm64" + +# NOTE: LLVM=1 is needed if your hostcc is clang +LINUX_HOSTCC_OPTS=" + $(cc --version | grep -q clang && echo "LLVM=1") +" + +KERNEL=kernel8.img +INITRD=initrd.cpio diff --git a/targets/aarch64-linux-musl-qemu.sh b/targets/aarch64-linux-musl-qemu.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +set -ex + +KERNEL="$BOOTROOT/$KERNEL" +INITRD="$BOOTROOT/$INITRD" + +QEMU_OPTS=" + -kernel $KERNEL + -append 'console=ttyS0' + -cpu max + -m 128M + -nographic + -serial mon:sdio + -nodefaults +" + +if [ ! -f "$KERNEL" ]; then + echo "No kernel was built, cannot run qemu!" + exit 1 +fi + +if [ -f "$INITRD" ]; then + QEMU_OPTS="$QEMU_OPTS -initrd $INITRD" +fi + +qemu-system-aarch64 $QEMU_OPTS