What is Picking An Embedded C Library in Linux-Free Embedded Linux Course

Picking An Embedded C Library

glibc, musl, or uClibc-ng: the C library you pick decides your binary size, your POSIX coverage, and how much pain you feel later.

glibc 2.44 is the current stable release
musl 1.2.6 is the current stable release
3 major C libraries dominate embedded Linux today
free embedded linux course
free linux kernel development course
free linux device drivers course
free embedded systems course

What You Will Learn

What a C library actually does for you
glibc vs musl vs uClibc-ng, compared honestly
Why eglibc no longer exists
How the toolchain tuple encodes your ABI choice
Where to get a trustworthy prebuilt toolchain in 2026

Prerequisites

Comfortable with the toolchain basics from the previous lecture
Know what a target tuple like arm-linux-gnueabihf means

The C Library Is the Gateway to the Kernel

Every Linux program eventually needs the kernel to do something for it: open a file, allocate memory, read from a socket. The C library is the layer that turns familiar function calls like printf(), malloc(), or open() into the actual system calls the kernel understands. Even languages that are not C, Python or Rust included, ultimately route through a C library at the bottom of their runtime.

Application to Kernel, via the C Library
Your application → C library (glibc / musl / uClibc-ng) → system call interface → Linux kernel

It is technically possible to bypass the C library and issue kernel system calls directly, and some extremely small init programs do exactly that, but for almost all real applications it is unnecessary effort for very little gain.

The Three C Libraries That Matter in 2026

The book-era landscape included eglibc as a fourth option. It no longer exists as a separate project: its configuration improvements were merged back into glibc as of glibc 2.20, and the eglibc project itself has been dead for years. Today the real decision is between three libraries.

Library Current release Best for Trade-off
glibc 2.44 Full POSIX coverage, general-purpose boards with enough storage Largest footprint of the three
musl 1.2.6 Small, fast, static-link-friendly systems; Alpine-style containers Intentionally minimal, some rarely used glibc extensions are absent
uClibc-ng Actively maintained fork of the original uClibc Very constrained MMU-less or tiny-flash devices Not as complete a POSIX implementation as glibc

How to Actually Decide

Ignore brand loyalty and ask three questions. First, how much storage do you have? If your rootfs has to fit in a few megabytes of NOR flash, musl or uClibc-ng will win every time. Second, does anything you depend on require full glibc POSIX or NSS (name service switch) support, such as certain networking or user/group lookup features? If yes, glibc is the safer default. Third, are you statically linking a lot of small utilities? musl was designed for exactly that use case and produces noticeably smaller static binaries than glibc.

A practical default for 2026: reach for glibc unless you have a specific, measured reason not to. Reach for musl when image size or static linking really matters and you’ve confirmed your dependencies build cleanly against it (most mainstream packages do now, thanks to years of musl adoption in container base images like Alpine). Reserve uClibc-ng for genuinely constrained, MMU-less, or legacy targets.

Choosing a C Library
Question Answer favors
Storage under a few MB? musl or uClibc-ng
Need full POSIX / NSS support? glibc
Heavy static linking of small tools? musl
MMU-less or legacy silicon? uClibc-ng
Not sure yet? glibc (safest general default)

The Target Tuple Encodes Your C Library Choice

Recall the dash-separated target tuple from the previous lecture. The final segment names both the operating system and, often, the ABI and C library: gnu means glibc, musl means musl, and uclibcgnu style suffixes indicate uClibc-ng builds. On 32-bit ARM you will also see the float ABI folded in, giving names like arm-linux-gnueabihf (glibc, hard-float) or arm-linux-musleabihf (musl, hard-float). Always read the full tuple before you trust a toolchain; guessing from the filename alone is a common source of mismatched builds.

Finding a Toolchain That Matches Your C Library

You have three realistic paths to a working cross toolchain, and they haven’t changed in spirit since this course’s source material, only in where you actually get them.

Source 2026 reality
Official Arm GNU Toolchain Arm now publishes and maintains these directly at developer.arm.com; the old Linaro-branded binary releases are end-of-life and should not be used for new projects
Bootlin prebuilt toolchains Over 200 free, ready-to-use cross toolchains at toolchains.bootlin.com covering glibc, uClibc-ng, and musl across many architectures, rebuilt and refreshed on a regular release cadence
Build system SDKs Buildroot and the Yocto Project both generate a toolchain matched exactly to your chosen C library as part of building your image
Build it yourself crosstool-NG, covered in the next lecture, gives you full control over every component and version

