Skip to the content.

Create cross toolchain using crosstool-ng

1. Enviorments

Platform: Ubuntu 22.04

$ sudo apt update
$ sudo apt install build-essential flex bison gawk texinfo bc file git ssh \
                zip unzip libncurses-dev libssl-dev u-boot-tools net-tools \
                liblz4-tool libtool libtool-bin help2man python-dev-is-python3
$ sudo apt install qemu-user-static qemu-system-arm

2. Build ct-ng

$ mkdir $HOME/crosstools
$ cd $HOME/crosstools/
$ git clone https://github.com/crosstool-ng/crosstool-ng.git
$ mkdir dl out _install
$ cd crosstool-ng/
$ ./bootstrap
$ ./configure --prefix=$HOME/crosstools/out
$ make
$ make install
$ export PATH=$PATH:$HOME/crosstools/out/bin
$ ct-ng help
$ git branch -vv
* master 06fad54c [origin/master] gcc: Add GCC 13.3.0

3. Build cross toolchain

$ ct-ng list-samples
...
[L...]   aarch64-rpi4-linux-gnu
[L...]   aarch64-unknown-linux-gnu
[L...]   aarch64-unknown-linux-musl
[L...]   aarch64-unknown-linux-uclibc
...
[L...]   arm-unknown-linux-gnueabi
...
[L...]   i686-w64-mingw32
...
[L..X]   loongarch64-unknown-linux-gnu
...
[L...]   mipsel-multilib-linux-gnu
[L...]   mips-unknown-linux-gnu
...
[L...]   powerpc64-unknown-linux-gnu
[L...]   powerpc-e300c3-linux-gnu
...
[L..X]   riscv32-unknown-elf
[L..X]   riscv64-unknown-linux-gnu
...
[L...]   x86_64-unknown-linux-gnu
[L...]   x86_64-w64-mingw32,x86_64-pc-linux-gnu
...

Using aarch64:

$ ct-ng aarch64-unknown-linux-gnu
$ ct-ng menuconfig

The menuconfig configure:

Paths and misc options  --->
    ($HOME/crosstools/dl) Local tarballs directory
    ($HOME/crosstools/out/build) Working directory
    ($HOME/crosstools/_install) Prefix directory

Operating System  --->
    Target OS (linux)  --->
    Version of linux (5.4.276)  --->

C compiler  --->
    Compiler (gcc)  --->
    Version of gcc (12.3.0)  --->

Debug facilities  --->
    [*] gdb  --->
        Version of gdb (12.1)  --->

build (include build.log):

$ ct-ng build

It will download src file and build, install. The download file list:

$ ls $HOME/crosstools/dl
binutils-2.42.tar.xz
expat-2.5.0.tar.xz
gcc-12.3.0.tar.xz
gdb-12.1.tar.xz
gettext-0.22.5.tar.xz
glibc-2.39.tar.xz
gmp-6.2.1.tar.xz
isl-0.26.tar.xz
libiconv-1.16.tar.gz
linux-5.4.276.tar.xz
mpc-1.3.1.tar.gz
mpfr-4.2.1.tar.xz
ncurses-6.4.tar.gz
zlib-1.3.tar.xz
zstd-1.5.6.tar.gz

The build file list:

