Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
5 changes: 5 additions & 0 deletions .github/workflows/01-ci-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,8 @@ jobs:
name: Build & Test (Windows)
needs: lint
uses: ./.github/workflows/05-windows-build.yml

build-ios:
name: Build & Test (iOS)
needs: lint
uses: ./.github/workflows/06-ios-build.yml
118 changes: 118 additions & 0 deletions .github/workflows/06-ios-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
name: iOS Cross Build

on:
workflow_call:
workflow_dispatch:

permissions:
contents: read

jobs:
build-ios:
runs-on: macos-15
strategy:
fail-fast: false
matrix:
include:
- platform: SIMULATORARM64
arch: arm64
sdk: iphonesimulator
test_on_simulator: true
- platform: OS
arch: arm64
sdk: iphoneos
test_on_simulator: false

name: iOS (${{ matrix.platform }})

steps:
- name: Checkout
uses: actions/checkout@v6
with:
submodules: recursive

- name: Cache host protoc build
uses: actions/cache@v5
with:
path: build_host
key: macos-host-protoc-${{ hashFiles('src/**', 'CMakeLists.txt') }}
restore-keys: |
macos-host-protoc-

- name: Build host protoc
run: |
if [ ! -f "build_host/bin/protoc" ]; then
cmake -S . -B build_host -DCMAKE_BUILD_TYPE=Release
cmake --build build_host --target protoc --parallel $(sysctl -n hw.ncpu)
else
echo "Using cached host protoc"
fi

- name: Cache iOS build
uses: actions/cache@v5
with:
path: build_ios_${{ matrix.platform }}
key: ios-build-${{ matrix.platform }}-${{ hashFiles('src/**', 'CMakeLists.txt', 'cmake/**', 'thirdparty/**') }}

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

SDK_PATH=$(xcrun --sdk ${{ matrix.sdk }} --show-sdk-path)
NPROC=$(sysctl -n hw.ncpu)

cmake -S . -B build_ios_${{ matrix.platform }} \
-DCMAKE_SYSTEM_NAME=iOS \
-DCMAKE_OSX_DEPLOYMENT_TARGET="13.0" \
-DCMAKE_OSX_ARCHITECTURES="${{ matrix.arch }}" \
-DCMAKE_OSX_SYSROOT="$SDK_PATH" \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_PYTHON_BINDINGS=OFF \
-DBUILD_TOOLS=OFF \
-DCMAKE_INSTALL_PREFIX="./install" \
-DGLOBAL_CC_PROTOBUF_PROTOC="$GITHUB_WORKSPACE/build_host/bin/protoc" \
-DIOS=ON

cmake --build build_ios_${{ matrix.platform }} --parallel $NPROC

- name: Build test targets
if: matrix.test_on_simulator
run: |
NPROC=$(sysctl -n hw.ncpu)
cmake --build build_ios_${{ matrix.platform }} --target collection_test --parallel $NPROC

- name: Boot iOS Simulator
if: matrix.test_on_simulator
run: |
DEVICE_ID=$(xcrun simctl list devices available -j \
| python3 -c "
import json, sys
data = json.load(sys.stdin)
for runtime, devices in data['devices'].items():
if 'iOS' in runtime:
for d in devices:
if 'iPhone' in d['name'] and d['isAvailable']:
print(d['udid'])
sys.exit(0)
sys.exit(1)
")
echo "DEVICE_ID=$DEVICE_ID" >> $GITHUB_ENV
xcrun simctl boot "$DEVICE_ID"
echo "Booted simulator: $DEVICE_ID"

- name: Run collection_test
if: matrix.test_on_simulator
run: |
xcrun simctl install "$DEVICE_ID" build_ios_${{ matrix.platform }}/bin/collection_test.app
xcrun simctl launch --console "$DEVICE_ID" com.zvec.collection_test 2>&1 | tee /tmp/collection_test.log
if grep -q '\[ FAILED \]' /tmp/collection_test.log; then
echo "::error::collection_test has failing tests:"
grep '\[ FAILED \]' /tmp/collection_test.log
exit 1
fi
grep -q '\[ PASSED \]' /tmp/collection_test.log

- name: Shutdown Simulator
if: matrix.test_on_simulator && always()
run: |
xcrun simctl shutdown "$DEVICE_ID" || true
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,6 @@ yarn-error.log*

allure-*

!build_android.sh
!build_android.sh
!build_ios.sh

22 changes: 19 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror=return-type")
endif()

if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT IOS)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-as-needed")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-as-needed")
endif()
Expand All @@ -47,7 +47,19 @@ message(STATUS "PROJECT_ROOT_DIR = ${PROJECT_ROOT_DIR}")
include(${PROJECT_ROOT_DIR}/cmake/bazel.cmake)
include(${PROJECT_ROOT_DIR}/cmake/option.cmake)

