What are Custom Root Filesystem Overlays in Linux-Free Embedded Linux Course online

PREV_LEC NEXT_LEC
Custom Root Filesystem Overlays
A free embedded linux course lecture from EmbeddedPathashala
Module 6.2
Buildroot Series
Beginner Friendly

Every free embedded systems course eventually reaches the point where the stock root filesystem is not enough – you have your own binary, your own init script, or a config file that has to land in a specific place on the target. Buildroot’s answer to this is the root filesystem overlay: a plain directory tree that gets copied on top of the generated rootfs at the very end of the build. This lecture shows exactly how that mechanism works and where its limits are.

Buildroot Overlay Root Filesystem Init Scripts Cross Toolchain Free Embedded Linux Course

What You Will Learn

  • What a Buildroot overlay is and precisely when it gets applied during the build
  • How to compile a standalone program with the Buildroot toolchain so it runs correctly on target
  • How to lay out an overlay directory and register it in the build configuration
  • Where overlays stop being the right tool, and a real package becomes necessary instead

Prerequisites

  • A working Buildroot configuration that already produces a booting rootfs image, covered in the previous lecture of this free linux device drivers course
  • Comfort with cross-compilation and the target sysroot, from earlier modules in this free linux kernel development course

What an Overlay Actually Is

A Buildroot overlay is nothing more than a directory on your host machine whose contents get recursively copied on top of the target root filesystem near the very end of the build, after every package has finished installing but before the final image (ext4, squashfs, tar, and so on) is packaged up. There is no special format, no manifest file, and no build step of its own – if a file exists in the overlay directory at the path bin/ep_monitor, it lands at exactly /bin/ep_monitor on the target.

This makes overlays the right tool for two very different jobs: dropping in a handful of files you already have (an init script, a config file, a certificate), or, combined with the toolchain, dropping in a compiled program you built separately from Buildroot’s own package system.

Where the Overlay Fits in the Build
1. toolchain build → 2. kernel build → 3. packages installed to staging → 4. root filesystem skeleton assembled → 5. OVERLAY COPIED ON TOP → 6. final image (ext4 / squashfs / tar) generated

Compiling a Standalone Program for the Target

Before a compiled binary can go into an overlay, it has to be built with the same toolchain, and against the same C library, that Buildroot used for every other package on the target – mixing an ABI from your host’s native compiler with a target built by a different toolchain is a common source of mysterious crashes. Buildroot always builds its own toolchain under output/host, and the simplest way to use it outside of Buildroot’s own package system is to put it first on your PATH:

$ export PATH=$(pwd)/output/host/usr/bin:$PATH
$ ${'$'}{ARCH}-linux-gcc --version

Every cross tool Buildroot generated is prefixed with the target triplet, for example arm-linux-gnueabihf-gcc or aarch64-linux-gcc depending on your board. As a concrete example, here is a tiny original status-reporting utility – not the book’s demo program, just a small original tool for this lecture – that we will place on the target with an overlay:

/* ep_monitor.c - reports board uptime once, for overlay demo purposes */
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE *f = fopen("/proc/uptime", "r");
    if (!f) {
        perror("ep_monitor: fopen");
        return EXIT_FAILURE;
    }

    double uptime_seconds;
    if (fscanf(f, "%lf", &uptime_seconds) != 1) {
        fprintf(stderr, "ep_monitor: failed to read uptime\n");
        fclose(f);
        return EXIT_FAILURE;
    }
    fclose(f);

    printf("ep_monitor: board has been up for %.0f seconds\n", uptime_seconds);
    return EXIT_SUCCESS;
}
$ arm-linux-gnueabihf-gcc -O2 -o ep_monitor ep_monitor.c
$ file ep_monitor
ep_monitor: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked

Laying Out the Overlay Directory

The overlay directory mirrors the target’s own filesystem layout starting from the root. To ship ep_monitor in /usr/bin and start it automatically at boot with a BusyBox-style init script, the overlay tree looks like this:

Overlay Directory Layout
board/epboard/overlay/ usr/bin/ep_monitor (the cross-compiled binary) etc/init.d/S60ep_monitor (startup script, executable)
$ mkdir -p board/epboard/overlay/usr/bin board/epboard/overlay/etc/init.d
$ cp ep_monitor board/epboard/overlay/usr/bin/
$ chmod 755 board/epboard/overlay/usr/bin/ep_monitor
#!/bin/sh
# board/epboard/overlay/etc/init.d/S60ep_monitor
case "$1" in
  start)
    /usr/bin/ep_monitor
    ;;
  stop)
    ;;
  *)
    echo "Usage: $0 {start|stop}"
    exit 1
    ;;
