Skip to content

Handle unicode filenames in FTP #114

Handle unicode filenames in FTP

Handle unicode filenames in FTP #114

Workflow file for this run

name: Kotlin Build and Test
on:
push:
branches:
- 'main'
tags:
- 'v*'
paths-ignore:
- 'cpp/docs/**'
pull_request:
branches:
- '*'
paths-ignore:
- 'cpp/docs/**'
- '.github/workflows/docs_deploy.yml'
workflow_dispatch:
# Unlike linux.yml and macos.yml, this workflow does NOT set
# `defaults.run.working-directory`, because it spans cpp/, c/, jni/ and kt/.
# Every path below is relative to the repository root.
jobs:
# Build the JNI library for each desktop platform. cmavsdk is linked
# statically, so libmavsdk_jni is self-contained and needs no companion
# libcmavsdk at runtime.
jni-desktop:
name: jni-${{ matrix.platform }}
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- platform: linux-x86_64
runner: ubuntu-24.04
library: libmavsdk_jni.so
- platform: darwin-aarch64
runner: macos-15
library: libmavsdk_jni.dylib
- platform: darwin-x86_64
runner: macos-15-intel
library: libmavsdk_jni.dylib
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
# Provides JAVA_HOME, which jni/CMakeLists.txt needs for find_package(JNI),
# and javac for the contract validation below.
- uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'
- uses: actions/cache@v4
id: cache
with:
path: ./cpp/build/kotlin/third_party/install
key: kotlin-${{ matrix.platform }}-${{ hashFiles('./third_party/**') }}-1
- name: disable superbuild on cache hit
if: steps.cache.outputs.cache-hit == 'true'
run: |
echo "superbuild=-DSUPERBUILD=OFF" >> $GITHUB_ENV
echo "cmake_prefix_path=-DCMAKE_PREFIX_PATH=$(pwd)/cpp/build/kotlin/third_party/install" >> $GITHUB_ENV
- name: build MAVSDK C++
run: |
cmake $superbuild $cmake_prefix_path \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=OFF \
-DBUILD_TESTING=OFF \
-DBUILD_MAVSDK_SERVER=OFF \
-DCMAKE_INSTALL_PREFIX=$(pwd)/cpp/build/kotlin/install \
-Scpp -Bcpp/build/kotlin
cmake --build cpp/build/kotlin -j$(getconf _NPROCESSORS_ONLN) --target install
# CMAKE_POSITION_INDEPENDENT_CODE is explicit here: c/CMakeLists.txt does
# not set it, and a non-PIC static archive cannot be linked into the
# shared libmavsdk_jni on Linux.
- name: build cmavsdk
run: |
cmake \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=OFF \
-DBUILD_EXAMPLES=OFF \
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
-DCMAKE_PREFIX_PATH="$(pwd)/cpp/build/kotlin/install;$(pwd)/cpp/build/kotlin/third_party/install" \
-DCMAKE_INSTALL_PREFIX=$(pwd)/c/build/kotlin/install \
-Sc -Bc/build/kotlin
cmake --build c/build/kotlin -j$(getconf _NPROCESSORS_ONLN) --target install
- name: build mavsdk_jni
run: |
cmake \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH="$(pwd)/c/build/kotlin/install;$(pwd)/cpp/build/kotlin/install;$(pwd)/cpp/build/kotlin/third_party/install" \
-Sjni -Bjni/build/kotlin
cmake --build jni/build/kotlin -j$(getconf _NPROCESSORS_ONLN)
# Compiles the generated Java contracts and cross-checks them against the
# symbols actually exported by the library we just built.
- name: validate JNI contracts
run: ./jni/jvm/validate.sh "$(pwd)/jni/build/kotlin/${{ matrix.library }}"
- name: upload native library
uses: actions/upload-artifact@v4
with:
name: jni-native-${{ matrix.platform }}
path: jni/build/kotlin/${{ matrix.library }}
retention-days: 7
if-no-files-found: error
# Cross-compile the JNI library for each Android ABI. jni/CMakeLists.txt
# branches on ANDROID, so it links liblog and skips find_package(JNI) -- the
# NDK inside the dockcross image supplies the headers.
jni-android:
name: jni-android-${{ matrix.abi }}
runs-on: ubuntu-24.04
env:
OCI_EXE: docker
strategy:
fail-fast: false
matrix:
include:
- name: android-arm
abi: armeabi-v7a
- name: android-arm64
abi: arm64-v8a
- name: android-x86
abi: x86
- name: android-x86_64
abi: x86_64
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- name: Free Disk Space
uses: jlumbroso/free-disk-space@v1.3.1
continue-on-error: true
# Generated from the repository root, so /work inside the container maps
# to the root and can reach cpp/, c/ and jni/ in one pass.
- name: setup dockcross
run: docker run --rm dockcross/${{ matrix.name }}:20250818-0a27819 > ./dockcross-${{ matrix.name }}; chmod +x ./dockcross-${{ matrix.name }}
- uses: actions/cache@v4
id: cache
with:
path: ./cpp/build/android/${{ matrix.name }}/third_party/install
key: kotlin-${{ matrix.name }}-${{ hashFiles('./third_party/**') }}-1
- name: disable superbuild on cache hit
if: steps.cache.outputs.cache-hit == 'true'
run: |
echo "superbuild=-DSUPERBUILD=OFF" >> $GITHUB_ENV
echo "cmake_prefix_path=-DCMAKE_PREFIX_PATH=/work/cpp/build/android/${{ matrix.name }}/third_party/install" >> $GITHUB_ENV
- name: configure MAVSDK C++
run: ./dockcross-${{ matrix.name }} /bin/bash -c "cmake $superbuild $cmake_prefix_path -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTING=OFF -DBUILD_MAVSDK_SERVER=OFF -DCMAKE_INSTALL_PREFIX=/work/cpp/build/android/${{ matrix.name }}/install -Scpp -Bcpp/build/android/${{ matrix.name }}"
- name: build MAVSDK C++
run: ./dockcross-${{ matrix.name }} cmake --build cpp/build/android/${{ matrix.name }} -j$(nproc) --target install
- name: configure cmavsdk
run: ./dockcross-${{ matrix.name }} /bin/bash -c "cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DBUILD_EXAMPLES=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_PREFIX_PATH='/work/cpp/build/android/${{ matrix.name }}/install;/work/cpp/build/android/${{ matrix.name }}/third_party/install' -DCMAKE_INSTALL_PREFIX=/work/c/build/android/${{ matrix.name }}/install -Sc -Bc/build/android/${{ matrix.name }}"
- name: build cmavsdk
run: ./dockcross-${{ matrix.name }} cmake --build c/build/android/${{ matrix.name }} -j$(nproc) --target install
- name: configure mavsdk_jni
run: ./dockcross-${{ matrix.name }} /bin/bash -c "cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH='/work/c/build/android/${{ matrix.name }}/install;/work/cpp/build/android/${{ matrix.name }}/install;/work/cpp/build/android/${{ matrix.name }}/third_party/install' -Sjni -Bjni/build/android/${{ matrix.name }}"
- name: build mavsdk_jni
run: ./dockcross-${{ matrix.name }} cmake --build jni/build/android/${{ matrix.name }} -j$(nproc)
- name: upload native library
uses: actions/upload-artifact@v4
with:
name: jni-android-${{ matrix.abi }}
path: jni/build/android/${{ matrix.name }}/libmavsdk_jni.so
retention-days: 7
if-no-files-found: error
# Fan in the desktop natives, build the JVM target, and smoke-test that the
# library actually loads through NativeLibraryLoader.
kotlin-jvm:
name: kotlin-jvm
needs: jni-desktop
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'
- uses: gradle/actions/setup-gradle@v4
- uses: actions/download-artifact@v4
with:
pattern: jni-native-*
path: native-staging
# download-artifact drops each artifact into <path>/<artifact-name>/, so
# strip the prefix to get the <os>-<arch> layout NativeLibraryLoader
# looks for.
- name: lay out natives
run: |
dest=kt/mavsdk-kotlin/src/jvmMain/resources/native
mkdir -p "$dest"
for dir in native-staging/jni-native-*; do
platform="$(basename "$dir")"
platform="${platform#jni-native-}"
mkdir -p "$dest/$platform"
cp "$dir"/* "$dest/$platform/"
done
find "$dest" -type f | sort
- name: build library and examples
run: |
cd kt/examples/cli-jvm
./gradlew build
- name: build jvm jar
run: |
cd kt/mavsdk-kotlin
./gradlew jvmJar
# Telemetry uses firstAutopilot(timeoutSeconds = 10.0), so it terminates
# on its own without a vehicle. This proves the native library loads and
# the JNI boundary works end to end.
- name: smoke-test native loading
run: |
cd kt/examples/cli-jvm
./gradlew run --args="Telemetry" --console=plain 2>&1 | tee run.log
grep -q "Loaded libmavsdk_jni from resources: /native/linux-x86_64/" run.log
- name: upload jvm jar
uses: actions/upload-artifact@v4
with:
name: mavsdk-kotlin-jvm-jar
path: kt/mavsdk-kotlin/build/libs/*.jar
retention-days: 14
if-no-files-found: error
# Fan in the four Android ABIs and assemble the AAR.
kotlin-android:
name: kotlin-android
needs: jni-android
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'
- uses: gradle/actions/setup-gradle@v4
- uses: actions/download-artifact@v4
with:
pattern: jni-android-*
path: android-staging
- name: lay out jniLibs
run: |
dest=kt/mavsdk-kotlin/src/androidMain/jniLibs
mkdir -p "$dest"
for dir in android-staging/jni-android-*; do
abi="$(basename "$dir")"
abi="${abi#jni-android-}"
mkdir -p "$dest/$abi"
cp "$dir"/* "$dest/$abi/"
done
find "$dest" -type f | sort
- name: assemble AAR
run: |
cd kt/mavsdk-kotlin
./gradlew assembleAndroidMain
- name: upload AAR
uses: actions/upload-artifact@v4
with:
name: mavsdk-kotlin-aar
path: kt/mavsdk-kotlin/build/outputs/aar/*.aar
retention-days: 14
if-no-files-found: error
# Publishes io.mavsdk:mavsdk-kotlin{,-jvm,-android} to Maven Central:
# a v* tag publishes the release version unattended, and every merge to main
# publishes the next patch as a snapshot so the in-between state is testable.
publish:
name: publish to Maven Central
needs: [kotlin-jvm, kotlin-android]
if: github.event_name == 'push' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'
- uses: gradle/actions/setup-gradle@v4
# The jvm jar embeds the desktop natives from its resources, and the AAR
# embeds the Android ones from jniLibs, so both sets have to be back in
# place before the publication is built.
- uses: actions/download-artifact@v4
with:
pattern: jni-native-*
path: native-staging
- uses: actions/download-artifact@v4
with:
pattern: jni-android-*
path: android-staging
- name: lay out natives
run: |
dest=kt/mavsdk-kotlin/src/jvmMain/resources/native
mkdir -p "$dest"
for dir in native-staging/jni-native-*; do
platform="$(basename "$dir")"
platform="${platform#jni-native-}"
mkdir -p "$dest/$platform"
cp "$dir"/* "$dest/$platform/"
done
dest=kt/mavsdk-kotlin/src/androidMain/jniLibs
mkdir -p "$dest"
for dir in android-staging/jni-android-*; do
abi="$(basename "$dir")"
abi="${abi#jni-android-}"
mkdir -p "$dest/$abi"
cp "$dir"/* "$dest/$abi/"
done
# Release tags live on the release branches rather than on main, so the
# last release is the highest v* tag, not the one `git describe` finds.
- name: derive version
run: |
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
echo "VERSION_NAME=${GITHUB_REF_NAME#v}" >> $GITHUB_ENV
else
latest="$(git tag --list 'v*' --sort=-v:refname | head -n 1)"
IFS=. read -r major minor patch <<< "${latest#v}"
echo "VERSION_NAME=${major}.${minor}.$((patch + 1))-SNAPSHOT" >> $GITHUB_ENV
fi
- name: publish
env:
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }}
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.SIGNING_IN_MEMORY_KEY }}
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SIGNING_IN_MEMORY_KEY_PASSWORD }}
run: |
echo "Publishing $VERSION_NAME"
cd kt/mavsdk-kotlin
./gradlew publishAndReleaseToMavenCentral -PVERSION_NAME="$VERSION_NAME"