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
188 changes: 188 additions & 0 deletions .github/workflows/android_build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
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]
api: [30] # arm64 emulator 建议 >= 30,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 SDK
uses: android-actions/setup-android@v3

- name: Install NDK (side by side)
shell: bash
run: |
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
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"

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: |
export ANDROID_SDK_ROOT="$ANDROID_HOME"
export ANDROID_NDK_HOME="$ANDROID_SDK_ROOT/ndk/26.1.10909125"

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

# 注意:emulator-runner 的 arch 需要 "arm64"(不是 arm64-v8a)
- name: Run on Android emulator (arm64) and verify
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ matrix.api }}
arch: arm64
target: google_apis
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -netdelay none -netspeed full
disable-animations: true
script: |
set -euxo pipefail

adb wait-for-device

echo "Device ABI:"
adb shell getprop ro.product.cpu.abi
adb shell getprop ro.product.cpu.abilist

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

# 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/

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

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 "Running core example:"
adb shell 'cd /data/local/tmp && ./core-example'

echo "Running db example:"
adb shell 'cd /data/local/tmp && ./db-example'
Comment on lines +17 to +188

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 about 9 hours ago

To fix the problem, explicitly declare least-privilege GITHUB_TOKEN permissions for this workflow. Since the job only needs to read repository contents (for actions/checkout) and interact with caches (which do not require repository write access), contents: read is sufficient as a minimal baseline. We can place a permissions: block at the root of the workflow, so it applies to all jobs, and keep it minimal.

The best fix without changing functionality is:

  • Add a root-level permissions: block after name: (or after on:) setting contents: read.
  • No job seems to require writes to pull requests, issues, or other resources, so we do not grant them.

Concretely, in .github/workflows/android_build.yml, add:

permissions:
  contents: read

right after the name: android-cross-build line. No additional imports or methods are needed since this is pure workflow configuration.

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