Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions ci/arm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# ARM CI Directory

## Folder overview

This directory contains scripts and configuration for building Scopy for ARM platforms (both 32-bit armhf and 64-bit aarch64). The build process uses cross-compilation toolchains and creates AppImage packages for ARM devices like Raspberry Pi. More information about this build can be found here [Creating an Installer for other architectures](https://analogdevicesinc.github.io/scopy/user_guide/build_instructions/linuxBuild.html#creating-an-installer-for-other-architectures).

### Scripts

#### `arm_build_config.sh` - Configuration file that sets up build environment variables

#### `arm_build_process.sh` - Main build orchestration script

#### `create_sysroot.sh` - Creates a sysroot from ADI Kuiper Linux image, the sysroot is used during cross-compilation

#### `build_qt.sh` - Cross-compiles Qt 5.15.16 for ARM

#### `create_docker_image.sh` - Creates Docker images for ARM builds

#### `docker/Dockerfile` - Base image configuration for ARM build environment

#### `copy-deps.sh` - Copies runtime dependencies into AppImage directory

#### `inside_chroot_arm64.sh` / `inside_chroot_armhf.sh` - Scripts that run inside chroot environment

#### `local_build_scopy_for_kuiper.sh` - Local build script specifically for Kuiper Linux

### Supporting Files

#### `cmake_toolchain.cmake` - Contains the toolchain used for cross-compiling

#### `qt_patch_arm32/arm64.patch` - A patch to some Qt files to be able to cross-compile it for arm32/64

#### `runtime-armhf/aarch64` - This is the runtime used inside the AppImage

## Build Process

### Building Scopy using the Docker Image

`Prerequisites:`

- [Docker](https://docs.docker.com/desktop/setup/install/windows-install/)
- the rest of the dependencies are installed using the scripts

This is by far the easiest method of building an armhf or arm64 Scopy AppImage.

A temporary Docker volume is created to link the local environment with the Docker container. The compilation process takes place inside the container using
the pre-configured filesystem and all the changes inside the volume will reflect to the locally stored files.

The next steps will describe how to build Scopy and create a armhf(arm32) AppImage, the process is the same for arm64(aarch64), just change the argument.

1. **Install the packages needed for emulating the required architecture**

```bash
ci/arm/create_sysroot.sh arm32 install_packages install_qemu
```

2. **Pull the Docker image**

```bash
docker pull cristianbindea/scopy2-armhf-appimage:latest
```

3. **Run the image, while creating a docker volume**

```bash
docker run -it --mount type=bind,source=path/to/scopy/repository,target=/home/runner/scopy cristianbindea/scopy2-armhf-appimage:latest
```

4. **Using the Docker environment you can compile and package the application with one command:**

```bash
/home/runner/scopy/ci/arm/arm_build_process.sh arm32 run_workflow
```

`TIP:` Inspect the arm_build_process.sh file. You can call any function inside that file using **$ ./arm_build_process.sh architecture function**.
This way you can only build Scopy, you can create an AppDir folder or even run the whole workflow and create the AppImage.

Finally, after the development is done use this to clean the system

```bash
docker container ls -a # get the container id
docker container rm -v (container id)
docker image rm cristianbindea/scopy2-armhf-appimage:latest
```

### Building the Docker Image

To build the Docker image, just run the script and select the required architecture.

```bash
ci/arm/create_docker_image.sh arm32 run_workflow
# or
ci/arm/create_docker_image.sh arm64 run_workflow
```

### Building locally from sources

In order to build Scopy locally you will need a device with the armhf or arm64 architecture, for example a Raspberry Pi.

To build the app directly on the Raspberry Pi, just run:

```bash
ci\arm\local_build_scopy_for_kuiper.sh install_apt clone buid_deps build_scopy
```

This script is made for [Kuiper Linux](https://wiki.analog.com/resources/tools-software/linux-software/kuiper-linux), but you can adapt it for another distro by updating the packages installed via apt.

## CI Integration

- **GitHub Actions**: `.github/workflows/appimage-armhf.yml`
- **GitHub Actions**: `.github/workflows/appimage-arm64.yml`

## Notes

- Uses ADI Kuiper Linux as the base system
- Requires significant disk space (~15GB) for sysroot and build artifacts
- Build time can be several hours depending on hardware
96 changes: 57 additions & 39 deletions ci/arm/arm_build_config.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
#!/bin/bash

# ARM Cross-Compilation Configuration Script
# ==========================================
# Sets up all environment variables and paths needed for ARM cross-compilation
# Usage: source arm_build_config.sh [arm32|arm64]
# Note: This script must be sourced, not executed directly


# Validate and set architecture-specific variables
# arm32: 32-bit ARM (armhf)
# arm64: 64-bit ARM (aarch64)
if [ "$1" == "arm64" ];then
echo "Building for aarch64"
TOOLCHAIN_HOST="aarch64-linux-gnu"
Expand All @@ -17,6 +27,9 @@ else
exit
fi


# These branches/tags define which version of each dependency to build
# Update these when you need to use different versions of dependencies
LIBSERIALPORT_BRANCH=master
LIBIIO_VERSION=v0.26
LIBAD9361_BRANCH=main
Expand All @@ -36,77 +49,82 @@ ECM_BRANCH=kf5
KARCHIVE_BRANCH=kf5
GENALYZER_BRANCH=main

# This environment variable tells the C++ code to use relative paths for libraries
# When set to 1, the application looks for libraries in the AppImage bundle
# instead of system locations, making the package portable
export APPIMAGE=1

# SRC_SCRIPT: Directory containing this script (ci/arm)
# STAGING_AREA: Main working directory for builds
SRC_SCRIPT=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
[ $CI_SCRIPT == "ON" ] && STAGING_AREA=$HOME/scopy/ci/arm/staging || STAGING_AREA=$SRC_SCRIPT/staging
SYSROOT=$STAGING_AREA/sysroot

SYSROOT=$STAGING_AREA/sysroot # root filesystem extracted from Kuiper Linux image
SYSROOT_TAR=$STAGING_AREA/sysroot.tar.gz
TOOLCHAIN=$STAGING_AREA/cross-pi-gcc
TOOLCHAIN=$STAGING_AREA/cross-pi-gcc # Cross-compiler location
TOOLCHAIN_BIN=$TOOLCHAIN/bin
TOOLCHAIN_FILE=$SRC_SCRIPT/cmake_toolchain.cmake
QT_LOCATION=$SYSROOT/usr/lib/$TOOLCHAIN_HOST/qt5

if [ $TOOLCHAIN_HOST == "aarch64-linux-gnu" ]; then
QT_BUILD_DEVICE=linux-rasp-pi4-v3d-g++
elif [ $TOOLCHAIN_HOST == "arm-linux-gnueabihf" ]; then
QT_BUILD_DEVICE=linux-rasp-pi3-vc4-g++
fi
QT_LOCATION=$SYSROOT/usr/lib/$TOOLCHAIN_HOST/qt5
QT_BUILD_LOCATION=$QT_LOCATION # The location where Qt will be installed in the system
QT_SYSTEM_LOCATION=/usr/lib/$TOOLCHAIN_HOST/qt5 # The Qt location relative to the sysroot folder

CMAKE_BIN=$STAGING_AREA/cmake/bin/cmake
QMAKE_BIN=$QT_LOCATION/bin/qmake
JOBS=-j14

APP_DIR=$SRC_SCRIPT/scopy.AppDir
APP_IMAGE=$SRC_SCRIPT/Scopy.AppImage
APP_RUN=$SRC_SCRIPT/../general/AppRun
APP_DESKTOP=$SRC_SCRIPT/../general/scopy.desktop
JOBS=-j14 # Parallel build configuration

CMAKE_OPTS=(\
-DCMAKE_INSTALL_PREFIX="$SYSROOT" \
-DCMAKE_TOOLCHAIN_FILE="$TOOLCHAIN_FILE" \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
)

CMAKE="$CMAKE_BIN ${CMAKE_OPTS[*]}" # Complete CMake command with all options

CROSS_COMPILER=$TOOLCHAIN

APP_DIR=$SRC_SCRIPT/scopy.AppDir # Temporary directory structure that becomes the AppImage
APP_IMAGE=$SRC_SCRIPT/Scopy.AppImage # Final AppImage executable file
APP_RUN=$SRC_SCRIPT/../general/AppRun # Entry point script that launches the application
APP_DESKTOP=$SRC_SCRIPT/../general/scopy.desktop # Desktop entry file for Linux desktop integration
APP_SQUASHFS=$SRC_SCRIPT/scopy.squashfs

# Runetimes downloaded from https://github.com/AppImage/type2-runtime/releases/tag/20251108 8 Dec 2025
# AppImage runtime for ARM
# Downloaded from https://github.com/AppImage/AppImageKit/releases/continuous
# The runtime is a small executable that mounts and runs the AppImage
RUNTIME_ARM=$SRC_SCRIPT/runtime-$ARCHITECTURE


# The exports below ensure these variables are available to the toolchain file.
# These exports make variables available to cmake_toolchain.cmake
# The toolchain file needs these to properly configure cross-compilation
export CMAKE_SYSROOT="$SYSROOT"
export QT_LOCATION="$QT_LOCATION"
export STAGING_AREA="$STAGING_AREA"
export CMAKE_SYSTEM_PROCESSOR="$CMAKE_SYSTEM_PROCESSOR"
export CMAKE_LIBRARY_ARCHITECTURE="$CMAKE_LIBRARY_ARCHITECTURE"

CMAKE_OPTS=(\
-DCMAKE_INSTALL_PREFIX="$SYSROOT" \
-DCMAKE_TOOLCHAIN_FILE="$TOOLCHAIN_FILE" \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
)

CMAKE="$CMAKE_BIN ${CMAKE_OPTS[*]}"

QT_BUILD_LOCATION=$QT_LOCATION # the location where Qt will be installed in the system
QT_SYSTEM_LOCATION=/usr/lib/$TOOLCHAIN_HOST/qt5 # the Qt location relative to the sysroot folder
CROSS_COMPILER=$TOOLCHAIN
# CMake 3.29
CMAKE_DOWNLOAD_LINK=https://github.com/Kitware/CMake/releases/download/v3.29.0-rc2/cmake-3.29.0-rc2-linux-x86_64.tar.gz
# Qt 5.15.16 LTS source code
QT_DOWNLOAD_LINK=https://download.qt.io/archive/qt/5.15/5.15.16/single/qt-everywhere-opensource-src-5.15.16.tar.xz
# Script to fix absolute symlinks in sysroot
SYSROOT_RELATIVE_LINKS=https://raw.githubusercontent.com/abhiTronix/rpi_rootfs/master/scripts/sysroot-relativelinks.py

# Sets download URLs and Qt device specs based on target architecture
if [ $TOOLCHAIN_HOST == "aarch64-linux-gnu" ]; then
QT_BUILD_DEVICE=linux-rasp-pi4-v3d-g++
CROSSCOMPILER_DOWNLOAD_LINK=https://sourceforge.net/projects/raspberry-pi-cross-compilers/files/Bonus%20Raspberry%20Pi%20GCC%2064-Bit%20Toolchains/Raspberry%20Pi%20GCC%2064-Bit%20Cross-Compiler%20Toolchains/Bookworm/GCC%2012.2.0/cross-gcc-12.2.0-pi_64.tar.gz
KUIPER_DOWNLOAD_LINK=https://github.com/analogdevicesinc/adi-kuiper-gen/releases/download/v2.0.0/image_2025-04-03-ADI-Kuiper-Linux-arm64.zip
IMAGE_NAME="2025-04-03-ADI-Kuiper-Linux-arm64"

elif [ $TOOLCHAIN_HOST == "arm-linux-gnueabihf" ]; then
QT_BUILD_DEVICE=linux-rasp-pi3-vc4-g++
# bookwork
#CROSSCOMPILER_DOWNLOAD_LINK=https://sourceforge.net/projects/raspberry-pi-cross-compilers/files/Raspberry%20Pi%20GCC%20Cross-Compiler%20Toolchains/Bookworm/GCC%2012.2.0/Raspberry%20Pi%202%2C%203/cross-gcc-12.2.0-pi_2-3.tar.gz
# bullseye, with armv8 flags
#CROSSCOMPILER_DOWNLOAD_LINK=https://sourceforge.net/projects/raspberry-pi-cross-compilers/files/Raspberry%20Pi%20GCC%20Cross-Compiler%20Toolchains/Bullseye/GCC%2010.2.0/Raspberry%20Pi%203A%2B%2C%203B%2B%2C%204%2C%205/cross-gcc-10.2.0-pi_3%2B.tar.gz
# compiler with armv7 flags
CROSSCOMPILER_DOWNLOAD_LINK=https://sourceforge.net/projects/raspberry-pi-cross-compilers/files/Raspberry%20Pi%20GCC%20Cross-Compiler%20Toolchains/Bullseye/GCC%2010.2.0/Raspberry%20Pi%202%2C%203/cross-gcc-10.2.0-pi_2-3.tar.gz
fi

CMAKE_DOWNLOAD_LINK=https://github.com/Kitware/CMake/releases/download/v3.29.0-rc2/cmake-3.29.0-rc2-linux-x86_64.tar.gz

if [ $TOOLCHAIN_HOST == "aarch64-linux-gnu" ]; then
KUIPER_DOWNLOAD_LINK=https://github.com/analogdevicesinc/adi-kuiper-gen/releases/download/v2.0.0/image_2025-04-03-ADI-Kuiper-Linux-arm64.zip
IMAGE_NAME="2025-04-03-ADI-Kuiper-Linux-arm64"
elif [ $TOOLCHAIN_HOST == "arm-linux-gnueabihf" ]; then
KUIPER_DOWNLOAD_LINK=https://swdownloads.analog.com/cse/kuiper/image_2023-12-13-ADI-Kuiper-full.zip
IMAGE_NAME="2023-12-13-ADI-Kuiper-full"
fi

QT_DOWNLOAD_LINK=https://download.qt.io/archive/qt/5.15/5.15.16/single/qt-everywhere-opensource-src-5.15.16.tar.xz

SYSROOT_RELATIVE_LINKS=https://raw.githubusercontent.com/abhiTronix/rpi_rootfs/master/scripts/sysroot-relativelinks.py
Loading
Loading