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
104 changes: 83 additions & 21 deletions .github/workflows/build-natives.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,43 +130,65 @@ jobs:
build-natives-windows:
if: github.event.inputs.platforms != 'linux'
runs-on: windows-2022
timeout-minutes: 30
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
include:
- platform: x86_64
msvc_arch: x64
windows_arm64: "0"
- platform: arm64
msvc_arch: amd64_arm64
windows_arm64: "1"
steps:
- uses: actions/checkout@v5
- uses: ilammy/msvc-dev-cmd@v1
with:
vsversion: 2022
arch: ${{ matrix.msvc_arch }}
- uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '17'
- name: Compile native library
- name: Compile native library (${{ matrix.platform }})
shell: bash
env:
WINDOWS_COMPILE_ARM64: ${{ matrix.windows_arm64 }}
run: |
bash.exe cppbuild.bash
if [ "${{ matrix.windows_arm64 }}" = "1" ]; then
bash build-windows-arm64.bash
else
bash cppbuild.bash
fi
- name: Stage and verify Windows native libraries
shell: bash
run: |
set -euo pipefail
DEST="src/main/resources/fastddsjava/native/windows-x86_64"
DEST="src/main/resources/fastddsjava/native/windows-${{ matrix.platform }}"
ls -la "$DEST" || true
test -f "$DEST/fastcdr-2.3.dll" || { echo "Missing fastcdr DLL"; ls -la "$DEST" install/bin 2>/dev/null || true; exit 1; }
test -f "$DEST/fastdds-3.6.dll" || { echo "Missing fastdds-3.6.dll"; ls -la "$DEST" cppbuild/install/bin 2>/dev/null || true; exit 1; }
test -f "$DEST/jnifastddsjava.dll" || { echo "Missing jnifastddsjava.dll"; exit 1; }
# Reject stale JNI binaries still linked against older Fast-DDS SONAMEs.
if command -v objdump >/dev/null 2>&1; then
deps=$(objdump -p "$DEST/jnifastddsjava.dll" | grep -i 'DLL Name' || true)
echo "$deps"
echo "$deps" | grep -qi 'fastdds-3\.6\.dll' || { echo "jnifastddsjava.dll does not import fastdds-3.6.dll"; exit 1; }
echo "$deps" | grep -qi 'fastdds-3\.2\.dll' && { echo "jnifastddsjava.dll still imports fastdds-3.2.dll"; exit 1; } || true
# Prefer dumpbin: MinGW objdump on the runner cannot parse ARM64 PE.
deps=""
if command -v dumpbin.exe >/dev/null 2>&1 || command -v dumpbin >/dev/null 2>&1; then
deps=$(MSYS_NO_PATHCONV=1 dumpbin.exe /DEPENDENTS "$DEST/jnifastddsjava.dll" 2>/dev/null || true)
elif command -v objdump >/dev/null 2>&1; then
deps=$(objdump -p "$DEST/jnifastddsjava.dll" 2>/dev/null | grep -i 'DLL Name' || true)
fi
mkdir -p artifact/windows-x86_64
cp -a "$DEST/." artifact/windows-x86_64/
ls -la artifact/windows-x86_64
echo "$deps"
echo "$deps" | grep -qi 'fastdds-3\.6\.dll' || { echo "jnifastddsjava.dll does not import fastdds-3.6.dll"; exit 1; }
echo "$deps" | grep -qi 'fastdds-3\.2\.dll' && { echo "jnifastddsjava.dll still imports fastdds-3.2.dll"; exit 1; } || true
mkdir -p "artifact/windows-${{ matrix.platform }}"
cp -a "$DEST/." "artifact/windows-${{ matrix.platform }}/"
ls -la "artifact/windows-${{ matrix.platform }}"
- name: Upload artifacts
uses: actions/upload-artifact@v7
with:
name: natives-windows
path: artifact/windows-x86_64/
name: natives-windows-${{ matrix.platform }}
path: artifact/windows-${{ matrix.platform }}/
retention-days: 1

