Skip to content

Cross Compile ARM Cortex-A9 (glibc Toolchain)

Step-by-step guide for cross-compiling inotify-tools for ARM Cortex-A9 using a glibc-based OpenWrt toolchain, including static build and troubleshooting


Critical First Step: Match the libc

Your toolchain is named: …glibc_eabi

This means it produces binaries that require glibc on the target router.

Before building anything, verify which libc the router uses.

Check libc on the router

# Which libc is installed?
ls -l /lib/libc.so* 2>/dev/null
strings /lib/libc.so* 2>/dev/null | head

What to look for

If you see:

  • /lib/ld-musl-... → Router uses musl
  • uClibc references → Router uses uClibc
  • /lib/ld-linux.so.3 or similar → Router uses glibc

If the router does not use glibc, a glibc-built binary will fail immediately.

Your options if libc mismatches

1) Use a toolchain matching the router’s libc 2) Build statically (if static libs are available) 3) Use an OpenWrt package built specifically for your firmware (often easiest)

Set Up the Toolchain

export TC=/mnt/usb/firmware/technicolor_toolchain/toolchain-arm_cortex-a9+neon_gcc-4.8-linaro_glibc_eabi
export PATH="$TC/bin:$PATH"

export TARGET=arm-openwrt-linux-gnueabi

export CC=${TARGET}-gcc
export AR=${TARGET}-ar
export RANLIB=${TARGET}-ranlib
export STRIP=${TARGET}-strip

Sanity Check

$CC -v
${TARGET}-gcc -dumpmachine

Build inotify-tools (provides inotifywait)

mkdir -p /tmp/build-inotify && cd /tmp/build-inotify
wget -O inotify-tools.tar.gz https://github.com/inotify-tools/inotify-tools/archive/refs/tags/3.22.6.0.tar.gz
tar xf inotify-tools.tar.gz
cd inotify-tools-3.22.6.0

If your build machine has no internet access, transfer the tarball manually.

Configure for Cross Compilation

export DEST=/tmp/inotify-staging
rm -rf "$DEST"
mkdir -p "$DEST"

./autogen.sh 2>/dev/null || true

./configure \
  --host="$TARGET" \
  --build="$(gcc -dumpmachine)" \
  --prefix=/usr

Compile and Install

make -j"$(nproc)"
make DESTDIR="$DEST" install
  • Verify:
ls -l "$DEST/usr/bin/inotifywait"
file "$DEST/usr/bin/inotifywait"
  • Strip for smaller size:
$STRIP --strip-all "$DEST/usr/bin/inotifywait"

Transfer to Router

From build machine:

scp "$DEST/usr/bin/inotifywait" root@ROUTER_IP:/tmp/
  • On the router:
chmod +x /tmp/inotifywait
/tmp/inotifywait --help

Monitor Directory and Log

/tmp/inotifywait -m -e create,delete,modify,move /tmp/watchdir \
  --format '%T %e %w%f' --timefmt '%F %T' \
  >> /tmp/inotify.log

Static Build (Maximum Compatibility)

Static builds are useful if:

  • glibc version mismatches
  • Dynamic loader errors occur
  • First check if static libraries exist:

    find "$TC" -name "libc.a" -o -name "libpthread.a" | head
    
  • If they exist:

    export CFLAGS="-Os -pipe"
    export LDFLAGS="-static"
    
    ./configure \
      --host="$TARGET" \
      --build="$(gcc -dumpmachine)" \
      --prefix=/usr \
      --disable-man \
      --disable-nls
    
    make clean
    make -j"$(nproc)"
    make DESTDIR="$DEST" install
    $STRIP --strip-all "$DEST/usr/bin/inotifywait"
    
  • Verify:

    file "$DEST/usr/bin/inotifywait"
    ${TARGET}-readelf -d "$DEST/usr/bin/inotifywait" | head
    

A static binary should show no NEEDED dependencies in readelf -d.

Troubleshooting

If you get an error similiar to ./inotifywait: error while loading shared libraries: libinotifytools.so.0: cannot open shared object file: No such file or directory

1) Grab the missing library from your staging dir

On your build machine, it should be here:

```bash
ls -l /tmp/inotify-staging/usr/lib/libinotifytools.so*

lrwxrwxrwx 1 root root     24 Feb 11 17:05 /tmp/inotify-staging/usr/lib/libinotifytools.so -> libinotifytools.so.0.4.1
lrwxrwxrwx 1 root root     24 Feb 11 17:05 /tmp/inotify-staging/usr/lib/libinotifytools.so.0 -> libinotifytools.so.0.4.1
-rwxr-xr-x 1 root root 103594 Feb 11 17:05 /tmp/inotify-staging/usr/lib/libinotifytools.so.0.4.1
```

On your build machine: package a tiny runtime folder

This makes transfer easy even without SFTP

mkdir -vp /tmp/inotify-runtime/lib

cp -v /tmp/inotify-staging/usr/bin/inotifywait /tmp/inotify-runtime/
cp -va /tmp/inotify-staging/usr/lib/libinotifytools.so* /tmp/inotify-runtime/lib/

# optional: shrink
arm-openwrt-linux-gnueabi-strip --strip-all /tmp/inotify-runtime/inotifywait || true
arm-openwrt-linux-gnueabi-strip --strip-all /tmp/inotify-runtime/lib/libinotifytools.so.0.4.1 || true

# tar it
tar -C /tmp -czf /tmp/inotify-runtime.tgz inotify-runtime
ls -lh /tmp/inotify-runtime.tgz

-rw-r--r-- 1 root root 66K Feb 11 17:22 /tmp/inotify-runtime.tgz

On the router: unpack to /tmp (or USB) and run

mkdir -p /tmp/inotify
tar -C /tmp/inotify -xzf /tmp/run/mountd/sda/inotify-runtime.tgz

/tmp/inotify/inotify-runtime/inotifywait
/tmp/inotify/inotify-runtime/lib/libinotifytools.so.0 -> libinotifytools.so.0.4.1
/tmp/inotify/inotify-runtime/lib/libinotifytools.so.0.4.1

If your tarball is stored somewhere else, just adjust the path.

  • You should end up with:

Set LD_LIBRARY_PATH before running

cd /tmp/inotify/inotify-runtime
export LD_LIBRARY_PATH="$PWD/lib"
./inotifywait --help

To get inotifywait to works by /usr/bin

Create /usr/bin/inotifywait wrapper script

cat > /usr/bin/inotifywait <<'EOF'
#!/bin/sh
BASE="/tmp/run/mountd/sda/inotify-runtime"
export LD_LIBRARY_PATH="$BASE/lib"
exec "$BASE/inotifywait" "$@"
EOF
chmod +x /usr/bin/inotifywait

Setup watch for /tmp directory

inotifywait -m -r \
-e create -e modify -e delete -e moved_to -e moved_from \
--format 'File: %w%f was %e' \
/tmp
  • You´re done! Happy inotifying.