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
42 changes: 42 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,45 @@ build:libc++ --action_env=BAZEL_CXXOPTS=-stdlib=libc++
build:libc++ --action_env=BAZEL_LINKLIBS=-l%:libc++.a:-l%:libc++abi.a
build:libc++ --action_env=BAZEL_LINKOPTS=-lm:-pthread
build:libc++ --define force_libcpp=enabled

# Android NDK Toolchain Configurations
# Prerequisites:
# 1. Install Android NDK (r25b or later)
# 2. Set ANDROID_NDK_HOME to the NDK installation path
# 3. Add to MODULE.bazel (see bazel/android/ndk.MODULE.bazel):
# android_ndk_repository_extension = use_extension(...)
# use_repo(android_ndk_repository_extension, "androidndk")
# register_toolchains("@androidndk//:all")
build:android_arm64 --platforms=//platform/android:android_arm64
build:android_arm64 --action_env=ANDROID_NDK_HOME
build:android_arm64 --cxxopt=-D__ANDROID_API__=28
build:android_arm64 --cpu=aarch64
build:android_arm64 --linkopt=-lc++_static
build:android_arm64 --linkopt=-lc++abi
build:android_arm64 --extra_toolchains=@androidndk//:all

build:android_x86_64 --platforms=//platform/android:android_x86_64
build:android_x86_64 --action_env=ANDROID_NDK_HOME
build:android_x86_64 --cxxopt=-D__ANDROID_API__=28
build:android_x86_64 --cpu=x86_64
build:android_x86_64 --linkopt=-lc++_static
build:android_x86_64 --linkopt=-lc++abi
build:android_x86_64 --extra_toolchains=@androidndk//:all

build:android --config=android_arm64

# QNX 8 Toolchain Configurations
# Set QNX_SDP_PATH environment variable or use default ~/qnx800
build:qnx_aarch64 --platforms=//bazel/toolchains/qnx/platforms:qnx_aarch64
build:qnx_aarch64 --action_env=QNX_SDP_PATH
build:qnx_aarch64 --define=QNX_SDP_PATH=/home/dave.allison/qnx800
build:qnx_aarch64 --cxxopt=-D__QNX__

build:qnx_x86_64 --platforms=//bazel/toolchains/qnx/platforms:qnx_x86_64
build:qnx_x86_64 --action_env=QNX_SDP_PATH
build:qnx_x86_64 --define=QNX_SDP_PATH=/home/dave.allison/qnx800
build:qnx_x86_64 --cxxopt=-D__QNX__

# QNX common flags
build:qnx --cxxopt=-std=c++17
build:qnx --cxxopt=-Wno-sign-compare
72 changes: 72 additions & 0 deletions .github/scripts/android-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/bin/bash
set -euo pipefail

# Wait for device to be fully available after emulator boot
adb wait-for-device
adb root
sleep 5
adb wait-for-device
adb shell "while [[ -z \$(getprop sys.boot_completed) ]]; do sleep 1; done"

# Create shared memory directory
adb shell "mkdir -p /dev/subspace && chmod 777 /dev/subspace"
adb shell "mkdir -p /data/local/tmp"

# Collect shared libraries (dereference symlinks from bazel output)
mkdir -p /tmp/android_libs
find bazel-bin/ -name "*.so" -path "*_solib*" -exec cp -L {} /tmp/android_libs/ \; 2>/dev/null || true
find bazel-bin/plugins/ -name "*.so" -exec cp -L {} /tmp/android_libs/ \; 2>/dev/null || true

