Cross-compile OpenCV with a target root filesystem
This example builds an OpenCV program on an x86_64 host for an AArch64 Linux target. The target's headers and libraries are copied into a local sysroot. CMake then searches that sysroot while the cross-compiler produces an AArch64 executable. Finally, the executable is copied to the target and tested over SSH without X11 or a desktop session.
The process is:
- Copy
/liband/usrfrom the target to a sysroot on the host. - Configure CMake with an AArch64 toolchain file and the sysroot.
- Build and link against the target's OpenCV libraries.
- Copy the executable to the target with
scp. - Run it through SSH and verify the generated PNG.
The sysroot and compiler must target the same architecture and ABI. This example uses the GNU/glibc AArch64 toolchain because the target root filesystem contains glibc libraries.
ABI
ABI means Application Binary Interface. While an API defines how source code calls functions, an ABI defines how compiled machine code works together. It includes calling conventions, register use, data type sizes and alignment, symbol naming, object-file format, and the expected runtime libraries and dynamic loader. Two systems can both use AArch64 but still be incompatible if, for example, one executable expects glibc and the other system provides musl.
Match the compiler to the target ABI
Copying headers and libraries from the target is not enough if the compiler
produces binaries for a different ABI. Check the target with uname -m,
inspect the executable with file build-arm/hello_cv, and use ldd on the
target executable. The architecture, libc, dynamic loader, and linked
libraries must agree.
Install prerequisites
Install rsync on both the host and target. On the host, also install the
AArch64 cross-compiler and CMake:
Configure SSH
Add a short name for the target to the host's SSH configuration:
Test the connection before continuing:
The expected architecture is aarch64.
Create the sysroot
Create a local directory on the host:
-L follows symbolic links so the sysroot receives the actual library files.
Run the same command again whenever packages such as OpenCV are updated on the
target.
Create the CMake toolchain file
The toolchain file tells CMake that this is a cross-build, selects the AArch64 compilers, and restricts library, header, and package searches to the copied sysroot. Host programs needed during the build are still found on the host.
ABI libc version
target hardware: radxa zero 3w target os: debian kernel 6.1 libcxx: GLIBCXX_3.4.30
Use gnu compiler version 12
| Setting | Search behavior | Reason |
|---|---|---|
| PROGRAM NEVER | Search host paths | Build tools must run on the host. |
| LIBRARY ONLY | Search the target sysroot | Link target-compatible libraries. |
| INCLUDE ONLY | Search the target sysroot | Use headers installed on the target. |
| PACKAGE ONLY | Search the target sysroot | Find target CMake packages. |
Define the application
find_package(OpenCV) now finds the target's OpenCV package inside the
sysroot. The resulting include paths and libraries are used to build
hello_cv.
The application creates an image in memory, draws a rectangle and text, and
writes the result with cv::imwrite(). It does not call cv::imshow() or
cv::waitKey(), so it does not need X11 and can run in a headless SSH session.
Code example
The program performs a complete OpenCV test without opening a window:
- It reads an optional output filename from the first command-line argument.
If none is provided, it uses
opencv-headless-check.png. - It prints
CV_VERSIONto confirm which OpenCV version is available at runtime. - It creates a 400 x 300, three-channel BGR image with a blue background.
- It draws a white rectangle and green text, testing basic OpenCV image and drawing operations.
- It writes the image to disk with
cv::imwrite(). A write failure produces an error message and exit status1. - It prints the image dimensions and mean BGR values. These terminal values provide a quick check over SSH even before the PNG is copied to the host.
No HighGUI functions are used, so the program does not require DISPLAY, X11,
Wayland, or an attached monitor.
Configure and build
Run these commands from the directory containing CMakeLists.txt:
Confirm that the result is an AArch64 executable before copying it:
Copy and run on the target
Copy the executable, run it through SSH, and request an output image in /tmp:
Successful output reports the OpenCV version, image size, mean BGR values, and the path of the generated file. Verify the image on the target:
To inspect it visually, copy it back to the host and open it locally:
If the executable reports a missing shared library, use ldd on the target to
identify which runtime dependency is unavailable: