How to Build Toolchains With crosstool-NG in Linux-Free Embedded Linux Training

PREV_LEC | NEXT_LEC

Build Toolchains With crosstool-NG
A hands-on guide to generating a custom cross compiler for your embedded target on a free embedded Linux course
Build system: crosstool-NG
Level: Beginner-Intermediate
Time: 45 minutes

If you have followed this free embedded Linux course so far, you already know that a toolchain is a matched set of compiler, binutils, C library and kernel headers built for a specific target. Getting a prebuilt toolchain is fast, but sooner or later every embedded Linux developer needs a toolchain with an exact glibc version, an exact GCC version, or support for a target that nobody ships a prebuilt package for. That is exactly the gap crosstool-NG fills, and it is one of the most useful skills you can pick up on a free linux kernel development course path.

crosstool-NG
cross compiler
free embedded systems course
free linux device drivers course
ct-ng menuconfig
toolchain build system

What You Will Learn

  • What crosstool-NG actually does and how it differs from a build system like Buildroot or Yocto
  • How to install crosstool-NG’s build dependencies and get its source
  • How to pick a starting sample configuration close to your target
  • How to fine-tune the configuration with ct-ng menuconfig
  • How to kick off and monitor the actual toolchain build

Prerequisites

  • A Linux host — Ubuntu 22.04 or newer is assumed in the examples
  • Comfort with the shell and roughly 5-10 GB of free disk space
  • Basic idea of what a target triplet is (covered in an earlier lecture in this free linux development course)

Why crosstool-NG Instead of a Distro Package

Distributions ship a small number of prebuilt cross toolchains, usually one glibc version, one GCC version, glued to whatever the packagers decided was reasonable. The moment your board vendor asks for an older glibc for ABI compatibility, or you want the latest GCC to pick up a new C23 feature, the distro package stops being an option. crosstool-NG solves this by driving the actual build of binutils, GCC, a C library and the kernel headers from source, using a menu-driven configuration that mirrors the Linux kernel’s own menuconfig. You describe what you want; crosstool-NG downloads, patches, configures and builds every component in the right order.

The alternative most experienced developers reach for once a project grows is a full build system such as Buildroot or Yocto, since those generate a toolchain automatically as one output of building a whole root filesystem. crosstool-NG earns its place when you specifically want a standalone toolchain — nothing else — and you want to see and control every step of how it was put together.

Installing crosstool-NG

crosstool-NG is now developed and released on GitHub rather than the old crosstool-ng.org download page, so grabbing a tagged release with git is the most reliable route. First install the host build dependencies:

Host Build Dependencies
$ sudo apt-get update
$ sudo apt-get install -y build-essential git autoconf automake \
    libtool libtool-bin gperf bison flex texinfo help2man \
    gawk libncurses-dev python3-dev unzip rsync wget bzip2 \
    xz-utils patch

Next, clone the repository and check out a stable tag instead of always tracking the moving development branch — this keeps your build reproducible:

Fetching and Bootstrapping crosstool-NG
$ git clone https://github.com/crosstool-ng/crosstool-ng.git
$ cd crosstool-ng
$ git checkout crosstool-ng-1.28.0
$ ./bootstrap
$ ./configure --enable-local
$ make
$ make install

The --enable-local flag installs the ct-ng front end into the current directory rather than /usr/local/bin, so nothing requires root and you can keep multiple crosstool-NG checkouts side by side without them colliding. Once make install finishes, run ./ct-ng version from that directory to confirm it built correctly.

Choosing a Starting Sample

crosstool-NG ships dozens of tested “sample” configurations covering common architecture and C-library combinations, and starting from one of these is far less error-prone than configuring a target from a blank slate. List them with:

Listing Available Samples
$ ./ct-ng list-samples

Say your target is a 64-bit ARM board — an Armv8-A core such as a Cortex-A72 — running glibc. The closest sample is aarch64-unknown-linux-gnu. Preview what that sample actually pulls in by prefixing it with show-:

Previewing a Sample Configuration
$ ./ct-ng show-aarch64-unknown-linux-gnu
[G..] aarch64-unknown-linux-gnu

    Languages       : C,C++
    OS               : linux-6.x
    Binutils        : binutils 2.42
    C compiler      : gcc 14.2.0
    C library       : glibc 2.40 (threads: nptl)
    Debug tools     : gdb

Note that the exact component versions crosstool-NG resolves depend on the release you built, since the project regularly bumps its default component versions — always trust the output of your own show- command over any figure printed here or in an old book.

Select the sample as your active configuration:

Selecting the Target Configuration
$ ./ct-ng aarch64-unknown-linux-gnu

Fine-Tuning With menuconfig