if (NOT ANDROID AND AUTO_DETECT_ARCH AND HOST_ARCH MATCHES "^(x86|x64)$")
# iOS platform detection
if(NOT ANDROID AND NOT IOS AND CMAKE_SYSTEM_NAME STREQUAL "iOS")
set(IOS TRUE)
endif()

# iOS bundle properties for test executables
if(IOS)
set(MACOSX_BUNDLE_BUNDLE_VERSION "1")
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "1.0")
set(CMAKE_MACOSX_BUNDLE_INFO_PLIST "${PROJECT_ROOT_DIR}/cmake/iOSBundleInfo.plist.in")
endif()

if (NOT ANDROID AND NOT IOS AND AUTO_DETECT_ARCH AND HOST_ARCH MATCHES "^(x86|x64)$")
setup_compiler_march_for_x86(MATH_MARCH_FLAG_SSE MATH_MARCH_FLAG_AVX2 MATH_MARCH_FLAG_AVX512 MATH_MARCH_FLAG_AVX512FP16)
message(STATUS "best compiler march, sse: " ${MATH_MARCH_FLAG_SSE} ", avx2: " ${MATH_MARCH_FLAG_AVX2} ", avx512: " ${MATH_MARCH_FLAG_AVX512} ", avx512fp16: " ${MATH_MARCH_FLAG_AVX512FP16})
endif()
Expand All @@ -66,7 +78,7 @@ message(STATUS "BUILD_TOOLS:${BUILD_TOOLS}")

option(RABITQ_ENABLE_AVX512 "Compile RaBitQ with AVX-512 support" OFF)

if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64" AND NOT ANDROID)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64" AND NOT ANDROID AND NOT IOS)
include(CheckCCompilerFlag)

check_c_compiler_flag("-mavx2" COMPILER_SUPPORTS_AVX2)
Expand All @@ -86,6 +98,10 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64
add_definitions(-DRABITQ_SUPPORTED=0)
message(STATUS "RaBitQ support disabled - compiler does not support AVX2 or AVX-512")
endif()
elseif(IOS)
set(RABITQ_SUPPORTED OFF)
add_definitions(-DRABITQ_SUPPORTED=0)
message(STATUS "RaBitQ support disabled - not supported on iOS")
else()
set(RABITQ_SUPPORTED OFF)
add_definitions(-DRABITQ_SUPPORTED=0)
Expand Down
34 changes: 30 additions & 4 deletions cmake/bazel.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -584,9 +584,16 @@ macro(_add_library _NAME _OPTION)
add_library(
${_NAME}_static STATIC ${_OPTION} $<TARGET_OBJECTS:${_NAME}_objects>
)
add_library(
${_NAME} SHARED ${_OPTION} $<TARGET_OBJECTS:${_NAME}_objects>
)
if(IOS)
# iOS: create the main target as static too (no shared libs on iOS)
add_library(
${_NAME} STATIC ${_OPTION} $<TARGET_OBJECTS:${_NAME}_objects>
)
else()
add_library(
${_NAME} SHARED ${_OPTION} $<TARGET_OBJECTS:${_NAME}_objects>
)
endif()
add_dependencies(${_NAME} ${_NAME}_static)
if(NOT MSVC)
set_property(TARGET ${_NAME}_static PROPERTY OUTPUT_NAME ${_NAME})
Expand Down Expand Up @@ -708,7 +715,7 @@ function(_target_link_libraries _NAME)
endif()

if(NOT MSVC)
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "iOS")
list(APPEND LINK_LIBS -Wl,--whole-archive ${LIB} -Wl,--no-whole-archive)
else()
list(APPEND LINK_LIBS -Wl,-force_load ${LIB})
Expand Down Expand Up @@ -1011,6 +1018,13 @@ function(cc_binary)
endif()
add_executable(${CC_ARGS_NAME} ${CC_ARGS_SRCS})

# iOS: set bundle properties for simulator/device installation
if(IOS)
set_target_properties(${CC_ARGS_NAME} PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${PROJECT_ROOT_DIR}/cmake/iOSBundleInfo.plist.in"
)
endif()

