configure –host
Buildroot
Yocto Project
free linux device drivers course
free embedded systems course
By this point in this free embedded Linux course you can build a toolchain, install libraries
into its sysroot, and query flags with pkg-config. That’s enough for well-behaved packages. Most real packages
aren’t well-behaved. This lecture walks through the classic ways cross-compiling problems show up
in practice, how to diagnose them, and — just as important — when the right answer is to stop hand-cross-compiling
altogether. This closes out the toolchain chapter of the course before we move on to bootloaders.
What You Will Learn
- The three recurring categories of cross-compiling failure
- How to diagnose a configure script that’s reading the host instead of the target
- How to recognize and work around scripts that try to execute cross-compiled binaries
- Why dependency chains make manual cross compiling unsustainable past a handful of packages
- When to switch to Buildroot, the Yocto Project, or native compilation instead
Prerequisites
- A working cross toolchain and sysroot (earlier lectures in this chapter)
- Familiarity with Autotools
configureand--host/--build(previous lecture) - Basic pkg-config usage (previous lecture)
Category 1: Non-Standard Build Systems
Not every package uses Autotools correctly, and some ship a configure script that looks familiar but
behaves differently — accepting different flags, ignoring --host, or requiring hand-edited config
headers instead of autodetection. There’s no universal fix here; each one requires reading its actual build
documentation rather than assuming Autotools conventions apply.
$ ./configure --host=arm-none-linux-gnueabihf --prefix=/usr
checking build system type... x86_64-pc-linux-gnu
checking host system type... x86_64-pc-linux-gnu # <-- wrong, should be arm-*
If the detected host type doesn’t match what you passed, the script isn’t honoring --host the way
standard Autotools does — treat that as a signal to check the package’s own build instructions before going
further.
Category 2: Configure Scripts That Read the Host
Some configure scripts probe for dependencies by running pkg-config, checking
/usr/include, or invoking a helper binary — all of which default to the host unless every one of those
lookups is redirected. This is exactly why PKG_CONFIG_LIBDIR matters (covered in the previous lecture),
but scripts can also hard-code paths like /usr/include directly, bypassing pkg-config entirely.
checking for libfoo... found in /usr/include (HOST path, not sysroot)
The fix is usually one of: passing an explicit --with-libfoo-include=$SYSROOT/usr/include flag if
the script supports it, or patching the configure/config.h template directly when it doesn’t.
Category 3: Scripts That Try to Run Cross-Compiled Code
Some build systems generate a small test program, compile it with the cross compiler, and then try to
execute it on the host to detect a feature at configure time. That fails immediately, because an
ARM binary can’t run on an x86 host.
checking whether byte ordering is bigendian... configure: error: in `/build/eplib':
configure: error: cannot run test program while cross compiling
Standard Autotools projects usually let you supply the answer manually via a cache variable
(ac_cv_*) to skip the runtime check. Non-standard scripts may need a QEMU user-mode emulation setup
instead, so the “cross-compiled” test binary can actually execute.
The Real Issue: Dependency Chains
Any single fix above is manageable. The real problem is scale: a package with a graphical interface or media
support can easily depend on 50-100 other libraries, each of which may hit one of the three categories above. Fixing
them one at a time, in dependency order, for a large package is realistically weeks of work — not because any one
fix is hard, but because there are so many of them.
| Approach | Best for | Cost |
|---|---|---|
| Manual cross compile, one package at a time | A handful of packages, learning the mechanics | High per-package effort, doesn’t scale |
| Buildroot | Small, focused embedded images | Learning curve, but dependency resolution is automatic |
| Yocto Project | Larger, more customizable distributions | Steeper learning curve, more powerful long-term |
| Native compilation on target-like hardware | When target CPU is fast enough (e.g. many SBCs) | Slower builds, but sidesteps cross-compile bugs entirely |
Common Mistakes
- Assuming every “configure” script is Autotools — some are hand-rolled and only look similar.
- Chasing a runtime-detection failure with more flags instead of just supplying the
ac_cv_*cache variable the check is trying to compute. - Manually cross compiling a package with a huge dependency tree instead of reaching for
Buildroot or Yocto once the count of dependencies gets past a handful.
Best Practices
- Before fixing a cross-compile failure, read the package’s own cross-compiling documentation — most
non-trivial projects have one, and it saves guessing which category the failure falls into. - Keep a personal notes file of
ac_cv_*overrides you’ve had to supply per architecture; they’re
reusable across projects. - Set a mental threshold (e.g. “more than 5 dependencies”) past which you switch to a build system instead of
continuing manually.
Chapter Summary: Where the Toolchain Fits
This closes out the toolchain chapter of the course. The toolchain — binutils, a C compiler, a C library, and
usually gdb — is the foundation every later stage depends on: nothing else in an embedded Linux build (root
filesystem, kernel, bootloader) can be produced without it working correctly first. You can obtain one from
crosstool-NG, a prebuilt distribution, or as part of a larger build system like Buildroot or the Yocto Project; the
right choice depends on project size, and it’s worth being deliberate and consistent about it rather than switching
mid-project.
Key Takeaways
- Cross-compile failures fall into three recurring categories: non-standard build systems, scripts reading the
host instead of the target, and scripts trying to execute cross-compiled binaries. - Each category has a targeted fix, but dependency chains make fixing packages one at a time unsustainable past a
handful of libraries. - Buildroot, Yocto, or native compilation on capable target hardware are the standard escape hatches once manual
cross compiling stops scaling.
Conclusion
Cross compiling by hand is a valuable skill to actually understand — it’s how you debug the black-box build
systems later — but it’s rarely the right production approach past a small number of packages. Recognize which of
the three failure categories you’re looking at, fix what’s genuinely worth fixing by hand, and know when to hand
the job to Buildroot or Yocto instead.
FAQ
How do I know if a configure script is standard Autotools or a lookalike?
Run it with --host set and check whether the reported host system type matches what you passed. If
it doesn’t, or the script doesn’t recognize --host at all, treat it as non-standard and check its own
documentation.
What is an ac_cv_* cache variable and how do I find the right one?
It’s an Autotools cache variable that stores the answer to a configure-time check. When a check fails because it
can’t execute a cross-compiled test binary, the error message or configure.ac source usually names the exact
variable to set on the command line to skip the runtime probe.
Can I just run cross-compiled binaries directly to answer these checks?
Not on the host CPU directly, but QEMU user-mode emulation can execute foreign-architecture binaries
transparently on Linux, which some build setups use specifically to satisfy these runtime checks.
At what point should I switch from manual cross compiling to Buildroot or Yocto?
There’s no fixed number, but once a single package pulls in more than a handful of transitive dependencies, the
per-package fixing cost usually exceeds the learning cost of a proper build system.
Is native compilation ever a legitimate alternative to cross compiling?
Yes — on target hardware fast enough to tolerate longer build times, native compilation avoids the entire class
of cross-compile-specific bugs, which is part of why some Linux distributions build natively rather than cross
compiling everything.
Toolchain Chapter Complete
Next up: the bootloader — how your embedded device comes to life and starts the boot process.