esac
exit 0

Registering the Overlay

Buildroot needs to be told where the overlay directory lives, which you can do either through menuconfig or directly by hand in the option BR2_ROOTFS_OVERLAY:

Menuconfig Path
System configuration Root filesystem overlay directories → board/epboard/overlay

This field accepts a space-separated list, so you can stack several overlays – a common pattern is one overlay shared across all boards for common files, and one board-specific overlay layered on top for hardware-specific configuration. Buildroot copies them in the order listed, and later entries win on any file path collision.

$ make
$ ls output/target/usr/bin/ep_monitor
output/target/usr/bin/ep_monitor

Two Details That Save Debugging Time

The permissions and ownership of every file placed in the root filesystem are ultimately controlled by system/skeleton for the base layout, and by device_table.txt style permission tables for anything that needs a specific UID, GID, or device node that a plain file copy cannot express – overlays alone cannot create device nodes or set non-default ownership, since a host-side directory copy has no concept of target UIDs beyond what your host filesystem happens to record.

Second, Buildroot does not rebuild an overlay’s contents – if you change ep_monitor.c and recompile it, you must recopy the binary into the overlay directory yourself before running make again, because the overlay step is a dumb copy, not a build rule with its own dependency tracking.

Common Mistakes and Troubleshooting

SymptomLikely CauseFix
Program segfaults immediately on targetBinary built with the host’s native compiler instead of the Buildroot cross toolchainRebuild with the prefixed cross compiler from output/host/usr/bin
Init script never runs at bootScript not executable, or missing the correct S<NN> prefix expected by the init systemchmod 755 the script and check the numeric ordering against other S* scripts
File appears to vanish after rebuildA package installed later overwrote the same pathList your overlay after that package’s install step, or use a distinct path
Overlay changes seem to have no effectOld binary was still sitting in the overlay directoryRecopy the freshly built binary before rerunning make

Best Practices

  • Keep overlays small – a handful of files and scripts, not entire application trees with their own build process
  • Use a Buildroot package instead of an overlay once a program needs to be compiled as part of the Buildroot build itself, covered in the next lecture
  • Separate a shared, board-independent overlay from a board-specific one so common configuration is not duplicated per board
  • Never hand-edit files inside output/target directly – those changes are silently discarded on the next build

Summary and Key Takeaways

  • An overlay is a plain directory copied on top of the target root filesystem at the end of the build, with no build logic of its own
  • Anything compiled for an overlay must use Buildroot’s own cross toolchain to match the target ABI and C library
  • BR2_ROOTFS_OVERLAY accepts multiple space-separated directories, applied in order

Conclusion

Overlays are the fastest path from “I have a file” to “that file is on my board,” which is exactly why they show up so early in almost every free linux device drivers course. They are intentionally simple, and that simplicity is also their boundary: the moment your own code needs its own build rules, dependency tracking, or version pinning inside the Buildroot tree, it is time to graduate from an overlay to a real Buildroot package, which is exactly what the next lecture in this free embedded systems course covers.

Frequently Asked Questions

Can an overlay create device nodes?

No. Overlays are a plain file copy. Special files and non-default permissions need a device table or a proper Buildroot package.

Does Buildroot rebuild files inside an overlay automatically?

No. The overlay step only copies whatever is currently in the overlay directory – you must update the source file yourself before the next build.

Can I use more than one overlay directory?

Yes. BR2_ROOTFS_OVERLAY accepts a space-separated list, applied in order, with later overlays winning on path conflicts.

Why did my program crash only on the target, not on my host?

This almost always means it was compiled with the host’s native compiler instead of Buildroot’s cross toolchain, producing a binary linked against the wrong C library.

Should application source code always be added as an overlay?

Only for small, already-built artifacts. Anything that needs its own compile step inside the Buildroot build belongs in a proper package instead.

Where do overlay files end up if there is a path collision with a package?

Whichever overlay or package installs last during the build wins, so ordering in BR2_ROOTFS_OVERLAY and package install order both matter.

Continue the Free Embedded Linux Course

Next up: turning your own program into a real Buildroot package with Config.in and a makefile.

Next Lecture Browse the Full Course
PREV_LEC NEXT_LEC

2 Comments

Leave a Reply

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