Cross-compiles netopeer2 and its full dependency stack for x86_64, ARM32 (armhf), and ARM64 (aarch64) inside Docker, and produces a ready-to-use sysroot for each architecture.
For each target architecture the build compiles, in order, and installs everything into a shared per-arch sysroot:
- zlib
- openssl
- libssh
- libpsl
- libxcrypt
- pcre
- curl
- libyang
- sysrepo
- libnetconf2
- netopeer2
- cJSON
- rabbitmq-c
Later libraries in the list are linked against the ones built before them (e.g.
libssh/curl against openssl and zlib; libyang/sysrepo/libnetconf2/netopeer2
against all of the above), so they must be built in this order — which is exactly what
scripts/build_all.sh does.
.
├── build.sh # entry point — run this
├── docker-compose.yml # builds the image and runs the build inside it
├── Dockerfile # Ubuntu 24.04 + cross toolchains for arm32/arm64
├── toolchain-x86.cmake # CMake toolchain file used for the x86_64 build
├── toolchain-arm32.cmake # CMake toolchain file for the armhf build
├── toolchain-arm64.cmake # CMake toolchain file for the aarch64 build
└── scripts/
├── build_all.sh # runs all three per-arch installs in sequence
└── install/
├── x86/install_x86.sh # native x86_64 build
├── arm32/install_arm32.sh # cross build for armhf (arm-linux-gnueabihf-*)
└── arm64/install_arm64.sh # cross build for aarch64 (aarch64-linux-gnu-*)
-
Docker Engine with the Compose plugin (
docker compose ..., not the standalonedocker-compose). -
Enough free disk space for three full dependency builds (a few GB).
-
sudo/write access to/opton the host — the final step ofbuild.shcopies the build output there. -
Source trees for every dependency listed above, placed in the repository root (the same directory as
build.sh), using exactly these folder names:zlib/ openssl/ libssh/ libpsl/ libxcrypt/ pcre/ curl/ libyang/ sysrepo/ libnetconf2/ netopeer2/ cJSON/ rabbitmq-c/These are not checked into this repository (only the build scripts and toolchain files are).
DockerfiledoesCOPY . /build, so whatever sits next tobuild.shat build time is what gets compiled — pull in the versions of each library your project is standardized on before running the build. Thescripts/install/*scripts assume each folder is a normal, unbuilt source checkout (e.g. openssl/curl/libpsl/libxcrypt/pcre need their./configurescript present; the CMake-based projects just need their top-levelCMakeLists.txt).
You do not need to install the ARM cross-compilers yourself — Dockerfile installs
gcc/g++/binutils for both arm-linux-gnueabihf and aarch64-linux-gnu automatically
when the image is built.
From the repository root, with all dependency source folders in place:
./build.shThis does the following:
- Removes any existing
./sysrootsdirectory from a previous run. - Runs
docker compose up --build, which:- Builds the
library_builderimage fromDockerfile(installs build tools and the ARM cross-toolchains, then copies the whole repo, including your dependency sources, into/buildin the image). - Runs
scripts/build_all.shin a container, which builds x86_64 first, then arm32, then arm64, writing all output to/opt/sysrootsinside the container. That path is volume-mounted to./sysrootson the host, so the result lands there as the build progresses.
- Builds the
- Copies the finished
./sysrootsdirectory to/opt/sysrootson the host (needs permission to write to/opt, hencesudomay be required — runsudo ./build.shif you get a permission error on this step).
A full run builds all three architectures back to back; expect it to take a while, since ARM builds are cross-compiled from source with no caching between architectures.
Re-running ./build.sh wipes ./sysroots and rebuilds everything from scratch. On the
very first run, the rm -r ./sysroots step will print a harmless
"No such file or directory" error since there's nothing to remove yet — this does not
stop the build.
After a successful build, each architecture gets its own sysroot under
/opt/sysroots/:
/opt/sysroots/
├── x86_64/
│ ├── lib/ # all built .so/.a files, flattened together
│ ├── include/ # all headers, flattened together
│ ├── pkgconfig/ # all .pc files, flattened together
│ ├── zlib-x86/ # per-library install prefix (lib/, include/, ...)
│ ├── openssl-x86/
│ ├── libssh-x86/
│ ├── ...
│ └── netopeer2-x86/
├── arm32/ # same structure, "-arm32" suffixed prefixes
└── arm64/ # same structure, "-arm64" suffixed prefixes
The flattened lib/, include/, and pkgconfig/ directories at the top of each arch
folder are what the CMake toolchain files (toolchain-x86.cmake,
toolchain-arm32.cmake, toolchain-arm64.cmake) point downstream builds at via
CMAKE_FIND_ROOT_PATH and PKG_CONFIG_PATH — use those toolchain files if you need to
build additional software (e.g. an application linking against netopeer2) against one
of these sysroots outside of this repo.
- The toolchain files hardcode
/opt/sysroots/<arch>/...paths, so the sysroots must end up at that exact location on the host for downstream builds to find them — this is whybuild.shcopies./sysrootsto/opt/sysrootsafter the container finishes. docker-compose.ymlbuilds a single service (alpha) that runs the entire three-architecture build sequentially; there's currently no way to build just one architecture without editingscripts/build_all.sh.