$ cd $HOME/crosstools/
$ tree ./out/build/ -L 2
./out/build/
├── aarch64-unknown-linux-gnu
│   ├── build
│   ├── buildtools
│   └── src
├── src
│   ├── binutils-2.42
│   ├── expat-2.5.0
│   ├── gcc-12.3.0
│   ├── gdb-12.1
│   ├── gettext-0.22.5
│   ├── glibc-2.39
│   ├── gmp-6.2.1
│   ├── isl-0.26
│   ├── libiconv-1.16
│   ├── linux-5.4.276
│   ├── mpc-1.3.1
│   ├── mpfr-4.2.1
│   ├── ncurses-6.4
│   ├── zlib-1.3
│   └── zstd-1.5.6
├── tarballs
│   ├── binutils-2.42.tar.xz -> $HOME/crosstools/dl/binutils-2.42.tar.xz
│   ├── expat-2.5.0.tar.xz -> $HOME/crosstools/dl/expat-2.5.0.tar.xz
│   ├── gcc-12.3.0.tar.xz -> $HOME/crosstools/dl/gcc-12.3.0.tar.xz
│   ├── gdb-12.1.tar.xz -> $HOME/crosstools/dl/gdb-12.1.tar.xz
│   ├── gettext-0.22.5.tar.xz -> $HOME/crosstools/dl/gettext-0.22.5.tar.xz
│   ├── glibc-2.39.tar.xz -> $HOME/crosstools/dl/glibc-2.39.tar.xz
│   ├── gmp-6.2.1.tar.xz -> $HOME/crosstools/dl/gmp-6.2.1.tar.xz
│   ├── isl-0.26.tar.xz -> $HOME/crosstools/dl/isl-0.26.tar.xz
│   ├── libiconv-1.16.tar.gz -> $HOME/crosstools/dl/libiconv-1.16.tar.gz
│   ├── linux-5.4.276.tar.xz -> $HOME/crosstools/dl/linux-5.4.276.tar.xz
│   ├── mpc-1.3.1.tar.gz -> $HOME/crosstools/dl/mpc-1.3.1.tar.gz
│   ├── mpfr-4.2.1.tar.xz -> $HOME/crosstools/dl/mpfr-4.2.1.tar.xz
│   ├── ncurses-6.4.tar.gz -> $HOME/crosstools/dl/ncurses-6.4.tar.gz
│   ├── zlib-1.3.tar.xz -> $HOME/crosstools/dl/zlib-1.3.tar.xz
│   └── zstd-1.5.6.tar.gz -> $HOME/crosstools/dl/zstd-1.5.6.tar.gz
└── tools
    └── bin

23 directories, 15 files

The install file list:

$ cd $HOME/crosstools/
$ tree _install/ -L 2
_install/
├── aarch64-unknown-linux-gnu
│   ├── bin
│   ├── debug-root
│   ├── include
│   ├── lib
│   ├── lib64
│   └── sysroot
├── bin
│   ├── aarch64-unknown-linux-gnu-addr2line
│   ├── aarch64-unknown-linux-gnu-ar
│   ├── aarch64-unknown-linux-gnu-as
│   ├── aarch64-unknown-linux-gnu-c++
│   ├── aarch64-unknown-linux-gnu-cc -> aarch64-unknown-linux-gnu-gcc
│   ├── aarch64-unknown-linux-gnu-c++filt
│   ├── aarch64-unknown-linux-gnu-cpp
│   ├── aarch64-unknown-linux-gnu-ct-ng.config
│   ├── aarch64-unknown-linux-gnu-dwp
│   ├── aarch64-unknown-linux-gnu-elfedit
│   ├── aarch64-unknown-linux-gnu-g++
│   ├── aarch64-unknown-linux-gnu-gcc
│   ├── aarch64-unknown-linux-gnu-gcc-12.3.0
│   ├── aarch64-unknown-linux-gnu-gcc-ar
│   ├── aarch64-unknown-linux-gnu-gcc-nm
│   ├── aarch64-unknown-linux-gnu-gcc-ranlib
│   ├── aarch64-unknown-linux-gnu-gcov
│   ├── aarch64-unknown-linux-gnu-gcov-dump
│   ├── aarch64-unknown-linux-gnu-gcov-tool
│   ├── aarch64-unknown-linux-gnu-gdb
│   ├── aarch64-unknown-linux-gnu-gdb-add-index
│   ├── aarch64-unknown-linux-gnu-gp-archive
│   ├── aarch64-unknown-linux-gnu-gp-collect-app
│   ├── aarch64-unknown-linux-gnu-gp-display-html
│   ├── aarch64-unknown-linux-gnu-gp-display-src
│   ├── aarch64-unknown-linux-gnu-gp-display-text
│   ├── aarch64-unknown-linux-gnu-gprof
│   ├── aarch64-unknown-linux-gnu-gprofng
│   ├── aarch64-unknown-linux-gnu-ld
│   ├── aarch64-unknown-linux-gnu-ld.bfd
│   ├── aarch64-unknown-linux-gnu-ldd
│   ├── aarch64-unknown-linux-gnu-ld.gold
│   ├── aarch64-unknown-linux-gnu-lto-dump
│   ├── aarch64-unknown-linux-gnu-nm
│   ├── aarch64-unknown-linux-gnu-objcopy
│   ├── aarch64-unknown-linux-gnu-objdump
│   ├── aarch64-unknown-linux-gnu-populate
│   ├── aarch64-unknown-linux-gnu-ranlib
│   ├── aarch64-unknown-linux-gnu-readelf
│   ├── aarch64-unknown-linux-gnu-size
│   ├── aarch64-unknown-linux-gnu-strings
│   └── aarch64-unknown-linux-gnu-strip
├── build.log.bz2
├── etc
│   └── gprofng.rc
├── include
│   ├── collectorAPI.h
│   ├── libcollector.h
│   └── libfcollector.h
├── lib
│   ├── bfd-plugins
│   ├── gcc
│   ├── gprofng
│   ├── libcc1.so -> libcc1.so.0.0.0
│   ├── libcc1.so.0 -> libcc1.so.0.0.0
│   ├── libcc1.so.0.0.0
│   └── libgprofng.a
├── libexec
│   └── gcc
└── share
    ├── gcc-12.3.0
    ├── gdb
    └── licenses