build-natives-android:
Expand All @@ -176,7 +198,7 @@ jobs:
strategy:
fail-fast: false
matrix:
platform: [arm64-v8a, x86_64]
platform: [arm64-v8a, armeabi-v7a, x86_64]
steps:
- name: Checkout repository
uses: actions/checkout@v5
Expand Down Expand Up @@ -204,6 +226,11 @@ jobs:
run: |
PATH=/opt/cmake-4.0.2/bin:$PATH bash build-android-arm64.bash

- name: Compile native library (armeabi-v7a)
if: matrix.platform == 'armeabi-v7a'
run: |
PATH=/opt/cmake-4.0.2/bin:$PATH bash build-android-armeabi-v7a.bash

- name: Compile native library (x86_64)
if: matrix.platform == 'x86_64'
run: |
Expand All @@ -213,7 +240,7 @@ jobs:
run: |
set -euo pipefail
DEST="android/src/main/jniLibs/${{ matrix.platform }}"
for f in libfastcdr.so libfastdds.so libjnifastddsjava.so; do
for f in libfastcdr.so libfastdds.so libjnifastddsjava.so libc++_shared.so; do
test -f "$DEST/$f" || { echo "Missing $DEST/$f"; ls -la "$DEST" || true; exit 1; }
done
mkdir -p "artifact/${{ matrix.platform }}"
Expand Down Expand Up @@ -449,9 +476,11 @@ jobs:
copy_artifact_dir "$(resolve_artifact_src artifacts/natives-linux-armhf linux-armhf)" src/main/resources/fastddsjava/native/linux-armhf
copy_artifact_dir "$(resolve_artifact_src artifacts/natives-linux-x86_64 linux-x86_64)" src/main/resources/fastddsjava/native/linux-x86_64

copy_artifact_dir "$(resolve_artifact_src artifacts/natives-windows windows-x86_64)" src/main/resources/fastddsjava/native/windows-x86_64
copy_artifact_dir "$(resolve_artifact_src artifacts/natives-windows-x86_64 windows-x86_64)" src/main/resources/fastddsjava/native/windows-x86_64
copy_artifact_dir "$(resolve_artifact_src artifacts/natives-windows-arm64 windows-arm64)" src/main/resources/fastddsjava/native/windows-arm64

copy_artifact_dir "$(resolve_artifact_src artifacts/natives-android-arm64-v8a arm64-v8a)" android/src/main/jniLibs/arm64-v8a
copy_artifact_dir "$(resolve_artifact_src artifacts/natives-android-armeabi-v7a armeabi-v7a)" android/src/main/jniLibs/armeabi-v7a
copy_artifact_dir "$(resolve_artifact_src artifacts/natives-android-x86_64 x86_64)" android/src/main/jniLibs/x86_64

copy_artifact_dir "$(resolve_artifact_src artifacts/natives-macos-arm64 macos-arm64)" src/main/resources/fastddsjava/native/macos-arm64
Expand Down Expand Up @@ -522,10 +551,10 @@ jobs:
done

# Windows x86_64
check_file "$BASE/windows-x86_64/fastcdr-2.3.dll" "x86-64|PE32" "windows-x86_64"
check_file "$BASE/windows-x86_64/fastdds-3.6.dll" "x86-64|PE32" "windows-x86_64"
check_file "$BASE/windows-x86_64/jnifastddsjava.dll" "x86-64|PE32" "windows-x86_64"
win_jni_deps=$(objdump -p "$BASE/windows-x86_64/jnifastddsjava.dll" | grep -i 'DLL Name' || true)
check_file "$BASE/windows-x86_64/fastcdr-2.3.dll" "x86-64" "windows-x86_64"
check_file "$BASE/windows-x86_64/fastdds-3.6.dll" "x86-64" "windows-x86_64"
check_file "$BASE/windows-x86_64/jnifastddsjava.dll" "x86-64" "windows-x86_64"
win_jni_deps=$(objdump -p "$BASE/windows-x86_64/jnifastddsjava.dll" 2>/dev/null | grep -i 'DLL Name' || true)
echo "$win_jni_deps"
if ! echo "$win_jni_deps" | grep -qi 'fastdds-3\.6\.dll'; then
echo "WRONG DEPS [windows-x86_64]: jnifastddsjava.dll must import fastdds-3.6.dll"
Expand All @@ -536,6 +565,31 @@ jobs:
FAIL=1
fi