Whichever path you take, verify the C library before you commit: run ldd --version or check the toolchain’s sysroot for tell-tale files (a libmusl loader for musl, or ld-linux.so.2 style names for glibc) so you know exactly what you’re shipping.

Try It: Confirm Which C Library a Toolchain Uses

A tiny original program, ep_libcheck.c, prints back the size of a common libc struct, which is a fast smoke test that your headers and library actually agree with each other:

#include <stdio.h>
#include <sys/utsname.h>

int main(void)
{
    printf("sizeof(struct utsname) = %zu bytes\n", sizeof(struct utsname));
    return 0;
}
$ aarch64-linux-gnu-gcc ep_libcheck.c -o ep_libcheck
$ ./ep_libcheck
sizeof(struct utsname) = 390 bytes

$ file ep_libcheck
ep_libcheck: ELF 64-bit LSB pie executable, ARM aarch64, dynamically linked, interpreter /lib/ld-linux-aarch64.so.1

The interpreter path in the file output, ld-linux-aarch64.so.1, is glibc’s dynamic linker. A musl-built binary would instead show an interpreter path containing musl, such as /lib/ld-musl-aarch64.so.1.

Common Mistakes

Mistake Why it hurts
Downloading a legacy Linaro toolchain tarball found via an old blog post These are end-of-life, unpatched, and may not match current kernel headers
Assuming all glibc versions behave identically Notable ABI-visible changes have landed over the years; always match the glibc version to what your target’s rootfs actually ships
Switching C libraries mid-project without rebuilding every dependency Mixed glibc/musl objects are not link-compatible
Ignoring NSS features when picking musl musl’s NSS support is intentionally minimal; DNS or user lookups that rely on glibc-specific NSS modules may behave differently

Best Practices

Match your C library choice to real constraints, not habit
Use Bootlin or Arm’s official toolchains instead of unmaintained mirrors
Let Buildroot or Yocto generate a matched toolchain when you’re already using one of them
Record the exact glibc/musl version in your project’s build documentation
Re-test thoroughly if you ever change C libraries later in a project’s life

Summary and Key Takeaways

The C library is the bridge between your application and the kernel, and in 2026 the real decision is between glibc, musl, and uClibc-ng, since eglibc was folded back into glibc years ago. glibc remains the safest general default, musl shines when size and static linking matter, and uClibc-ng is for genuinely constrained hardware. The target tuple tells you which one a given toolchain was built with, and trustworthy prebuilt toolchains now come from Arm’s official downloads, Bootlin, or your build system’s own SDK rather than aging third-party mirrors.

Next, we roll up our sleeves and build a toolchain completely from source using crosstool-NG, so you understand every one of these pieces from the inside.

FAQ

Is eglibc still a thing in 2026?

No. eglibc’s improvements were merged back into glibc as of version 2.20, and the eglibc project has been discontinued for years. Any reference to eglibc today is purely historical.

Which C library should a beginner start with?

glibc. It has the most complete POSIX support and the largest amount of documentation and community troubleshooting available, which matters most while you’re still learning.

Can I mix musl and glibc binaries on the same target?

You can run both on the same system as long as each binary is dynamically linked against its own matching library and dynamic linker, but you cannot link a single binary against both.

Are Linaro prebuilt toolchains still safe to use?

No. The Linaro-branded binary toolchain releases are now classified as legacy and end-of-life, with no further security patches. Use the official Arm GNU Toolchain or Bootlin toolchains instead.

What is uClibc-ng, and how is it different from the original uClibc?

uClibc-ng is the actively maintained fork that continues development after the original uClibc project became largely inactive. It targets the same very small footprint use cases, including MMU-less systems.

How do I tell which C library a prebuilt toolchain uses without reading documentation?

Compile a small test program and inspect the interpreter path with the file or readelf command. A glibc binary shows a path like ld-linux-aarch64.so.1, while a musl binary shows a path containing musl, such as ld-musl-aarch64.so.1.

Does musl support everything glibc supports?

Not quite. musl deliberately omits some rarely used glibc extensions and has more limited NSS (name service switch) support, in exchange for a much smaller and simpler codebase.

 

Next: build a toolchain from source with crosstool-NG

 

 

Leave a Reply

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