Skip to content
Open
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
195 changes: 195 additions & 0 deletions .github/workflows/android_build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
name: android-cross-build

on:
push:
branches: [ "main" ]
paths-ignore:
- '**.md'
merge_group:
pull_request:
branches: [ "main" ]
paths-ignore:
- '**.md'
workflow_dispatch:

jobs:
build-android:
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
# abi: [arm64-v8a, armeabi-v7a, x86_64]
abi: [x86_64]
api: [21]

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Cache dependencies
uses: actions/cache@v3
with:
path: |
~/.ccache
key: ${{ runner.os }}-dependencies-cache-${{ hashFiles('**/CMakeLists.txt', 'thirdparty/**') }}-stl-fix
restore-keys: |
${{ runner.os }}-dependencies-cache-

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
cmake ninja-build git ca-certificates python3 \
build-essential make ccache

- name: Setup Java 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '17'

- name: Setup Android NDK
uses: android-actions/setup-android@v3

- name: Install NDK (side by side)
shell: bash
run: |
# yes | sdkmanager --licenses
sdkmanager "ndk;26.1.10909125"

- name: Cache host protoc build
uses: actions/cache@v3
with:
path: build-host
key: ${{ runner.os }}-host-protoc-${{ hashFiles('src/**', 'CMakeLists.txt') }}-stl-fix
restore-keys: |
${{ runner.os }}-host-protoc-

- name: Use host env to compile protoc
shell: bash
run: |
git submodule update --init
if [ ! -d "build-host" ]; then
# Setup ccache for host build
export CCACHE_BASEDIR="$GITHUB_WORKSPACE"
export CCACHE_NOHASHDIR=1
export CCACHE_SLOPPINESS=clang_index_store,file_stat_matches,include_file_mtime,locale,time_macros

cmake -S . -B build-host -G Ninja \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
cmake --build build-host --target protoc --parallel
else
echo "Using cached host protoc build"
fi

- name: Cache Android build
uses: actions/cache@v3
with:
path: build-android-${{ matrix.abi }}
key: ${{ runner.os }}-android-build-${{ matrix.abi }}-${{ hashFiles('src/**', 'CMakeLists.txt', 'cmake/**', 'thirdparty/**') }}-stl-fix-2

- name: Configure and Build
shell: bash
run: |
git submodule foreach --recursive 'git stash --include-untracked'

export ANDROID_SDK_ROOT="$ANDROID_HOME"
export ANDROID_NDK_HOME="$ANDROID_SDK_ROOT/ndk/26.1.10909125"

# Setup ccache
export CCACHE_BASEDIR="$GITHUB_WORKSPACE"
export CCACHE_NOHASHDIR=1
export CCACHE_SLOPPINESS=clang_index_store,file_stat_matches,include_file_mtime,locale,time_macros

if [ ! -d "build-android-${{ matrix.abi }}" ]; then
cmake -S . -B build-android-${{ matrix.abi }} -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake" \
-DANDROID_ABI=${{ matrix.abi }} \
-DANDROID_PLATFORM=android-${{ matrix.api }} \
-DANDROID_STL=c++_static \
-DBUILD_PYTHON_BINDINGS=OFF \
-DBUILD_TOOLS=OFF \
-DGLOBAL_CC_PROTOBUF_PROTOC="$GITHUB_WORKSPACE/build-host/bin/protoc" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
cmake --build build-android-${{ matrix.abi }} --parallel
else
echo "Using cached Android build directory"
fi


- name: Cache examples build
uses: actions/cache@v3
with:
path: examples/c++/build-android-examples-${{ matrix.abi }}
key: ${{ runner.os }}-examples-build-${{ matrix.abi }}-${{ hashFiles('examples/c++/**', 'CMakeLists.txt', 'src/**') }}-stl-fix-2

- name: Build examples
shell: bash
run: |
if [ ! -d "examples/c++/build-android-examples-${{ matrix.abi }}" ]; then
cmake -S examples/c++ -B examples/c++/build-android-examples-${{ matrix.abi }} -G Ninja \
-DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake" \
-DANDROID_ABI=${{ matrix.abi }} \
-DANDROID_PLATFORM=android-${{ matrix.api }} \
-DANDROID_STL=c++_static \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
-DHOST_BUILD_DIR="build-android-${{ matrix.abi }}" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
cmake --build examples/c++/build-android-examples-${{ matrix.abi }} --parallel
else
echo "Using cached examples build"
fi

- name: Install ADB and setup Android emulator
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ matrix.api }}
arch: ${{ matrix.abi }}
# target: google_apis
# emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim
# disable-animations: true
script: |
# Wait for device to be ready
adb wait-for-device

# Check file sizes before pushing
echo "Checking binary sizes:"
ls -lah examples/c++/build-android-examples-${{ matrix.abi }}/

# Check device architecture
echo "Device architecture info:"
adb shell 'getprop ro.product.cpu.abi'
adb shell 'getprop ro.product.cpu.abilist'