# Windows ARM64
check_file "$BASE/windows-arm64/fastcdr-2.3.dll" "Aarch64|ARM64|aarch64" "windows-arm64"
check_file "$BASE/windows-arm64/fastdds-3.6.dll" "Aarch64|ARM64|aarch64" "windows-arm64"
check_file "$BASE/windows-arm64/jnifastddsjava.dll" "Aarch64|ARM64|aarch64" "windows-arm64"
# Linux binutils may not parse ARM64 PE; try llvm-objdump, then objdump, then strings fallback.
win_arm_jni_deps=""
if command -v llvm-objdump >/dev/null 2>&1; then
win_arm_jni_deps=$(llvm-objdump -p "$BASE/windows-arm64/jnifastddsjava.dll" 2>/dev/null | grep -iE 'DLL Name|fastdds' || true)
fi
if [ -z "$win_arm_jni_deps" ]; then
win_arm_jni_deps=$(objdump -p "$BASE/windows-arm64/jnifastddsjava.dll" 2>/dev/null | grep -i 'DLL Name' || true)
fi
if [ -z "$win_arm_jni_deps" ]; then
win_arm_jni_deps=$(strings "$BASE/windows-arm64/jnifastddsjava.dll" | grep -iE 'fastdds-.*\.dll' || true)
fi
echo "$win_arm_jni_deps"
if ! echo "$win_arm_jni_deps" | grep -qi 'fastdds-3\.6\.dll'; then
echo "WRONG DEPS [windows-arm64]: jnifastddsjava.dll must import fastdds-3.6.dll"
FAIL=1
fi
if echo "$win_arm_jni_deps" | grep -qi 'fastdds-3\.2\.dll'; then
echo "WRONG DEPS [windows-arm64]: jnifastddsjava.dll still imports fastdds-3.2.dll"
FAIL=1
fi

# macOS arm64
check_file "$BASE/macos-arm64/libfastcdr.2.3.5.dylib" "arm64" "macos-arm64"
check_file "$BASE/macos-arm64/libfastdds.3.6.2.dylib" "arm64" "macos-arm64"
Expand All @@ -550,11 +604,19 @@ jobs:
check_file "$ANDROID_BASE/arm64-v8a/libfastcdr.so" "aarch64" "android-arm64-v8a"
check_file "$ANDROID_BASE/arm64-v8a/libfastdds.so" "aarch64" "android-arm64-v8a"
check_file "$ANDROID_BASE/arm64-v8a/libjnifastddsjava.so" "aarch64" "android-arm64-v8a"
check_file "$ANDROID_BASE/arm64-v8a/libc++_shared.so" "aarch64" "android-arm64-v8a"

# Android armeabi-v7a
check_file "$ANDROID_BASE/armeabi-v7a/libfastcdr.so" "EABI5|ARM" "android-armeabi-v7a"
check_file "$ANDROID_BASE/armeabi-v7a/libfastdds.so" "EABI5|ARM" "android-armeabi-v7a"
check_file "$ANDROID_BASE/armeabi-v7a/libjnifastddsjava.so" "EABI5|ARM" "android-armeabi-v7a"
check_file "$ANDROID_BASE/armeabi-v7a/libc++_shared.so" "EABI5|ARM" "android-armeabi-v7a"

