$npx -y skills add mohitmishra786/low-level-dev-skills --skill cross-gccCross-compilation with GCC skill for embedded and multi-architecture targets. Use when setting up cross-gcc toolchains, configuring sysroots, building for ARM/AArch64/RISC-V/MIPS from an x86-64 host, troubleshooting wrong-architecture errors, or running cross-compiled binaries un
| 1 | # Cross-GCC |
| 2 | |
| 3 | ## Purpose |
| 4 | |
| 5 | Guide agents through setting up and using cross-compilation GCC toolchains: triplets, sysroots, pkg-config, QEMU-based testing, and common failure modes. |
| 6 | |
| 7 | ## Triggers |
| 8 | |
| 9 | - "How do I compile for ARM on my x86 machine?" |
| 10 | - "I'm getting 'wrong ELF class' or 'cannot execute binary file'" |
| 11 | - "How do I set up a sysroot for cross-compilation?" |
| 12 | - "pkg-config returns host libraries in my cross build" |
| 13 | - "How do I debug a cross-compiled binary with QEMU + GDB?" |
| 14 | |
| 15 | ## Workflow |
| 16 | |
| 17 | ### 1. Understand the triplet |
| 18 | |
| 19 | A GNU triplet has the form `<arch>-<vendor>-<os>-<abi>` (often 3 or 4 parts): |
| 20 | |
| 21 | | Triplet | Target | |
| 22 | |---------|--------| |
| 23 | | `aarch64-linux-gnu` | 64-bit ARM Linux (glibc) | |
| 24 | | `arm-linux-gnueabihf` | 32-bit ARM Linux hard-float | |
| 25 | | `arm-none-eabi` | Bare-metal ARM (no OS) | |
| 26 | | `riscv64-linux-gnu` | 64-bit RISC-V Linux | |
| 27 | | `x86_64-w64-mingw32` | Windows (MinGW) from Linux | |
| 28 | | `mipsel-linux-gnu` | Little-endian MIPS Linux | |
| 29 | |
| 30 | ### 2. Install the toolchain |
| 31 | |
| 32 | ```bash |
| 33 | # Debian/Ubuntu |
| 34 | sudo apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu binutils-aarch64-linux-gnu |
| 35 | |
| 36 | # For bare-metal ARM (Cortex-M) |
| 37 | sudo apt install gcc-arm-none-eabi binutils-arm-none-eabi |
| 38 | |
| 39 | # Verify |
| 40 | aarch64-linux-gnu-gcc --version |
| 41 | ``` |
| 42 | |
| 43 | ### 3. Basic cross-compilation |
| 44 | |
| 45 | ```bash |
| 46 | # C |
| 47 | aarch64-linux-gnu-gcc -O2 -o hello hello.c |
| 48 | |
| 49 | # C++ |
| 50 | aarch64-linux-gnu-g++ -O2 -std=c++17 -o hello hello.cpp |
| 51 | |
| 52 | # Bare-metal (no stdlib, no OS) |
| 53 | arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 \ |
| 54 | -ffreestanding -nostdlib -T linker.ld -o firmware.elf startup.s main.c |
| 55 | ``` |
| 56 | |
| 57 | ### 4. Sysroot |
| 58 | |
| 59 | A sysroot is a directory containing the target's headers and libraries. Required when your code links against target-specific libraries. |
| 60 | |
| 61 | ```bash |
| 62 | # Use a sysroot |
| 63 | aarch64-linux-gnu-gcc --sysroot=/path/to/aarch64-sysroot -O2 -o prog main.c |
| 64 | |
| 65 | # Common sysroot sources: |
| 66 | # - Raspberry Pi: download from raspbian/raspios |
| 67 | # - Debian multiarch: debootstrap --arch arm64 bullseye /tmp/sysroot |
| 68 | # - Yocto/Buildroot: generated automatically in build output |
| 69 | ``` |
| 70 | |
| 71 | Verify the sysroot is correct: |
| 72 | |
| 73 | ```bash |
| 74 | aarch64-linux-gnu-gcc --sysroot=/path/to/sysroot -v -E - < /dev/null 2>&1 | grep sysroot |
| 75 | ``` |
| 76 | |
| 77 | ### 5. pkg-config for cross builds |
| 78 | |
| 79 | `pkg-config` will return host library paths by default. Override: |
| 80 | |
| 81 | ```bash |
| 82 | export PKG_CONFIG_SYSROOT_DIR=/path/to/sysroot |
| 83 | export PKG_CONFIG_LIBDIR=${PKG_CONFIG_SYSROOT_DIR}/usr/lib/aarch64-linux-gnu/pkgconfig:${PKG_CONFIG_SYSROOT_DIR}/usr/share/pkgconfig |
| 84 | export PKG_CONFIG_PATH= # clear host path |
| 85 | |
| 86 | pkg-config --libs libssl # now returns target paths |
| 87 | ``` |
| 88 | |
| 89 | ### 6. CMake cross-compilation |
| 90 | |
| 91 | Create a toolchain file `aarch64.cmake`: |
| 92 | |
| 93 | ```cmake |
| 94 | set(CMAKE_SYSTEM_NAME Linux) |
| 95 | set(CMAKE_SYSTEM_PROCESSOR aarch64) |
| 96 | |
| 97 | set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc) |
| 98 | set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++) |
| 99 | |
| 100 | set(CMAKE_SYSROOT /path/to/aarch64-sysroot) |
| 101 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) |
| 102 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) |
| 103 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) |
| 104 | ``` |
| 105 | |
| 106 | ```bash |
| 107 | cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=aarch64.cmake |
| 108 | cmake --build build |
| 109 | ``` |
| 110 | |
| 111 | ### 7. Test with QEMU |
| 112 | |
| 113 | ```bash |
| 114 | # User-mode emulation (Linux binaries, no full OS) |
| 115 | sudo apt install qemu-user-static |
| 116 | |
| 117 | qemu-aarch64-static ./hello |
| 118 | # Or set binfmt_misc for transparent execution: |
| 119 | # Then just: ./hello |
| 120 | |
| 121 | # GDB remote debug via QEMU |
| 122 | qemu-aarch64-static -g 1234 ./hello & |
| 123 | aarch64-linux-gnu-gdb -ex "target remote :1234" ./hello |
| 124 | ``` |
| 125 | |
| 126 | ### 8. Common errors |
| 127 | |
| 128 | | Error | Cause | Fix | |
| 129 | |-------|-------|-----| |
| 130 | | `cannot execute binary file: Exec format error` | Running target binary on host without QEMU | Use `qemu-<arch>-static` | |
| 131 | | `wrong ELF class: ELFCLASS64` (or 32) | Wrong-architecture object linked | Check triplet; ensure all objects use same toolchain | |
| 132 | | `/usr/bin/ld: cannot find -lfoo` | Host library path used for cross-link | Set `--sysroot`; fix `PKG_CONFIG_LIBDIR` | |
| 133 | | `undefined reference to '__aeabi_*'` | Missing ARM ABI runtime | Link with `-lgcc` or `-lclang_rt.builtins` | |
| 134 | | `relocation R_AARCH64_ADR_PREL_PG_HI21 out of range` | Distance too large | Use `-mcmodel=large` or restructure | |
| 135 | | `unrecognized opcode` | Wrong `-mcpu` or `-march` | Set correct CPU flags for target | |
| 136 | |
| 137 | ### 9. Environment variables |
| 138 | |
| 139 | ```bash |
| 140 | # Tell build systems to use cross-compiler |
| 141 | export CC=aarch64-linux-gnu-gcc |
| 142 | export CXX=aarch64-linux-gnu-g++ |
| 143 | export AR=aarch64-linux-gnu-ar |
| 144 | export STRIP=aarch64-linux-gnu-strip |
| 145 | export OBJDUMP=aarch64-linux-gnu-objdump |
| 146 | |
| 147 | # For autoconf projects |
| 148 | ./configure --host=aarch64-linux-gnu --prefix=/usr |
| 149 | ``` |
| 150 | |
| 151 | For a refe |