A sample gets you close, but real projects almost always need a small adjustment or two. Open the configuration menu:

Opening the Configuration Menu
$ ./ct-ng menuconfig

Two changes are worth knowing about because they trip up newcomers every time:

Menu Path Option Why It Matters
Paths and misc options Render the toolchain read-only Disable this if you plan to add extra target libraries into the toolchain later — a read-only install blocks that
Target options → Floating point hardware (FPU) Picks the ABI variant that passes floating point arguments in VFP/NEON registers rather than general-purpose ones — get this wrong and your binaries silently mismatch your board’s expectations

Exit and save when you are done; the choices land in a plain-text .config file in the working directory, which you can diff, version-control, or hand-edit for anything the menu does not expose directly.

Running the Build

With the configuration set, kick off the actual build:

Building the Toolchain
$ ./ct-ng build

crosstool-NG now downloads every component’s source tarball, verifies checksums, applies its patch set, and builds binutils, a bootstrap GCC, the C library headers, the full GCC, and finally gdb — in that dependency order. Expect anywhere from 20 minutes to well over an hour depending on your CPU core count and network speed; use ./ct-ng build.4 in place of plain build to parallelise across 4 jobs if your host has the cores to spare. When it finishes without error, the finished toolchain lands under ~/x-tools/aarch64-unknown-linux-gnu/.

Common Mistakes and Troubleshooting

  • Build fails downloading a component: a mirror is occasionally down. Re-run ./ct-ng build — it resumes rather than restarting, and you can point CT_DOWNLOAD_AGENT at a different tool if wget keeps failing.
  • “directory already exists” errors on a second build: run ./ct-ng distclean before switching to a different sample or config in the same working directory.
  • Missing host package errors mid-build: crosstool-NG’s ./ct-ng build checks most dependencies up front but not all of them — install the package named in the error and re-run.
  • Picking the wrong ABI variant: always cross-check your board’s expected triplet (hard-float vs soft-float, big vs little endian) against your vendor’s BSP or datasheet before you spend an hour building the wrong thing.

Best Practices

  • Pin a specific crosstool-NG release tag rather than tracking its main branch, so your toolchain build is reproducible months later.
  • Commit the generated .config file to your project’s version control — it is the single source of truth for exactly how the toolchain was built.
  • Build once, then archive the resulting ~/x-tools/<triplet> directory as a tarball for teammates and CI, instead of asking every machine to rebuild from scratch.

Summary and Key Takeaways

  • crosstool-NG builds a standalone cross toolchain entirely from source, giving you precise control over compiler, C library, and target ABI versions.
  • Start from the closest built-in sample with ct-ng list-samples and show-<sample>, then refine it with ct-ng menuconfig.
  • ct-ng build does the rest, leaving a ready-to-use toolchain under ~/x-tools/.

Conclusion

Building your own toolchain sounds intimidating the first time, but crosstool-NG reduces it to picking a sample, adjusting a handful of menu options, and waiting for a build to finish. That control is exactly what separates a hobby setup from a production embedded Linux workflow, which is why this topic sits early in this free linux kernel development course. In the next lecture we put the toolchain you just built to work — compiling, cross-checking, and querying it like a real embedded engineer would.

Frequently Asked Questions

Is crosstool-NG still actively maintained?

Yes. Development moved from the original crosstool-ng.org site to GitHub, and releases continue to track current GCC, binutils, and glibc/musl versions.

Do I need root access to build a toolchain with crosstool-NG?

No. Using --enable-local when configuring crosstool-NG itself, and building the target toolchain as a normal user, avoids any need for root.

How long does a crosstool-NG build normally take?

Anywhere from 20 minutes to over an hour, depending on host CPU cores, disk speed, and network speed for the source downloads.

Should I use crosstool-NG or Buildroot for my board?

Use crosstool-NG when you only need a standalone toolchain. Use Buildroot or Yocto when you also need a full root filesystem, since both generate a toolchain as a side effect of that larger build.

What does the read-only toolchain option actually control?

It marks the installed toolchain directory read-only after the build. Disable it if you plan to install additional target libraries into the toolchain’s sysroot later.

Can I reuse the same crosstool-NG checkout for multiple targets?

Yes, but run ct-ng distclean between builds for different samples in the same working directory to avoid stale build artifacts.

Where does crosstool-NG install the finished toolchain?

By default under ~/x-tools/<target-triplet>/, unless you changed the install path in ct-ng menuconfig.

Ready to Build Your Own Cross Toolchain?

Explore the rest of this free embedded Linux course for more hands-on lectures on toolchains, kernel internals, and device drivers.

PREV_LEC | NEXT_LEC

 

Leave a Reply

Your email address will not be published. Required fields are marked *