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