# Android x86_64
check_file "$ANDROID_BASE/x86_64/libfastcdr.so" "x86-64" "android-x86_64"
check_file "$ANDROID_BASE/x86_64/libfastdds.so" "x86-64" "android-x86_64"
check_file "$ANDROID_BASE/x86_64/libjnifastddsjava.so" "x86-64" "android-x86_64"
check_file "$ANDROID_BASE/x86_64/libc++_shared.so" "x86-64" "android-x86_64"

if [ $FAIL -ne 0 ]; then
echo ""
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/gradle-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ jobs:
- name: Verify committed Android JNI libraries
run: |
set -euo pipefail
for abi in arm64-v8a x86_64; do
for abi in arm64-v8a armeabi-v7a x86_64; do
for lib in libfastcdr.so libfastdds.so libjnifastddsjava.so libc++_shared.so; do
test -f "android/src/main/jniLibs/$abi/$lib" || {
echo "Missing android/src/main/jniLibs/$abi/$lib"
Expand All @@ -125,7 +125,7 @@ jobs:
echo "Built AAR: $AAR"
unzip -l "$AAR"

for abi in arm64-v8a x86_64; do
for abi in arm64-v8a armeabi-v7a x86_64; do
for lib in libfastcdr.so libfastdds.so libjnifastddsjava.so libc++_shared.so; do
unzip -l "$AAR" | grep -q "jni/$abi/$lib" || {
echo "AAR missing jni/$abi/$lib"
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ ROS 2 compatible and tested distros: `[foxy, humble, jazzy, kilted, lyrical]`

Supported platforms:
- Linux (Ubuntu 20.04+ or similar x86_64, arm64, armhf)
- Windows (Windows 10+ x86_64)
- Windows (Windows 10+ x86_64, ARM64)
- macOS (macOS 13+ Intel, Apple Silicon)
- Android (Android 12+ x86_64, arm64-v8a)
- Android (Android 12+ x86_64, arm64-v8a, armeabi-v7a)

Works on NVIDIA Jetson and all versions of Raspberry Pi!

Expand Down
6 changes: 5 additions & 1 deletion android/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,11 @@ tasks.register("copyLibcppShared") {
if (ndkDir != null && ndkDir.exists()) {
println("Found NDK: $ndkDir")
// Copy libc++_shared.so for each ABI
listOf("arm64-v8a" to "aarch64-linux-android", "x86_64" to "x86_64-linux-android").forEach { (abi, triple) ->
listOf(
"arm64-v8a" to "aarch64-linux-android",
"armeabi-v7a" to "arm-linux-androideabi",
"x86_64" to "x86_64-linux-android"
).forEach { (abi, triple) ->
val libcppPath = file("$ndkDir/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/$triple/libc++_shared.so")
if (libcppPath.exists()) {
val abiDir = file("$jniLibsDir/$abi")
Expand Down
Binary file modified android/src/main/jniLibs/arm64-v8a/libc++_shared.so
Binary file not shown.
Binary file modified android/src/main/jniLibs/arm64-v8a/libjnifastddsjava.so
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified android/src/main/jniLibs/x86_64/libc++_shared.so
Binary file not shown.
Binary file modified android/src/main/jniLibs/x86_64/libjnifastddsjava.so
Binary file not shown.
37 changes: 37 additions & 0 deletions build-android-armeabi-v7a.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/bin/bash
# Build script for Android armeabi-v7a architecture
# This script sets all required environment variables and builds native libraries

set -e

# Find Android NDK (try common locations)
if [ -z "$ANDROID_NDK" ]; then
if [ -d "$HOME/Android/Sdk/ndk" ]; then
export ANDROID_NDK=$(ls -d $HOME/Android/Sdk/ndk/* 2>/dev/null | head -1)
fi

if [ -z "$ANDROID_NDK" ]; then
echo "Error: ANDROID_NDK not found. Please set ANDROID_NDK environment variable."
echo "Example: export ANDROID_NDK=/path/to/android-sdk/ndk/30.0.14904198"
exit 1
fi
fi

echo "Using Android NDK: $ANDROID_NDK"

# Set Android build configuration
export ANDROID_COMPILE=1
export ANDROID_ABI=armeabi-v7a
export ANDROID_API_LEVEL=26

# Clean previous build
echo "Cleaning previous build..."
rm -rf cppbuild

# Run build
echo "Building for Android armeabi-v7a..."
bash cppbuild.bash

echo ""
echo "Build complete! Libraries installed to:"
echo " android/src/main/jniLibs/armeabi-v7a/"
15 changes: 15 additions & 0 deletions build-windows-arm64.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash
# Build script for Windows ARM64
# Run from a bash shell with the MSVC ARM64 toolchain active
# (e.g. GitHub Actions: ilammy/msvc-dev-cmd with arch=amd64_arm64, or a native ARM64 VS prompt).

set -e

export WINDOWS_COMPILE_ARM64=1

echo "Building for Windows ARM64..."
bash cppbuild.bash

echo ""
echo "Build complete! Libraries installed to:"
echo " src/main/resources/fastddsjava/native/windows-arm64/"
33 changes: 32 additions & 1 deletion cppbuild.bash
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,16 @@ elif [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" || "$OS" == "Windows_NT" ]]
# Fast-DDS is built with MSVC; JNI must use the same toolchain/ABI.
WINDOWS_COMPILE=1
JNI_TARGET_NAME="jnifastddsjava.dll"
# Cross-compile ARM64 from an x64 host via msvc-dev-cmd arch=amd64_arm64 (or native ARM64 host).
if [ "$WINDOWS_COMPILE_ARM64" == "1" ]; then
COMPILER_ARGS="-A ARM64"
fi
elif [[ "$OSTYPE" == "darwin"* ]]; then
JNI_TARGET_NAME="libjnifastddsjava.dylib"
fi

WINDOWS_COMPILE=${WINDOWS_COMPILE:-0}
WINDOWS_COMPILE_ARM64=${WINDOWS_COMPILE_ARM64:-0}

# Build foonathan_memory_vendor
pushd .
Expand Down Expand Up @@ -177,6 +182,9 @@ to_win_path() {
}

if [ "$ANDROID_COMPILE" == "1" ]; then
# Prefer NDK JNI headers. Host OpenJDK jni.h uses AttachCurrentThread(void**),
# while Android's uses AttachCurrentThread(JNIEnv**) — required by our __ANDROID__ paths.
JNI_INCLUDE=""
ANDROID_TOOLCHAIN_BIN="$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin"
if [ "$ANDROID_ABI" == "arm64-v8a" ]; then
ANDROID_COMPILER_PREFIX="aarch64-linux-android"
Expand All @@ -194,6 +202,10 @@ if [ "$ANDROID_COMPILE" == "1" ]; then
-o javainstall/libjnifastddsjava.so -L${INSTALL_DIR}/install/lib \
-Wl,-rpath,${INSTALL_DIR}/install/lib \
-lfastdds -lfastcdr -llog -lc++_shared
if [ ! -f "javainstall/libjnifastddsjava.so" ]; then
echo "Error: Android JNI build did not produce javainstall/libjnifastddsjava.so"
exit 1
fi
elif [ "$WINDOWS_COMPILE" == "1" ]; then
# Match Fast-DDS MSVC build: MinGW cannot consume MSVC import libs as -lfastdds.
if ! command -v cl.exe >/dev/null 2>&1; then
Expand Down Expand Up @@ -269,7 +281,11 @@ if [ -f "javainstall/libjnifastddsjava.so" ]; then
fi
# Windows: Fast-DDS installs versioned DLLs (e.g. fastdds-3.6.dll, fastcdr-2.3.dll).
if [ "$WINDOWS_COMPILE" == "1" ]; then
WINDOWS_GEN_PATH="../src/main/resources/fastddsjava/native/windows-x86_64"
if [ "$WINDOWS_COMPILE_ARM64" == "1" ]; then
WINDOWS_GEN_PATH="../src/main/resources/fastddsjava/native/windows-arm64"
else
WINDOWS_GEN_PATH="../src/main/resources/fastddsjava/native/windows-x86_64"
fi
mkdir -p "$WINDOWS_GEN_PATH"
# Drop stale DLLs so we never ship an old JNI binary linked against a previous Fast-DDS SONAME.
rm -f "$WINDOWS_GEN_PATH"/*.dll
Expand Down Expand Up @@ -313,8 +329,16 @@ if [ "$ANDROID_COMPILE" == "1" ]; then
# Map ANDROID_ABI to Android jniLibs directory naming
if [ "$ANDROID_ABI" == "arm64-v8a" ]; then
ANDROID_GEN_PATH="../android/src/main/jniLibs/arm64-v8a"
ANDROID_NDK_TRIPLE="aarch64-linux-android"
elif [ "$ANDROID_ABI" == "armeabi-v7a" ]; then
ANDROID_GEN_PATH="../android/src/main/jniLibs/armeabi-v7a"
ANDROID_NDK_TRIPLE="arm-linux-androideabi"
elif [ "$ANDROID_ABI" == "x86_64" ]; then
ANDROID_GEN_PATH="../android/src/main/jniLibs/x86_64"
ANDROID_NDK_TRIPLE="x86_64-linux-android"
elif [ "$ANDROID_ABI" == "x86" ]; then
ANDROID_GEN_PATH="../android/src/main/jniLibs/x86"
ANDROID_NDK_TRIPLE="i686-linux-android"
else
echo "Unsupported ANDROID_ABI: $ANDROID_ABI"
exit 1
Expand All @@ -333,6 +357,13 @@ if [ "$ANDROID_COMPILE" == "1" ]; then
cp -f javainstall/libjnifastddsjava.so "$ANDROID_GEN_PATH/libjnifastddsjava.so"
${ANDROID_NDK}/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip "$ANDROID_GEN_PATH/libjnifastddsjava.so"
fi
# Bundle the C++ shared runtime required by Fast-DDS / JNI on Android.
ANDROID_LIBCPP_SHARED="${ANDROID_NDK}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/${ANDROID_NDK_TRIPLE}/libc++_shared.so"
if [ -f "$ANDROID_LIBCPP_SHARED" ]; then
cp -f "$ANDROID_LIBCPP_SHARED" "$ANDROID_GEN_PATH/libc++_shared.so"
else
echo "Warning: libc++_shared.so not found at $ANDROID_LIBCPP_SHARED"
fi
# Ensure the Android linker records the C++ runtime dependency (needed when symbols are unresolved).
if command -v patchelf >/dev/null 2>&1; then
for lib in libfastdds.so libjnifastddsjava.so; do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,20 @@ else if (arch.equals("amd64") || arch.equals("x86_64"))
}
else if (os.contains("win"))
{
if (!(arch.equals("amd64") || arch.equals("x86_64")))
String archPackage;
if (arch.equals("amd64") || arch.equals("x86_64"))
{
archPackage = "windows-x86_64";
}
else if (arch.equals("aarch64") || arch.equals("arm64"))
{
archPackage = "windows-arm64";
}
else
{
throw new RuntimeException("Unsupported Windows architecture: " + arch);
}
platformLibs = new PlatformLibs("fastddsjava.native.windows-x86_64", "jnifastddsjava.dll",
platformLibs = new PlatformLibs("fastddsjava.native." + archPackage, "jnifastddsjava.dll",
new String[] {"fastcdr-2.3.dll", "fastdds-3.6.dll"});
}
else if (os.contains("mac"))
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.