20 directories, 51 files

The origin crosstool-ng:

$ cd $HOME/crosstools/
$ ls crosstools-ng/
bash-completion  ct-ng.in           licenses.d   README.md
bootstrap        debian             m4           samples
config           docs               maintainer   scripts
configure.ac     issue_template.md  Makefile.am  testing
contrib          kconfig            packages     TODO
COPYING          LICENSE            paths.sh.in

The build completed crosstool-ng:

$ cd $HOME/crosstools/
$ ls crosstools-ng/
aclocal.m4       configure          kconfig      paths.sh.in
autom4te.cache   configure.ac       LICENSE      README.md
bash-completion  contrib            licenses.d   samples
bootstrap        COPYING            m4           scripts
build.log        ct-ng              maintainer   stamp-h1
config           ct-ng.in           Makefile     testing
config.h         debian             Makefile.am  TODO
config.h.in      docs               Makefile.in  verbatim-data.mk
config.log       include            packages
config.status    issue_template.md  paths.sh

4. Validation

Check version:

$ cd $HOME/crosstools/_install/bin/
$ ./aarch64-unknown-linux-gnu-gcc -v
Using built-in specs.
COLLECT_GCC=./aarch64-unknown-linux-gnu-gcc
COLLECT_LTO_WRAPPER=$HOME/crosstools/_install/libexec/gcc/aarch64-unknown-linux-gnu/12.3.0/lto-wrapper
Target: aarch64-unknown-linux-gnu
Configured with: ...
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 12.3.0 (crosstool-NG 1.26.0.85_06fad54)

Generate hello.c:

#include <stdio.h>

int main(void)
{
    printf("hello world.\n");

    return 0;
}

Build hello.c

$ aarch64-unknown-linux-gnu-gcc hello.c -o hello --static

$ du -sh hello
2.7M    hello

$ file hello
hello: ELF 64-bit LSB executable, ARM aarch64, version 1 (GNU/Linux), statically linked, for GNU/Linux 5.4.255, with debug_info, not stripped

$ aarch64-unknown-linux-gnu-strip hello
$ du -sh hello
520K    hello

Running:

$ qemu-aarch64-static hello
hello world.