Skip to content

Cross compilation toolchain

Quentin Delhaye edited this page Apr 9, 2026 · 18 revisions

We want to make programs and kernel modules that will run on the board, but build them on our local computer. To achieve this, we need a cross-compilation toolchain, i.e. a suite of tools that build stuff meant for another platform. In particular, we will need:

  • A gcc cross-compilation toolchain
  • The Linux kernel source code corresponding to the one running on the board
  • To build said kernel using the toolchain

Note

This whole setup is done on the host.

Set up your local environment

Install the relevant development package for your host Linux distribution: build-essential for Debian and base-devel for Manjaro (Arch), libssl-dev and flex.

Install the right cross-compilation toolchain

The board CPU is based on an ARM architecture. As such, we can fetch the GNU toolchain directly from Arm. In particular, we will use the arm-none-linux-gnueabihf version 12.2.rel1 which is close to the version used to compile the kernel running on the board. Better be safe here. The naming convention for the toolchain is <architecture>-<vendor>-<ABI> with:

  • <architecture> the target architecture, arm in our case.
  • <vendor> a specific vendor release, none in our case.
  • <ABI> to tell if the toolchain is meant to be used in a linux environment or bare-metal (i.e. directly on the hardware), so that the compiler knows if there will be libraries alongside the program to link them or not. In our case, the programs will run on a Linux OS, so our ABI is linux-gnueabihf. The hf part at the end means floats are managed in hardware.
$ wget https://developer.arm.com/-/media/files/downloads/gnu/12.2.rel1/binrel/arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-linux-gnueabihf.tar.xz
$ sudo mkdir -p /opt/arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-linux-gnueabihf
$ sudo chown $LOGNAME:$LOGNAME /opt/arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-linux-gnueabihf
$ tar -xf arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-linux-gnueabihf.tar.xz -C /opt/arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-linux-gnueabihf
$ echo "export PATH=/opt/arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-linux-gnueabihf/arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-linux-gnueabihf/bin/:$PATH" >> ~/.bashrc
$ source ~/.bashrc
$ arm-none-linux-gnueabihf-gcc -v

The last command should help you make sure the process worked.

Tip

If you don't have a .bashrc file, find out on your own how to add a directory to your PATH environment variable.

Compile the kernel locally

To cross-build a kernel module meant for another platform, we need the Linux kernel corresponding to that very platform. Citronics maintains a repository with the one we need.

$ git clone https://github.com/Citronics/lemon-image.git
$ cd lemon-image
$ git submodule init
$ git submodule update
$ cd lemon-image

Note

The update phase might take a little while (8 to 30 minutes).

To compile a Linux kernel, we need a configuration. It tells us which kernel modules should be compiled, formats to use, platform to target, etc. Luckily, it can be retrieved from a running system. From the board:

citro@board:~$ mkdir ~/LKM
citro@board:~$ cd ~/LKM
citro@board:~$ sudo modprobe configs
citro@board:~$ zcat /proc/config.gz > .config

Then from your host computer, navigate to the folder where you extracted the Linux source tree and download the file from the board (see how to do it).

Retrieve a second file named Module.symvers, located on your board in /usr/src/linux-headers-6.12.0-citronics-lemon/Module.symvers.

Edit build-all-kernels.sh as follows (< is a line to remove, > a line to add, # is a comment):

< CROSS_COMPILE="arm-linux-gnueabihf-"
> CROSS_COMPILE="arm-none-linux-gnueabihf-"
< CONFIG_FILE="${CONFIGS_DIR}/${KERNEL_NAME}.config"
> CONFIG_FILE="/path/to/the/board/.config"
> MOD_SYMVERS="/path/to/the/board/Module.symvers"
# After `make olddefconfig`:
> cp "$MOD_SYMVERS" Module.symvers
< deb-pkg
< mkdir -p "$OUTPUT_DIR"
<    cd "$BUILD_DIR/.."
<    mv ./*.deb "$OUTPUT_DIR"

The full updated script is available in the repo here.

Execute the script that will build the kernel headers (not the full kernel, would take too long):

$ ./build-all-kernels.sh

Clone this wiki locally