# Push executables to device
adb push examples/c++/build-android-examples-${{ matrix.abi }}/ailego-example /data/local/tmp/
adb push examples/c++/build-android-examples-${{ matrix.abi }}/core-example /data/local/tmp/
adb push examples/c++/build-android-examples-${{ matrix.abi }}/db-example /data/local/tmp/

# Make executables executable
adb shell 'chmod 755 /data/local/tmp/ailego-example'
adb shell 'chmod 755 /data/local/tmp/core-example'
adb shell 'chmod 755 /data/local/tmp/db-example'

# Verify file integrity
echo "File info on device:"
adb shell 'ls -la /data/local/tmp/ailego-example'
adb shell 'ls -la /data/local/tmp/core-example'
adb shell 'ls -la /data/local/tmp/db-example'

echo "Running ailego example:"
adb shell 'cd /data/local/tmp && ./ailego-example'
echo "Exit code: $?"

echo "Running core example:"
adb shell 'cd /data/local/tmp && ./core-example'
echo "Exit code: $?"

echo "Running db example:"
adb shell 'cd /data/local/tmp && ./db-example'
echo "Exit code: $?"
Comment on lines 17 to 195

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}

Copilot Autofix

AI 4 days ago

In general, fix this by explicitly specifying permissions for the GITHUB_TOKEN in the workflow, either at the top level (applies to all jobs) or per-job, and restricting them to the minimum needed. For this build-focused workflow, all steps only need to read repository contents (the checkout action and cache keys based on hashFiles), so contents: read is sufficient.

The best minimal fix without changing functionality is to add a top-level permissions block right after the name: declaration (or before jobs:) in .github/workflows/android_build.yml. This will apply to the build-android job and any future jobs that do not override permissions. No additional imports or methods are needed; this is purely a YAML configuration change. Concretely, insert:

permissions:
  contents: read

near the top of the file, keeping indentation consistent with other top-level keys.

Suggested changeset 1
.github/workflows/android_build.yml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/android_build.yml b/.github/workflows/android_build.yml
--- a/.github/workflows/android_build.yml
+++ b/.github/workflows/android_build.yml
@@ -1,5 +1,8 @@
 name: android-cross-build
 
+permissions:
+  contents: read
+
 on:
   push:
     branches: [ "main" ]
EOF
@@ -1,5 +1,8 @@
name: android-cross-build

permissions:
contents: read

