Cross-compiling
Getting the SDK into a camera image. One CMake toolchain file and one dependency — the rest is your BSP's normal process.
What actually has to be satisfied#
| Requirement | Why |
|---|---|
| C++17 compiler | The core is C++17. GCC 7 is enough. |
OpenSSL ≥ 1.1.1 libcrypto | Ed25519 verification. Present in every BSP. |
libssl | Only if XCAICX_WITH_TLS=ON, i.e. only if the camera phones home. |
| A writable persistent path | For state_dir. |
There is no requirement for a particular libc, a particular init system, threads beyond std::thread, or an accelerator. The reference backend runs anywhere the compiler does.
Build options#
| Option | Default | Notes |
|---|---|---|
XCAICX_WITH_ORT | OFF | ONNX Runtime backend. ON for production. |
XCAICX_WITH_TLS | ON | HTTPS for activation/heartbeat. OFF drops libssl. |
XCAICX_BUILD_SHARED | ON | OFF produces a static library. |
CMAKE_BUILD_TYPE | — | Always set Release for shipping images. |
A toolchain file#
# /opt/toolchains/aarch64.cmake
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(TOOLCHAIN /opt/gcc-aarch64-none-linux-gnu)
set(CMAKE_C_COMPILER ${TOOLCHAIN}/bin/aarch64-none-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN}/bin/aarch64-none-linux-gnu-g++)
set(CMAKE_SYSROOT ${TOOLCHAIN}/aarch64-none-linux-gnu/libc)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)cmake -S core -B build-arm64 \
-DCMAKE_TOOLCHAIN_FILE=/opt/toolchains/aarch64.cmake \
-DCMAKE_BUILD_TYPE=Release \
-DXCAICX_WITH_ORT=ON
cmake --build build-arm64 -jCareful
CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY is the line that stops CMake finding your host OpenSSL and linking an x86 library into an ARM image. The failure shows up as an inscrutable linker error late in the build, or worse, as a binary that builds and then will not load on the board.
Yocto#
A minimal recipe:
SUMMARY = "XCAICX camera SDK"
LICENSE = "CLOSED"
DEPENDS = "openssl"
SRC_URI = "file://xcaicx-sdk-${PV}.tar.gz"
S = "${WORKDIR}/xcaicx-sdk-${PV}"
inherit cmake
EXTRA_OECMAKE = " \
-DXCAICX_WITH_ORT=ON \
-DXCAICX_WITH_TLS=ON \
-DCMAKE_BUILD_TYPE=Release \
"
OECMAKE_SOURCEPATH = "${S}/core"
FILES:${PN} += "${libdir}/libxcaicx.so*"
FILES:${PN}-dev += "${includedir}/xcaicx"Add a persistent directory for state_dir in your image recipe — not under /tmp, and not on a volatile mount:
do_install:append() {
install -d -m 0700 ${D}/var/lib/xcaicx
}Do not
On a read-only rootfs image, confirm /var/lib is a real writable overlay and not a tmpfs. A tmpfs state_dir re-activates on every boot and consumes a batch unit each time.
Buildroot#
XCAICX_VERSION = 1.0.0
XCAICX_SITE = $(TOPDIR)/../vendor/xcaicx-sdk
XCAICX_SITE_METHOD = local
XCAICX_SUBDIR = core
XCAICX_DEPENDENCIES = openssl
XCAICX_INSTALL_STAGING = YES
XCAICX_CONF_OPTS = -DXCAICX_WITH_ORT=ON -DCMAKE_BUILD_TYPE=Release
$(eval $(cmake-package))Android (NDK)#
cmake -S core -B build-android \
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=arm64-v8a \
-DANDROID_PLATFORM=android-26 \
-DCMAKE_BUILD_TYPE=Release \
-DOPENSSL_ROOT_DIR=/path/to/prebuilt/openssl/arm64-v8a
cmake --build build-android -jAndroid has no system OpenSSL you may link against, so ship a prebuilt libcrypto.
state_dir should be your app's private storage — context.getFilesDir() — which survives reboot and is not world-readable.
Windows (NVR software)#
cmake -S core -B build-win -A x64 `
-DCMAKE_BUILD_TYPE=Release `
-DOPENSSL_ROOT_DIR="C:\dev\openssl-3"
cmake --build build-win --config ReleaseConsumers of the DLL must define XCAICX_USING_SHARED before including the header so the import attributes are right:
#define XCAICX_USING_SHARED
#include "xcaicx/xcaicx.h"Use %ProgramData%\xcaicx for state_dir, with an ACL that allows the service account to write.
Static linking into one firmware image#
cmake -S core -B build-static \
-DXCAICX_BUILD_SHARED=OFF \
-DXCAICX_WITH_TLS=OFF \
-DCMAKE_BUILD_TYPE=ReleaseTurning TLS off removes the libssl dependency entirely, which is the right call for a camera that will never phone home. Activation must then be offline pre-provisioning.
Verifying the build on the board#
# 1. The library loads and reports its version
xcaicx_version_smoke # or: python3 -c "import xcaicx; print(xcaicx.version())"
# 2. The fingerprint is what you expect, and is stable
XCAICX_DEVICE_ID= ./your_app --print-fingerprint
reboot
XCAICX_DEVICE_ID= ./your_app --print-fingerprint # must match
# 3. state_dir survives a power cut, not just a rebootStep 3 is the one people skip, and it is the one that costs units.
Size and footprint#
The core with the reference backend only, stripped, is a small shared object; ONNX Runtime and the model bundle dominate any production image. Budget for the model bundle first and the SDK second.
Runtime memory is dominated by the analysis image (320px on the long side) and your queue depth (max_queue_depth, default 4 per stream). A frame in the queue costs a full converted RGB+luma copy, so on a memory-tight board set max_queue_depth = 1 or 2 and use the synchronous xcaicx_stream_process.
Next#
- OEM integration — fingerprints, provisioning, the checklist
- Backends & models — what
XCAICX_WITH_ORT=ONgets you - Performance & tuning — making it fit the SoC budget