if(CC_ARGS_PACKED)
install(
TARGETS ${CC_ARGS_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
Expand Down Expand Up @@ -1051,8 +1065,20 @@ function(cc_test)
string(REPLACE "-" "_" MACRO_PREFIX "${CC_ARGS_NAME}")
list(APPEND CC_ARGS_DEFS ${MACRO_PREFIX}_VERSION="${CC_ARGS_VERSION}")
endif()
# iOS: add sandbox helper to redirect CWD to writable directory
if(IOS)
list(APPEND CC_ARGS_SRCS "${PROJECT_ROOT_DIR}/tests/ios_test_sandbox.cc")
endif()

add_executable(${CC_ARGS_NAME} EXCLUDE_FROM_ALL ${CC_ARGS_SRCS})

# iOS: set bundle properties for simulator/device installation
if(IOS)
set_target_properties(${CC_ARGS_NAME} PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${PROJECT_ROOT_DIR}/cmake/iOSBundleInfo.plist.in"
)
endif()

_cc_target_properties(
NAME "${CC_ARGS_NAME}"
INCS "${CC_ARGS_INCS}"
Expand Down
22 changes: 22 additions & 0 deletions cmake/iOSBundleInfo.plist.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.zvec.${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
</dict>
</plist>
5 changes: 5 additions & 0 deletions cmake/option.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,11 @@ function(setup_compiler_march_for_x86 VAR_NAME_SSE VAR_NAME_AVX2 VAR_NAME_AVX512
endforeach()
endfunction()

# iOS: Skip -march flags and OpenMP; architecture is controlled by CMAKE_OSX_ARCHITECTURES
if(IOS OR CMAKE_SYSTEM_NAME STREQUAL "iOS")
return()
endif()

if(NOT AUTO_DETECT_ARCH)
if(ENABLE_NATIVE)
if (NOT MSVC)
Expand Down
98 changes: 98 additions & 0 deletions scripts/build_ios.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#!/bin/bash
set -e
CURRENT_DIR=$(pwd)

# Platform options: OS (arm64 device), SIMULATOR64 (x86_64 sim), SIMULATORARM64 (arm64 sim)
PLATFORM=${1:-"OS"}
BUILD_TYPE=${2:-"Release"}
IOS_DEPLOYMENT_TARGET="13.0"

# Determine architecture based on platform
case "$PLATFORM" in
"OS")
ARCH="arm64"
;;
"SIMULATOR64")
ARCH="x86_64"
;;
"SIMULATORARM64")
ARCH="arm64"
;;
*)
echo "error: Unknown platform '$PLATFORM'"
echo "Usage: $0 [OS|SIMULATOR64|SIMULATORARM64] [Release|Debug]"
echo " OS - Build for iOS device (arm64)"
echo " SIMULATOR64 - Build for iOS Simulator (x86_64)"
echo " SIMULATORARM64- Build for iOS Simulator (arm64, Apple Silicon)"
exit 1
;;
esac

echo "Building zvec for iOS"
echo " Platform: $PLATFORM"
echo " Architecture: $ARCH"
echo " Build Type: $BUILD_TYPE"
echo " iOS Deployment Target: $IOS_DEPLOYMENT_TARGET"

# step1: use host env to compile protoc
echo "step1: building protoc for host..."

git submodule foreach --recursive 'git stash --include-untracked'

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 for iOS
echo "step2: building zvec for iOS..."

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

BUILD_DIR="build_ios_${PLATFORM}"
mkdir -p $BUILD_DIR
cd $BUILD_DIR

# Determine SDK and additional flags based on platform
if [ "$PLATFORM" = "OS" ]; then
SDK_NAME="iphoneos"
else
SDK_NAME="iphonesimulator"
fi

SDK_PATH=$(xcrun --sdk $SDK_NAME --show-sdk-path)

echo "configure CMake..."
cmake \
-DCMAKE_SYSTEM_NAME=iOS \
-DCMAKE_OSX_DEPLOYMENT_TARGET="$IOS_DEPLOYMENT_TARGET" \
-DCMAKE_OSX_ARCHITECTURES="$ARCH" \
-DCMAKE_OSX_SYSROOT="$SDK_PATH" \
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
-DBUILD_PYTHON_BINDINGS=OFF \
-DBUILD_TOOLS=OFF \
-DCMAKE_INSTALL_PREFIX="./install" \
-DGLOBAL_CC_PROTOBUF_PROTOC=$PROTOC_EXECUTABLE \
-DIOS=ON \
../

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

echo "step2: Done!!!"
echo ""
echo "Build completed successfully!"
echo "Output directory: $CURRENT_DIR/$BUILD_DIR"

# Test On MacOS15
# 1: xcrun simctl boot "iPhone 16"
# 2: cd $BUILD_DIR
# 3: xcrun simctl launch --console booted com.zvec.collection_test
Loading
Loading