on:
push:
branches: [ "main" ]
Copilot is powered by AI and may make mistakes. Always verify output.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ build*
bin/*
lib/*
var/*
thirdparty
venv*
tests/integration/conf/*
tests/de_integration/conf/*
Expand Down Expand Up @@ -48,3 +47,5 @@ yarn-debug.log*
yarn-error.log*

allure-*

!build_android.sh
65 changes: 65 additions & 0 deletions build_android.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/bin/bash
set -e
CURRENT_DIR=$(pwd)

ABI=${1:-"arm64-v8a"}
API_LEVEL=${2:-21}
BUILD_TYPE=${3:-"Release"}

# step1: use host env to compile protoc
echo "step1: building protoc for host..."
HOST_BUILD_DIR="build_host"
mkdir -p $HOST_BUILD_DIR
cd $HOST_BUILD_DIR

cmake -DCMAKE_BUILD_TYPE="$BUILD_TYPE" ..
make -j protoc
PROTOC_EXECUTABLE=$CURRENT_DIR/$HOST_BUILD_DIR/bin/protoc
cd $CURRENT_DIR

echo "step1: Done!!!"

# step2: cross build zvec based on android ndk
echo "step2: building zvec for android..."

# reset thirdparty directory
git submodule foreach --recursive 'git stash --include-untracked'

export ANDROID_SDK_ROOT=$HOME/Library/Android/sdk
export ANDROID_HOME=$ANDROID_SDK_ROOT
export ANDROID_NDK_HOME=$ANDROID_SDK_ROOT/ndk/28.2.13676358
export CMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake

export PATH=$PATH:$ANDROID_SDK_ROOT/cmdline-tools/latest/bin
export PATH=$PATH:$ANDROID_SDK_ROOT/platform-tools
export PATH=$PATH:$ANDROID_NDK_HOME

if [ -z "$ANDROID_NDK_HOME" ]; then
echo "error: ANDROID_NDK_HOME env not set"
echo "please install NDK and set env variable ANDROID_NDK_HOME"
exit 1
fi

BUILD_DIR="build_android_${ABI}"
mkdir -p $BUILD_DIR
cd $BUILD_DIR

echo "configure CMake..."
cmake \
-DANDROID_NDK="$ANDROID_NDK_HOME" \
-DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake" \
-DANDROID_ABI="$ABI" \
-DANDROID_NATIVE_API_LEVEL="$API_LEVEL" \
-DANDROID_STL="c++_static" \
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
-DBUILD_PYTHON_BINDINGS=OFF \
-DBUILD_TOOLS=OFF \
-DCMAKE_INSTALL_PREFIX="./install" \
-DGLOBAL_CC_PROTOBUF_PROTOC=$PROTOC_EXECUTABLE \
../

echo "building..."
CORE_COUNT=$(sysctl -n hw.ncpu)
make -j$CORE_COUNT

echo "step2: Done!!!"
3 changes: 3 additions & 0 deletions cmake/bazel.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -1313,6 +1313,9 @@ function(cc_proto_library)

_find_protobuf("${CC_ARGS_PROTOBUF_VERSION}")
set(CC_PROTOBUF_PROTOC ${CC_PROTOBUF_PROTOC_${CC_ARGS_PROTOBUF_VERSION}})
if(DEFINED GLOBAL_CC_PROTOBUF_PROTOC)
set(CC_PROTOBUF_PROTOC ${GLOBAL_CC_PROTOBUF_PROTOC})
endif()
set(CC_PROTOBUF_INCS ${CC_PROTOBUF_INCS_${CC_ARGS_PROTOBUF_VERSION}})
set(CC_PROTOBUF_LIBS ${CC_PROTOBUF_LIBS_${CC_ARGS_PROTOBUF_VERSION}})

Expand Down
56 changes: 54 additions & 2 deletions examples/c++/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@ set(CMAKE_CXX_STANDARD 17)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# --- Paths to Zvec and dependencies ---
# Allow custom host build directory, default to "build"
if(NOT DEFINED HOST_BUILD_DIR)
set(HOST_BUILD_DIR "build")
endif()

set(ZVEC_INCLUDE_DIR ${CMAKE_BINARY_DIR}/../../../src/include)
set(ZVEC_LIB_DIR ${CMAKE_BINARY_DIR}/../../../build/lib)
set(ZVEC_DEPENDENCY_LIB_DIR ${CMAKE_BINARY_DIR}/../../../build/external/usr/local/lib)
set(ZVEC_LIB_DIR ${CMAKE_BINARY_DIR}/../../../${HOST_BUILD_DIR}/lib)
set(ZVEC_DEPENDENCY_LIB_DIR ${CMAKE_BINARY_DIR}/../../../${HOST_BUILD_DIR}/external/usr/local/lib)

# Add include and library search paths
include_directories(${ZVEC_INCLUDE_DIR})
Expand Down Expand Up @@ -84,6 +89,16 @@ elseif(APPLE)
zvec-ailego
${zvec_core_deps}
)
elseif(ANDROID)
target_link_libraries(zvec-core INTERFACE
-Wl,--whole-archive
zvec_core
-Wl,--no-whole-archive
-Wl,--start-group
zvec-ailego
${zvec_core_deps}
-Wl,--end-group
)
else()
message(FATAL_ERROR "Unsupported platform: ${CMAKE_SYSTEM_NAME}")
endif()
Expand All @@ -106,6 +121,17 @@ elseif(APPLE)
zvec-ailego
${zvec_db_deps}
)
elseif(ANDROID)
target_link_libraries(zvec-db INTERFACE
zvec_db
zvec-core
zvec-ailego
-Wl,--start-group
${zvec_db_deps}
-Wl,--end-group
)
else()
message(FATAL_ERROR "Unsupported platform: ${CMAKE_SYSTEM_NAME}")
endif()


Expand All @@ -114,6 +140,11 @@ add_executable(db-example db/main.cc)
target_link_libraries(db-example PRIVATE
zvec-db
)
if(ANDROID)
target_link_libraries(db-example PRIVATE
log
)
endif()

add_executable(core-example core/main.cc)
target_link_libraries(core-example PRIVATE
Expand All @@ -124,3 +155,24 @@ add_executable(ailego-example ailego/main.cc)
target_link_libraries(ailego-example PRIVATE
zvec-ailego
)

# Strip symbols to reduce executable size
if(CMAKE_BUILD_TYPE STREQUAL "Release" OR ANDROID)
add_custom_command(TARGET db-example POST_BUILD
COMMAND ${CMAKE_STRIP} "$<TARGET_FILE:db-example>"
COMMENT "Stripping symbols from db-example")
add_custom_command(TARGET core-example POST_BUILD
COMMAND ${CMAKE_STRIP} "$<TARGET_FILE:core-example>"
COMMENT "Stripping symbols from core-example")
add_custom_command(TARGET ailego-example POST_BUILD
COMMAND ${CMAKE_STRIP} "$<TARGET_FILE:ailego-example>"
COMMENT "Stripping symbols from ailego-example")
endif()

# Optimize for size
if(CMAKE_BUILD_TYPE STREQUAL "Release" OR ANDROID)
set_property(TARGET db-example core-example ailego-example
PROPERTY COMPILE_FLAGS "-Os")
set_property(TARGET db-example core-example ailego-example
PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
endif()
Loading
Loading