In addition to using pre-built binaries, you may want or need to manually compile U-Boot and the Linux kernel to customize features or apply specific patches for your device. To ensure a reproducible and isolated build environment, we use a Docker container based on Debian armel. This approach allows compilation on various host systems, including Apple Silicon machines.
For our setup, we performed all builds on a Mac mini M4 host, leveraging Docker to provide a consistent Debian armel environment. This method is especially useful for ARM development, as it avoids host dependency issues and simplifies toolchain management
1. Prepare the Docker Environment
Install Docker on your host machine (macOS, Linux, or Windows). Ensure you have the latest version and sufficient disk space for the build process
2. Launch a Debian armel Docker Container
Start an interactive shell within a Debian armel container for any armel/armhf build. For example:
docker run --rm -ti armel/debian:latest /bin/bash
This container provides a clean environment where we install the necessary tools for compiling U-Boot and the Kernel.
Note: for aarch64 builds we can use a CRUX-ARM container.
3. Install required build tools
Inside the container, update the package list and install essential packages:
apt-get update apt-get install -y git make build-essential bison m4 flex python3 python3-setuptools python3-dev swig libssl-dev libgnutls28-dev wget bc device-tree-compiler cpio libncurses-dev
CRUX-ARM container:
prt-get depinst swig gnutls
4. Clone U-Boot source repositories
Fetch the U-Boot repository:
git clone https://source.denx.de/u-boot/u-boot
5. Get/Clone Linux kernel sources:
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.14.8.tar.gz tar xvf linux-6.14.8.tar.gz wget https://resources.crux-arm.nu/files/devices/cubieboard/3.8/kernel/6.14.8config
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.14.8.tar.xz tar xvf linux-6.14.8.tar.gz wget https://resources.crux-arm.nu/files/devices/cubieboard2/3.8/kernel/6.14.8/config
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.14.8.tar.gz tar xvf linux-6.14.8.tar.gz wget https://resources.crux-arm.nu/files/devices/odroidxu4/3.8/kernel/6.14.8/config
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.14.8.tar.gz tar xvf linux-6.14.8.tar.gz
6. Compile U-Boot
Configure and build U-Boot for your target board:
cd u-boot git checkout v2025.04 make Cubieboard_defconfig make -j$(nproc)
The resulting u-boot-sunxi-with-spl.bin file can then be flashed to the microSD card as described in the installation steps.
Configure and build U-Boot for your target board:
cd u-boot git checkout v2025.04 make Cubieboard2_defconfig make -j$(nproc)
The resulting u-boot-sunxi-with-spl.bin file can then be flashed to the microSD card as described in the installation steps.
Configure and build U-Boot for your target board:
cd u-boot make orangepi_pc_defconfig make -j$(nproc)
The resulting u-boot-sunxi-with-spl.bin file can then be flashed to the microSD card as described in the installation steps.
Configure and build U-Boot for your target board:
cd u-boot git checkout v2025.04 make odroid-xu3_defconfig make -j$(nproc)
The resulting u-boot-dtb.bin file can then be flashed to the microSD card as described in the installation steps.
Configure and build U-Boot for your target board:
arm-trusted-firmware
Needed patch:
--- Makefile.orig 2025-05-29 05:51:27.463649004 +0000 +++ Makefile 2025-05-29 05:51:51.622579002 +0000 @@ -418,7 +418,7 @@ # LD = gcc (used when GCC LTO is enabled) else ifneq ($(findstring gcc,$(notdir $(LD))),) # Pass ld options with Wl or Xlinker switches -TF_LDFLAGS += -Wl,--fatal-warnings -O1 +TF_LDFLAGS += -O1 TF_LDFLAGS += -Wl,--gc-sections ifeq ($(ENABLE_LTO),1) ifeq (${ARCH},aarch64) @@ -435,7 +435,7 @@ # LD = gcc-ld (ld) or llvm-ld (ld.lld) or other else -TF_LDFLAGS += --fatal-warnings -O1 +TF_LDFLAGS += -O1 TF_LDFLAGS += --gc-sections # ld.lld doesn't recognize the errata flags, # therefore don't add those in that case
Build:
git clone https://github.com/crust-firmware/arm-trusted-firmware/ cd arm-trusted-firmware export CROS_COMPILE="" export ARCH=arm64 make PLAT=sun50i_a64 -j$(nproc) bl31
arm-trusted-firmware/build/sun50i_a64/release/bl31.bin
cd u-boot export BL31=../arm-trusted-firmware/build/sun50i_a64/release/bl31.bin # We don't need SCP firmware so we avoid the build warning export SCP=/dev/null make pine64_plus_defconfig make -j$(nproc)
u-boot-sunxi-with-spl.bin -> Integrates U-boot SPL and FIT images
7. Compile the Linux Kernel Similarly, configure and build the kernel:
cd linux-6.14.8 make sunxi_defconfig make -j$(nproc) zImage modules sun4i-a10-cubieboard.dtb
After compilation, copy the arch/arm/boot/zImage and device tree blob arch/arm/boot/dts/sun4i-a10-cubieboard.dtb to the appropriate locations on your microSD card.
Similarly, configure and build the kernel:
cd linux-6.14.8 cp config .config make oldconfig make -j$(nproc) zImage dtbs modules
After compilation, copy the arch/arm/boot/zImage and device tree blob arch/arm/boot/dts/allwinner/sun7i-a20-cubieboard2.dtb to the appropriate locations on your microSD card. After compilation, copy the arch/arm/boot/zImage and device tree blob arch/arm/boot/dts/allwinner/sun8i-h3-orangepi-pc.dtb to the appropriate locations on your microSD card.
Similarly, configure and build the kernel:
cd linux-6.14.8 cp config .config make oldconfig make -j$(nproc) zImage dtbs modules
After compilation, copy the arch/arm/boot/zImage and device tree blob arch/arm/boot/dts/samsung/exynos5422-odroidxu4.dtb to the appropriate locations on your microSD card.
Similarly, configure and build the kernel:
cd linux-6.14.8 cp config .config make clean defconfig make -j$(nproc) make -j$(nproc) dtbs
After compilation, copy the arch/arm64/boot/Image and device tree blob arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dtb to the appropriate locations on your microSD card.
Similarly, configure and build the kernel:
git clone --depth=1 https://github.com/raspberrypi/linux cd linux KERNEL=kernel8 make bcm2711_defconfig make -j$(nproc) Image.gz modules dtbs
Needed files:
Similarly, configure and build the kernel:
git clone --depth=1 https://github.com/raspberrypi/linux cd linux KERNEL=kernel_2712 make bcm2712_defconfig make -j$(nproc) Image.gz modules dtbs
Needed files:
8. Modules and headers
Install modules and headers to a specific path to be packaged and distributed
make modules_install INSTALL_MOD_PATH="desired_path_to_be_compressed_and_distributed" make headers_install INSTALL_HDR_PATH="desired_path_to_be_compressed_and_distributed"
Note:
Building in a Docker container ensures a clean, repeatable environment, and using Debian armel as the base image provides compatibility with ARM targets. This workflow is particularly effective on Apple Silicon Macs, where native ARM support in Docker streamlines cross-compilation tasks.
We cannot use the CRUX-ARM toolchain for this process because it only provides support for the hard-float ABI (arm-unknown-linux-gnueabihf), which targets systems with hardware floating-point support. Since our target requires soft-float compatibility, we rely on the Debian armel toolchain, which is specifically designed for ARM systems using the soft-float ABI. This ensures proper compatibility and functionality throughout the build process.