if ls /tmp/android_libs/*.so 1>/dev/null 2>&1; then
adb push /tmp/android_libs /data/local/tmp/android_libs
fi

LIB="LD_LIBRARY_PATH=/data/local/tmp/android_libs"

# Push test binaries
adb push bazel-bin/server/subspace_server /data/local/tmp/subspace_server
adb push bazel-bin/client/client_test /data/local/tmp/client_test
adb push bazel-bin/client/bridge_test /data/local/tmp/bridge_test
adb push bazel-bin/common/split_buffer_test /data/local/tmp/split_buffer_test
adb push bazel-bin/coro_rpc/test/rpc_test /data/local/tmp/coro_rpc_test
adb push bazel-bin/coro_rpc/server/server_test /data/local/tmp/coro_rpc_server_test
adb push bazel-bin/coro_rpc/client/client_test /data/local/tmp/coro_rpc_client_test
adb push bazel-bin/co20_rpc/test/rpc_test /data/local/tmp/co20_rpc_test
adb push bazel-bin/co20_rpc/server/server_test /data/local/tmp/co20_rpc_server_test
adb push bazel-bin/co20_rpc/client/client_test /data/local/tmp/co20_rpc_client_test
adb push bazel-bin/asio_rpc/test/rpc_test /data/local/tmp/asio_rpc_test
adb push bazel-bin/asio_rpc/server/server_test /data/local/tmp/asio_rpc_server_test
adb push bazel-bin/asio_rpc/client/client_test /data/local/tmp/asio_rpc_client_test

# Push plugin .so files to relative path expected by tests
adb shell "mkdir -p /data/local/tmp/plugins"
find bazel-bin/plugins/ -name "*.so" -exec adb push {} /data/local/tmp/plugins/ \; 2>/dev/null || true

# Make binaries executable
adb shell "chmod +x /data/local/tmp/*_test /data/local/tmp/subspace_server"

echo "=== split_buffer_test ==="
adb shell "cd /data/local/tmp && $LIB ./split_buffer_test"

echo "=== client_test ==="
adb shell "cd /data/local/tmp && $LIB ./client_test"

echo "=== bridge_test ==="
adb shell "cd /data/local/tmp && $LIB ./bridge_test"

echo "=== coro_rpc tests ==="
adb shell "cd /data/local/tmp && $LIB ./coro_rpc_test"
adb shell "cd /data/local/tmp && $LIB ./coro_rpc_server_test"
adb shell "cd /data/local/tmp && $LIB ./coro_rpc_client_test"

echo "=== co20_rpc tests ==="
adb shell "cd /data/local/tmp && $LIB ./co20_rpc_test"
adb shell "cd /data/local/tmp && $LIB ./co20_rpc_server_test"
adb shell "cd /data/local/tmp && $LIB ./co20_rpc_client_test"

echo "=== asio_rpc tests ==="
adb shell "cd /data/local/tmp && $LIB ./asio_rpc_test"
adb shell "cd /data/local/tmp && $LIB ./asio_rpc_server_test"
adb shell "cd /data/local/tmp && $LIB ./asio_rpc_client_test"

echo "=== All Android tests passed ==="
56 changes: 56 additions & 0 deletions .github/scripts/cmake-android-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/bin/bash
set -euo pipefail

BUILD_DIR="build/android"

# Wait for device to be fully available after emulator boot
adb wait-for-device
adb root
sleep 5
adb wait-for-device
adb shell "while [[ -z \$(getprop sys.boot_completed) ]]; do sleep 1; done"

# Create shared memory directory
adb shell "mkdir -p /dev/subspace && chmod 777 /dev/subspace"
adb shell "mkdir -p /data/local/tmp"

# Push libc++_shared.so from NDK (needed since we built with ANDROID_STL=c++_shared)
NDK_LIBCXX=$(find "$ANDROID_NDK_HOME" -name "libc++_shared.so" -path "*/x86_64-linux-android/*" | head -1)
if [ -n "$NDK_LIBCXX" ]; then
adb push "$NDK_LIBCXX" /data/local/tmp/libc++_shared.so
fi

LIB="LD_LIBRARY_PATH=/data/local/tmp:/data/local/tmp/plugins"

# Push test binaries
adb push "$BUILD_DIR/server/subspace_server" /data/local/tmp/subspace_server
adb push "$BUILD_DIR/client/client_test" /data/local/tmp/client_test
adb push "$BUILD_DIR/common/split_buffer_test" /data/local/tmp/split_buffer_test
adb push "$BUILD_DIR/common/common_test" /data/local/tmp/common_test
adb push "$BUILD_DIR/c_client/c_client_test" /data/local/tmp/c_client_test
adb push "$BUILD_DIR/shadow/shadow_test" /data/local/tmp/shadow_test

# Push plugin .so files
adb shell "mkdir -p /data/local/tmp/plugins"
adb push "$BUILD_DIR/plugins/nop_plugin.so" /data/local/tmp/plugins/
adb push "$BUILD_DIR/plugins/split_buffer_free_test_plugin.so" /data/local/tmp/plugins/

# Make binaries executable
adb shell "chmod +x /data/local/tmp/*_test /data/local/tmp/subspace_server"

echo "=== common_test ==="
adb shell "cd /data/local/tmp && $LIB ./common_test"

echo "=== split_buffer_test ==="
adb shell "cd /data/local/tmp && $LIB ./split_buffer_test"

echo "=== client_test ==="
adb shell "cd /data/local/tmp && $LIB ./client_test"

echo "=== c_client_test ==="
adb shell "cd /data/local/tmp && $LIB ./c_client_test"

echo "=== shadow_test ==="
adb shell "cd /data/local/tmp && $LIB ./shadow_test"

echo "=== All CMake Android tests passed ==="
107 changes: 107 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,110 @@ jobs:

- name: Run CMake tests
run: ctest --test-dir build/cmake-${{ matrix.build_type }} --output-on-failure

cmake-android:
name: cmake-android (x86_64)
runs-on: ubuntu-latest
timeout-minutes: 45

steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Set up Android NDK
run: echo "ANDROID_NDK_HOME=$ANDROID_NDK_LATEST_HOME" >> $GITHUB_ENV

- name: Configure CMake for Android x86_64
run: |
cmake -S . -B build/android \
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=x86_64 \
-DANDROID_PLATFORM=android-28 \
-DANDROID_STL=c++_shared \
-DCMAKE_BUILD_TYPE=Release

- name: Build
run: cmake --build build/android --parallel $(nproc)

- name: Enable KVM
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm

- name: Run tests on Android emulator
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 30
target: google_apis
arch: x86_64
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
emulator-boot-timeout: 900
script: bash .github/scripts/cmake-android-test.sh

android:
name: android (x86_64)
runs-on: ubuntu-latest
timeout-minutes: 45

steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Install Bazel
uses: bazel-contrib/setup-bazel@0.18.0
with:
bazelisk-cache: true
disk-cache: ${{ github.workflow }}-android
repository-cache: true

- name: Set up Android NDK
run: |
ANDROID_SDK_ROOT="${ANDROID_HOME:-/usr/local/lib/android/sdk}"
# Find the installed NDK version
NDK_VERSION=$(ls "$ANDROID_SDK_ROOT/ndk" | sort -V | tail -1)
echo "ANDROID_NDK_HOME=$ANDROID_SDK_ROOT/ndk/$NDK_VERSION" >> "$GITHUB_ENV"

- name: Cross-compile for Android x86_64
run: |
bazel build \
//server:subspace_server \
//client:client_test \
//client:bridge_test \
//common:split_buffer_test \
//plugins:nop_plugin.so \
//plugins:split_buffer_free_test_plugin.so \
//coro_rpc/test:rpc_test \
//coro_rpc/server:server_test \
//coro_rpc/client:client_test \
//co20_rpc/test:rpc_test \
//co20_rpc/server:server_test \
//co20_rpc/client:client_test \
//asio_rpc/test:rpc_test \
//asio_rpc/server:server_test \
//asio_rpc/client:client_test \
--verbose_failures \
--config=android_x86_64

- name: Enable KVM
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm

- name: Run tests on Android emulator
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 30
target: google_apis
arch: x86_64
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
emulator-boot-timeout: 900
script: bash .github/scripts/android-test.sh

- name: Upload Android test logs
uses: actions/upload-artifact@v7
if: failure()
with:
name: android-test-logs
path: bazel-testlogs
23 changes: 23 additions & 0 deletions Android.bp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2023-2026 David Allison
// All Rights Reserved
// See LICENSE file for licensing information.

// Common defaults for all subspace native modules.
cc_defaults {
name: "subspace_defaults",
cflags: [
"-std=c++17",
"-Wall",
"-Wextra",
"-Wno-missing-field-initializers",
"-Wno-unused-parameter",
],
target: {
android: {
cflags: ["-DSUBSPACE_ANDROID"],
},
},
local_include_dirs: ["."],
stl: "c++_shared",
min_sdk_version: "28",
}
19 changes: 16 additions & 3 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,29 @@ package(default_visibility = ["//visibility:public"])

config_setting(
name = "macos_arm64",
values = {"cpu": "darwin_arm64"},
constraint_values = [
"@platforms//os:macos",
"@platforms//cpu:aarch64",
],
)

config_setting(
name = "macos_default",
values = {"cpu": "darwin"},
constraint_values = [
"@platforms//os:macos",
],
)

config_setting(
name = "macos_x86_64",
values = {"cpu": "darwin_x86_64"},
constraint_values = [
"@platforms//os:macos",
"@platforms//cpu:x86_64",
],
)

config_setting(
name = "android",
constraint_values = ["@platforms//os:android"],
)

19 changes: 14 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,20 @@ set(ABSL_BUILD_TEST_HELPERS ON CACHE INTERNAL "Enable Abseil TESTONLY+PUBLIC hel
set(ABSL_USE_EXTERNAL_GOOGLETEST ON CACHE INTERNAL "Use our GoogleTest instead of Abseil downloading its own")
set(ABSL_FIND_GOOGLETEST OFF CACHE INTERNAL "Don't find_package(GTest); we provide it via FetchContent")

# When cross-compiling, don't build protoc (we use a host-native one).
if(CMAKE_CROSSCOMPILING)
set(protobuf_BUILD_PROTOC_BINARIES OFF CACHE INTERNAL "Skip building protoc for target")
endif()

# Add common compile options as found in subspace/BUILD
# These will apply to all targets in this CMakeLists.txt unless overridden.
add_compile_options(-Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter)

# --- Android-specific settings ---
if(ANDROID)
add_compile_definitions(SUBSPACE_ANDROID)
endif()

# --- Apple Silicon (ARM64) specific settings ---
# Ensure that CMake targets the correct architecture when building on Apple platforms.
# This value will be propagated to sub-dependencies.
Expand Down Expand Up @@ -97,11 +107,10 @@ FetchContent_Declare(
protobuf
GIT_REPOSITORY https://github.com/protocolbuffers/protobuf.git
GIT_TAG v29.5
# Protobuf's CMake build can be configured to build only necessary components
CMAKE_ARGS
-Dprotobuf_BUILD_TESTS=OFF # Explicitly disable building tests to avoid gmock conflicts
-Dprotobuf_BUILD_TESTS=OFF
-Dprotobuf_BUILD_EXAMPLES=OFF
-Dprotobuf_BUILD_SHARED_LIBS=OFF # Build static libs
-Dprotobuf_BUILD_SHARED_LIBS=OFF
-DCMAKE_OSX_ARCHITECTURES="${CMAKE_OSX_ARCHITECTURES}"
)
FetchContent_MakeAvailable(protobuf)
Expand All @@ -124,10 +133,10 @@ if(SUBSPACE_PYTHON)
FetchContent_MakeAvailable(pybind11)
endif()

#add to get proto/subspace.pb.h working (build dir first so generated files win)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
#add to get */file.h includes working
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
#add to get proto/subspace.pb.h working
include_directories(${CMAKE_CURRENT_BINARY_DIR})
# --- Subspace Tests Target ---
# Corresponds to //subspace/tests:tests
enable_testing() # Enable CTest for running tests
Expand Down
Loading
Loading