From 1b3053e99539670b1460e6b40c6297b21d8c942f Mon Sep 17 00:00:00 2001 From: "xufeihong.xfh" Date: Thu, 26 Mar 2026 14:52:29 +0800 Subject: [PATCH 1/9] support ios build --- .github/workflows/01-ci-pipeline.yml | 5 + .github/workflows/05-ios-build.yml | 136 +++++++++++++++++++++++++++ .gitignore | 3 +- CMakeLists.txt | 22 ++++- cmake/bazel.cmake | 34 ++++++- cmake/iOSBundleInfo.plist.in | 22 +++++ cmake/option.cmake | 6 ++ scripts/build_ios.sh | 96 +++++++++++++++++++ src/db/CMakeLists.txt | 3 +- src/db/common/CMakeLists.txt | 3 +- tests/ios_test_sandbox.cc | 45 +++++++++ thirdparty/arrow/CMakeLists.txt | 30 ++++++ thirdparty/arrow/arrow.ios.patch | 26 +++++ thirdparty/glog/CMakeLists.txt | 14 ++- thirdparty/lz4/CMakeLists.txt | 38 ++++++++ thirdparty/rocksdb/CMakeLists.txt | 16 ++++ thirdparty/rocksdb/rocksdb.ios.patch | 29 ++++++ 17 files changed, 516 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/05-ios-build.yml create mode 100644 cmake/iOSBundleInfo.plist.in create mode 100755 scripts/build_ios.sh create mode 100644 tests/ios_test_sandbox.cc create mode 100644 thirdparty/arrow/arrow.ios.patch create mode 100644 thirdparty/rocksdb/rocksdb.ios.patch diff --git a/.github/workflows/01-ci-pipeline.yml b/.github/workflows/01-ci-pipeline.yml index 9eb2c9d23..1634aa013 100644 --- a/.github/workflows/01-ci-pipeline.yml +++ b/.github/workflows/01-ci-pipeline.yml @@ -70,3 +70,8 @@ jobs: name: Build & Test (android) needs: lint uses: ./.github/workflows/04-android-build.yml + + build-ios: + name: Build & Test (iOS) + needs: lint + uses: ./.github/workflows/05-ios-build.yml diff --git a/.github/workflows/05-ios-build.yml b/.github/workflows/05-ios-build.yml new file mode 100644 index 000000000..e22e0c407 --- /dev/null +++ b/.github/workflows/05-ios-build.yml @@ -0,0 +1,136 @@ +name: iOS Cross Build + +on: + workflow_call: + +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 arrow_ipc_writer_test --parallel $NPROC + cmake --build build_ios_${{ matrix.platform }} --target collection_test --parallel $NPROC + cmake --build build_ios_${{ matrix.platform }} --target data_generator --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 data_generator (smoke test) + if: matrix.test_on_simulator + run: | + xcrun simctl install "$DEVICE_ID" build_ios_${{ matrix.platform }}/bin/data_generator.app + xcrun simctl launch --console "$DEVICE_ID" com.zvec.data_generator || true + + - name: Run arrow_ipc_writer_test + if: matrix.test_on_simulator + run: | + xcrun simctl install "$DEVICE_ID" build_ios_${{ matrix.platform }}/bin/arrow_ipc_writer_test.app + xcrun simctl launch --console "$DEVICE_ID" com.zvec.arrow_ipc_writer_test 2>&1 | tee /tmp/arrow_ipc_writer_test.log + if grep -q '\[ FAILED \]' /tmp/arrow_ipc_writer_test.log; then + echo "::error::arrow_ipc_writer_test has failing tests" + exit 1 + fi + grep -q '\[ PASSED \]' /tmp/arrow_ipc_writer_test.log + + - name: Run collection_test (all cases) + 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 diff --git a/.gitignore b/.gitignore index 0827e539d..bac88b13d 100644 --- a/.gitignore +++ b/.gitignore @@ -48,4 +48,5 @@ yarn-error.log* allure-* -!build_android.sh \ No newline at end of file +!build_android.sh +!build_ios.sh \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 0cd2d6ab9..ff5ed2640 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ set(CC_CXX_STANDARD 17) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror=return-type") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror=return-type") -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() @@ -20,7 +20,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 CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|i686|i386|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 CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|i686|i386|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() @@ -36,7 +48,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) @@ -56,6 +68,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) diff --git a/cmake/bazel.cmake b/cmake/bazel.cmake index 2e4f1ccf7..7540fe18f 100644 --- a/cmake/bazel.cmake +++ b/cmake/bazel.cmake @@ -570,9 +570,16 @@ macro(_add_library _NAME _OPTION) add_library( ${_NAME}_static STATIC ${_OPTION} $ ) - add_library( - ${_NAME} SHARED ${_OPTION} $ - ) + if(IOS) + # iOS: create the main target as static too (no shared libs on iOS) + add_library( + ${_NAME} STATIC ${_OPTION} $ + ) + else() + add_library( + ${_NAME} SHARED ${_OPTION} $ + ) + endif() add_dependencies(${_NAME} ${_NAME}_static) if(NOT MSVC) set_property(TARGET ${_NAME}_static PROPERTY OUTPUT_NAME ${_NAME}) @@ -665,7 +672,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}) @@ -965,6 +972,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}" @@ -1005,8 +1019,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}" diff --git a/cmake/iOSBundleInfo.plist.in b/cmake/iOSBundleInfo.plist.in new file mode 100644 index 000000000..ac6e41e80 --- /dev/null +++ b/cmake/iOSBundleInfo.plist.in @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleIdentifier + com.zvec.${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + ${MACOSX_BUNDLE_SHORT_VERSION_STRING} + CFBundleVersion + ${MACOSX_BUNDLE_BUNDLE_VERSION} + + diff --git a/cmake/option.cmake b/cmake/option.cmake index 49a85c58d..3b0765e46 100644 --- a/cmake/option.cmake +++ b/cmake/option.cmake @@ -147,6 +147,12 @@ if(MSVC) return() endif() +# iOS: Skip -march flags, architecture is controlled by CMAKE_OSX_ARCHITECTURES +if(IOS OR CMAKE_SYSTEM_NAME STREQUAL "iOS") + message(STATUS "iOS build detected, skipping -march flags (controlled by CMAKE_OSX_ARCHITECTURES)") + return() +endif() + if(NOT AUTO_DETECT_ARCH) if(ENABLE_NATIVE) add_arch_flag("-march=native" NATIVE ENABLE_NATIVE) diff --git a/scripts/build_ios.sh b/scripts/build_ios.sh new file mode 100755 index 000000000..731c0b8a5 --- /dev/null +++ b/scripts/build_ios.sh @@ -0,0 +1,96 @@ +#!/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" + CMAKE_SYSTEM_NAME="iOS" + ;; + "SIMULATOR64") + ARCH="x86_64" + CMAKE_SYSTEM_NAME="iOS" + ;; + "SIMULATORARM64") + ARCH="arm64" + CMAKE_SYSTEM_NAME="iOS" + ;; + *) + 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..." +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" + ENABLE_BITCODE="ON" +else + SDK_NAME="iphonesimulator" + ENABLE_BITCODE="OFF" +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 \ + -DENABLE_BITCODE="$ENABLE_BITCODE" \ + -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" diff --git a/src/db/CMakeLists.txt b/src/db/CMakeLists.txt index 765a1b4a6..8ca3ae1bd 100644 --- a/src/db/CMakeLists.txt +++ b/src/db/CMakeLists.txt @@ -16,12 +16,13 @@ file(GLOB_RECURSE ALL_DB_SRCS *.cc *.c *.h) cc_library( NAME zvec_db STATIC STRICT SRCS_NO_GLOB SRCS ${ALL_DB_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/proto/zvec.pb.cc - INCS . ${CMAKE_CURRENT_BINARY_DIR} + INCS . ${CMAKE_CURRENT_BINARY_DIR} ${gflags_INCLUDE_DIR} PUBINCS ${PROJECT_ROOT_DIR}/src/include LIBS zvec_ailego zvec_core glog + gflags roaring rocksdb antlr4 diff --git a/src/db/common/CMakeLists.txt b/src/db/common/CMakeLists.txt index cc2110aa3..d13884a1c 100644 --- a/src/db/common/CMakeLists.txt +++ b/src/db/common/CMakeLists.txt @@ -6,9 +6,10 @@ cc_library( NAME zvec_common STATIC STRICT ALWAYS_LINK SRCS *.cc LIBS glog + gflags zvec_ailego roaring rocksdb - INCS . + INCS . ${gflags_INCLUDE_DIR} VERSION "${PROXIMA_ZVEC_VERSION}" ) diff --git a/tests/ios_test_sandbox.cc b/tests/ios_test_sandbox.cc new file mode 100644 index 000000000..ca8bed2c9 --- /dev/null +++ b/tests/ios_test_sandbox.cc @@ -0,0 +1,45 @@ +// iOS test sandbox helper +// Automatically changes the working directory to a writable location +// before any test code runs. On iOS, the app bundle is read-only, +// so tests that write files need a writable CWD. + +#if defined(__APPLE__) +#include +#if TARGET_OS_IOS || TARGET_OS_SIMULATOR + +#include +#include +#include +#include + +__attribute__((constructor)) +static void ios_test_sandbox_setup() { + // 1. Raise file descriptor limit (iOS default is very low) + struct rlimit rl; + if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { + rlim_t target = 65536; + if (rl.rlim_cur < target) { + rl.rlim_cur = (rl.rlim_max >= target) ? target : rl.rlim_max; + if (setrlimit(RLIMIT_NOFILE, &rl) == 0) { + fprintf(stderr, "[iOS] File descriptor limit raised to: %llu\n", + (unsigned long long)rl.rlim_cur); + } + } + } + + // 2. Change CWD to writable sandbox directory + // TMPDIR is set by iOS to the app's writable sandbox tmp directory + const char* tmpdir = getenv("TMPDIR"); + if (tmpdir && chdir(tmpdir) == 0) { + fprintf(stderr, "[iOS] Working directory set to: %s\n", tmpdir); + } else { + // Fallback: try HOME directory + const char* home = getenv("HOME"); + if (home && chdir(home) == 0) { + fprintf(stderr, "[iOS] Working directory set to: %s\n", home); + } + } +} + +#endif // TARGET_OS_IOS || TARGET_OS_SIMULATOR +#endif // __APPLE__ diff --git a/thirdparty/arrow/CMakeLists.txt b/thirdparty/arrow/CMakeLists.txt index 4326ea92a..912ec15f6 100644 --- a/thirdparty/arrow/CMakeLists.txt +++ b/thirdparty/arrow/CMakeLists.txt @@ -2,6 +2,9 @@ set(ARROW_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/apache-arrow-21.0.0) if(ANDROID) set(ARROW_PATCH ${CMAKE_CURRENT_SOURCE_DIR}/arrow.android.patch) apply_patch_once("arrow_android_fix" "${ARROW_SRC_DIR}" "${ARROW_PATCH}") +elseif(IOS) + set(ARROW_IOS_PATCH ${CMAKE_CURRENT_SOURCE_DIR}/arrow.ios.patch) + apply_patch_once("arrow_ios_fix" "${ARROW_SRC_DIR}" "${ARROW_IOS_PATCH}") else() set(ARROW_PATCH ${CMAKE_CURRENT_SOURCE_DIR}/arrow.patch) apply_patch_once("arrow_fix" "${ARROW_SRC_DIR}" "${ARROW_PATCH}") @@ -48,6 +51,33 @@ if(ANDROID) LOG_BUILD ON LOG_INSTALL ON ) +elseif(IOS) + # Determine ARROW_CPU_FLAG based on architecture + if(CMAKE_OSX_ARCHITECTURES MATCHES "arm64") + set(IOS_ARROW_CPU_FLAG "aarch64") + elseif(CMAKE_OSX_ARCHITECTURES MATCHES "x86_64") + set(IOS_ARROW_CPU_FLAG "x86") + else() + set(IOS_ARROW_CPU_FLAG "aarch64") + endif() + # Propagate deployment target to Arrow's bundled dependencies via env var. + # Without this, sub-ExternalProjects (re2, utf8proc, etc.) pick up the SDK + # version instead of the intended deployment target, causing linker warnings. + set(_arrow_ios_env ${CONFIGURE_ENV_LIST} "IPHONEOS_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}") + ExternalProject_Add( + ARROW.BUILD PREFIX arrow + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/apache-arrow-21.0.0 + DOWNLOAD_COMMAND "" + BUILD_IN_SOURCE false + CONFIGURE_COMMAND env ${_arrow_ios_env} "${CMAKE_COMMAND}" ${CMAKE_CACHE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_DEBUG_POSTFIX= -DARROW_BUILD_SHARED=OFF -DARROW_ACERO=ON -DARROW_FILESYSTEM=ON -DARROW_DATASET=ON -DARROW_PARQUET=ON -DARROW_COMPUTE=ON -DARROW_WITH_ZLIB=OFF -DARROW_DEPENDENCY_SOURCE=BUNDLED -DARROW_MIMALLOC=OFF -DCMAKE_INSTALL_LIBDIR=lib -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET} -DCMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES} -DCMAKE_OSX_SYSROOT=${CMAKE_OSX_SYSROOT} -DARROW_CPU_FLAG=${IOS_ARROW_CPU_FLAG} "/cpp" + BUILD_COMMAND env "IPHONEOS_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}" "${CMAKE_COMMAND}" --build . --target all -- -j ${NPROC} + INSTALL_COMMAND "${CMAKE_COMMAND}" --install "" --prefix=${EXTERNAL_BINARY_DIR}/usr/local + BYPRODUCTS ${LIB_PARQUET} ${LIB_ARROW} ${LIB_COMPUTE} ${LIB_ACERO} ${LIB_ARROW_DEPENDS} ${LIB_ARROW_DATASET} + LOG_DOWNLOAD ON + LOG_CONFIGURE ON + LOG_BUILD ON + LOG_INSTALL ON + ) else() ExternalProject_Add( ARROW.BUILD PREFIX arrow diff --git a/thirdparty/arrow/arrow.ios.patch b/thirdparty/arrow/arrow.ios.patch new file mode 100644 index 000000000..b84ba5d56 --- /dev/null +++ b/thirdparty/arrow/arrow.ios.patch @@ -0,0 +1,26 @@ +diff --git a/cpp/src/arrow/CMakeLists.txt b/cpp/src/arrow/CMakeLists.txt +index 1234567..abcdefg 100644 +--- a/cpp/src/arrow/CMakeLists.txt ++++ b/cpp/src/arrow/CMakeLists.txt +@@ -173,7 +173,7 @@ list(APPEND ARROW_STATIC_INSTALL_INTERFACE_LIBS ${ARROW_SYSTEM_LINK_LIBS}) + + # Need -latomic on Raspbian. + # See also: https://issues.apache.org/jira/browse/ARROW-12860 +-if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND ${CMAKE_SYSTEM_PROCESSOR} MATCHES "armv7") ++if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "armv7") + string(APPEND ARROW_PC_LIBS_PRIVATE " -latomic") + list(APPEND ARROW_SHARED_INSTALL_INTERFACE_LIBS "atomic") + list(APPEND ARROW_STATIC_INSTALL_INTERFACE_LIBS "atomic") +diff --git a/cpp/src/arrow/acero/source_node.cc b/cpp/src/arrow/acero/source_node.cc +index 0f5840676..cf68bfdcb 100644 +--- a/cpp/src/arrow/acero/source_node.cc ++++ b/cpp/src/arrow/acero/source_node.cc +@@ -407,7 +407,7 @@ struct SchemaSourceNode : public SourceNode { + struct RecordBatchReaderSourceNode : public SourceNode { + RecordBatchReaderSourceNode(ExecPlan* plan, std::shared_ptr schema, + arrow::AsyncGenerator> generator) +- : SourceNode(plan, schema, generator) {} ++ : SourceNode(plan, schema, generator, Ordering::Implicit()) {} + + static Result Make(ExecPlan* plan, std::vector inputs, + const ExecNodeOptions& options) { diff --git a/thirdparty/glog/CMakeLists.txt b/thirdparty/glog/CMakeLists.txt index 611f18efc..9f2f03e24 100644 --- a/thirdparty/glog/CMakeLists.txt +++ b/thirdparty/glog/CMakeLists.txt @@ -1,7 +1,12 @@ set(BUILD_TESTING OFF CACHE BOOL "Disable Unit Tests" FORCE) set(WITH_GFLAGS OFF CACHE BOOL "Disable find_package(gflags) in glog" FORCE) set(WITH_UNWIND OFF CACHE BOOL "Disable find_package(unwind) in glog" FORCE) -set(HAVE_LIB_GFLAGS TRUE CACHE BOOL "") +set(HAVE_LIB_GFLAGS FALSE CACHE BOOL "" FORCE) +set(gflags_FOUND FALSE CACHE BOOL "" FORCE) + +# Disable glog install to avoid export conflicts +set(INSTALL_HEADERS OFF CACHE BOOL "Disable install" FORCE) +set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build static lib" FORCE) add_compile_options(-Wno-deprecated-declarations) @@ -9,6 +14,10 @@ set(GLOG_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/glog-0.5.0) if (ANDROID) set(GLOG_ANDROID_PATCH ${CMAKE_CURRENT_SOURCE_DIR}/glog.android.patch) apply_patch_once("glog_android_fix" "${GLOG_SRC_DIR}" "${GLOG_ANDROID_PATCH}") +elseif(IOS) + # iOS uses the same patch as non-Android platforms + set(GLOG_PATCH ${CMAKE_CURRENT_SOURCE_DIR}/glog.patch) + apply_patch_once("glog_fix" "${GLOG_SRC_DIR}" "${GLOG_PATCH}") else() set(GLOG_PATCH ${CMAKE_CURRENT_SOURCE_DIR}/glog.patch) apply_patch_once("glog_fix" "${GLOG_SRC_DIR}" "${GLOG_PATCH}") @@ -20,7 +29,8 @@ add_subdirectory(glog-0.5.0) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${_SAVED_CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) unset(_SAVED_CMAKE_ARCHIVE_OUTPUT_DIRECTORY) -add_dependencies(glog gflags) +# Only add dependency when gflags is being used +# add_dependencies(glog gflags) if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") target_compile_options(glog PRIVATE -Wno-sign-compare) diff --git a/thirdparty/lz4/CMakeLists.txt b/thirdparty/lz4/CMakeLists.txt index 7db62d4f5..8bb025f64 100644 --- a/thirdparty/lz4/CMakeLists.txt +++ b/thirdparty/lz4/CMakeLists.txt @@ -41,6 +41,42 @@ if(ANDROID) "CFLAGS=${_lz4_cflags}" ) +elseif(IOS) + # iOS cross-compilation + set(_ios_arch ${CMAKE_OSX_ARCHITECTURES}) + if(NOT _ios_arch) + set(_ios_arch "arm64") + endif() + + set(_ios_min_version ${CMAKE_OSX_DEPLOYMENT_TARGET}) + if(NOT _ios_min_version) + set(_ios_min_version "13.0") + endif() + + # Get iOS SDK path - detect from CMAKE_OSX_SYSROOT or IOS_PLATFORM + string(TOLOWER "${CMAKE_OSX_SYSROOT}" _sysroot_lower) + if(IOS_PLATFORM STREQUAL "OS" OR _sysroot_lower MATCHES "iphoneos") + set(_ios_sdk "iphoneos") + set(_ios_target_flag "-miphoneos-version-min=${_ios_min_version}") + else() + set(_ios_sdk "iphonesimulator") + set(_ios_target_flag "-mios-simulator-version-min=${_ios_min_version}") + endif() + + execute_process( + COMMAND xcrun --sdk ${_ios_sdk} --show-sdk-path + OUTPUT_VARIABLE _ios_sysroot + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + set(_lz4_cflags "-arch ${_ios_arch} -isysroot ${_ios_sysroot} ${_ios_target_flag} -fPIC") + + list(APPEND _lz4_env + "CC=${CMAKE_C_COMPILER}" + "AR=${CMAKE_AR}" + "RANLIB=${CMAKE_RANLIB}" + "CFLAGS=${_lz4_cflags}" + ) else() list(APPEND _lz4_env "CFLAGS=-fPIC") endif() @@ -74,3 +110,5 @@ set(lz4_LIBRARIES ${lz4_LIBRARY_DIR}/liblz4.a PARENT_SCOPE) set(lz4_INCLUDE_DIR "${EXTERNAL_BINARY_DIR}/usr/local/include" PARENT_SCOPE) set(lz4_INCLUDE_DIRS "${EXTERNAL_BINARY_DIR}/usr/local/include" PARENT_SCOPE) set(lz4_VERSION 1.9.4 PARENT_SCOPE) +set(lz4_VERSION 1.9.4 PARENT_SCOPE) +set(lz4_VERSION 1.9.4 PARENT_SCOPE) diff --git a/thirdparty/rocksdb/CMakeLists.txt b/thirdparty/rocksdb/CMakeLists.txt index 9d756bba8..fbc5f6857 100644 --- a/thirdparty/rocksdb/CMakeLists.txt +++ b/thirdparty/rocksdb/CMakeLists.txt @@ -2,6 +2,22 @@ set(ROCKSDB_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/rocksdb-8.1.1) if (ANDROID) set(ROCKSDB_ANDROID_PATCH ${CMAKE_CURRENT_SOURCE_DIR}/rocksdb.android.patch) apply_patch_once("rocksdb_android_fix" "${ROCKSDB_SRC_DIR}" "${ROCKSDB_ANDROID_PATCH}") +elseif(IOS) + # iOS-specific patch for endianness detection + set(ROCKSDB_IOS_PATCH ${CMAKE_CURRENT_SOURCE_DIR}/rocksdb.ios.patch) + apply_patch_once("rocksdb_ios_fix" "${ROCKSDB_SRC_DIR}" "${ROCKSDB_IOS_PATCH}") + # iOS-specific options + set(WITH_JNI OFF CACHE BOOL "Disable JNI for iOS" FORCE) + set(WITH_GFLAGS OFF CACHE BOOL "Disable gflags for iOS" FORCE) + # Define OS_MACOSX for iOS to disable O_DIRECT and enable Apple-specific code paths + add_definitions(-DOS_MACOSX) + # Apple Clang for arm64 always supports CRC32 intrinsics (__ARM_FEATURE_CRC32 is + # always defined), but may reject the GCC-style -march=armv8-a+crc+crypto flag + # (especially for the simulator target). Pre-set the cache variable so RocksDB's + # CHECK_C_COMPILER_FLAG is skipped and crc32c_arm64.cc is included in the build. + if(CMAKE_OSX_ARCHITECTURES MATCHES "arm64") + set(HAS_ARMV8_CRC ON CACHE INTERNAL "Force ARM CRC for iOS arm64") + endif() endif() set(ROCKSDB_BUILD_SHARED OFF CACHE BOOL "Disable install in rocksdb" FORCE) diff --git a/thirdparty/rocksdb/rocksdb.ios.patch b/thirdparty/rocksdb/rocksdb.ios.patch new file mode 100644 index 000000000..f0671f7db --- /dev/null +++ b/thirdparty/rocksdb/rocksdb.ios.patch @@ -0,0 +1,29 @@ +diff --git a/port/port_posix.h b/port/port_posix.h +index 1234567..abcdefg 100644 +--- a/port/port_posix.h ++++ b/port/port_posix.h +@@ -58,6 +58,15 @@ + #include + #include + ++// iOS/macOS endianness detection ++#if defined(__APPLE__) ++#include ++#if !defined(__BYTE_ORDER) && defined(BYTE_ORDER) ++#define __BYTE_ORDER BYTE_ORDER ++#define __LITTLE_ENDIAN LITTLE_ENDIAN ++#endif ++#endif ++ + #ifndef PLATFORM_IS_LITTLE_ENDIAN + #define PLATFORM_IS_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN) + #endif +@@ -65,7 +74,7 @@ + + #if defined(OS_MACOSX) || defined(OS_SOLARIS) || defined(OS_FREEBSD) || \ + defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) || \ +- defined(OS_ANDROID) || defined(CYGWIN) || defined(OS_AIX) ++ defined(OS_ANDROID) || defined(CYGWIN) || defined(OS_AIX) || (defined(__APPLE__) && !defined(OS_MACOSX)) + // Use fread/fwrite/fflush on platforms without _unlocked variants + #define fread_unlocked fread + #define fwrite_unlocked fwrite From e2a28f788e1e4cc984f9fb3110c0c9f27c286ef5 Mon Sep 17 00:00:00 2001 From: "xufeihong.xfh" Date: Tue, 7 Apr 2026 14:05:03 +0800 Subject: [PATCH 2/9] fix: ci --- .github/workflows/05-ios-build.yml | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/.github/workflows/05-ios-build.yml b/.github/workflows/05-ios-build.yml index e22e0c407..698d32a46 100644 --- a/.github/workflows/05-ios-build.yml +++ b/.github/workflows/05-ios-build.yml @@ -2,6 +2,7 @@ name: iOS Cross Build on: workflow_call: + workflow_dispatch: permissions: contents: read @@ -78,9 +79,7 @@ jobs: if: matrix.test_on_simulator run: | NPROC=$(sysctl -n hw.ncpu) - cmake --build build_ios_${{ matrix.platform }} --target arrow_ipc_writer_test --parallel $NPROC cmake --build build_ios_${{ matrix.platform }} --target collection_test --parallel $NPROC - cmake --build build_ios_${{ matrix.platform }} --target data_generator --parallel $NPROC - name: Boot iOS Simulator if: matrix.test_on_simulator @@ -101,24 +100,7 @@ jobs: xcrun simctl boot "$DEVICE_ID" echo "Booted simulator: $DEVICE_ID" - - name: Run data_generator (smoke test) - if: matrix.test_on_simulator - run: | - xcrun simctl install "$DEVICE_ID" build_ios_${{ matrix.platform }}/bin/data_generator.app - xcrun simctl launch --console "$DEVICE_ID" com.zvec.data_generator || true - - - name: Run arrow_ipc_writer_test - if: matrix.test_on_simulator - run: | - xcrun simctl install "$DEVICE_ID" build_ios_${{ matrix.platform }}/bin/arrow_ipc_writer_test.app - xcrun simctl launch --console "$DEVICE_ID" com.zvec.arrow_ipc_writer_test 2>&1 | tee /tmp/arrow_ipc_writer_test.log - if grep -q '\[ FAILED \]' /tmp/arrow_ipc_writer_test.log; then - echo "::error::arrow_ipc_writer_test has failing tests" - exit 1 - fi - grep -q '\[ PASSED \]' /tmp/arrow_ipc_writer_test.log - - - name: Run collection_test (all cases) + - name: Run collection_test if: matrix.test_on_simulator run: | xcrun simctl install "$DEVICE_ID" build_ios_${{ matrix.platform }}/bin/collection_test.app From 24e92bdde4bd71d6f85c0580a204827de22b9921 Mon Sep 17 00:00:00 2001 From: "xufeihong.xfh" Date: Tue, 7 Apr 2026 15:18:38 +0800 Subject: [PATCH 3/9] fix: update build_ios.sh --- scripts/build_ios.sh | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/scripts/build_ios.sh b/scripts/build_ios.sh index 731c0b8a5..ccad68fac 100755 --- a/scripts/build_ios.sh +++ b/scripts/build_ios.sh @@ -11,15 +11,12 @@ IOS_DEPLOYMENT_TARGET="13.0" case "$PLATFORM" in "OS") ARCH="arm64" - CMAKE_SYSTEM_NAME="iOS" ;; "SIMULATOR64") ARCH="x86_64" - CMAKE_SYSTEM_NAME="iOS" ;; "SIMULATORARM64") ARCH="arm64" - CMAKE_SYSTEM_NAME="iOS" ;; *) echo "error: Unknown platform '$PLATFORM'" @@ -39,6 +36,9 @@ 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 @@ -63,10 +63,8 @@ cd $BUILD_DIR # Determine SDK and additional flags based on platform if [ "$PLATFORM" = "OS" ]; then SDK_NAME="iphoneos" - ENABLE_BITCODE="ON" else SDK_NAME="iphonesimulator" - ENABLE_BITCODE="OFF" fi SDK_PATH=$(xcrun --sdk $SDK_NAME --show-sdk-path) @@ -82,7 +80,6 @@ cmake \ -DBUILD_TOOLS=OFF \ -DCMAKE_INSTALL_PREFIX="./install" \ -DGLOBAL_CC_PROTOBUF_PROTOC=$PROTOC_EXECUTABLE \ - -DENABLE_BITCODE="$ENABLE_BITCODE" \ -DIOS=ON \ ../ @@ -94,3 +91,8 @@ 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 \ No newline at end of file From 3fe7c7d8478d71d600f6fdb4e3735c9faf3366c3 Mon Sep 17 00:00:00 2001 From: "xufeihong.xfh" Date: Tue, 7 Apr 2026 16:40:15 +0800 Subject: [PATCH 4/9] fix: pr --- .github/workflows/01-ci-pipeline.yml | 2 +- .gitignore | 3 ++- cmake/option.cmake | 3 +-- scripts/build_ios.sh | 2 +- src/db/CMakeLists.txt | 3 +-- src/db/common/CMakeLists.txt | 3 +-- thirdparty/glog/CMakeLists.txt | 14 ++------------ thirdparty/lz4/CMakeLists.txt | 2 -- 8 files changed, 9 insertions(+), 23 deletions(-) diff --git a/.github/workflows/01-ci-pipeline.yml b/.github/workflows/01-ci-pipeline.yml index b02096897..c2296f501 100644 --- a/.github/workflows/01-ci-pipeline.yml +++ b/.github/workflows/01-ci-pipeline.yml @@ -88,7 +88,7 @@ jobs: name: Build & Test (android) needs: lint uses: ./.github/workflows/04-android-build.yml - + build-and-test-on-windows: name: Build & Test (Windows) needs: lint diff --git a/.gitignore b/.gitignore index bac88b13d..e56a7660c 100644 --- a/.gitignore +++ b/.gitignore @@ -49,4 +49,5 @@ yarn-error.log* allure-* !build_android.sh -!build_ios.sh \ No newline at end of file +!build_ios.sh + diff --git a/cmake/option.cmake b/cmake/option.cmake index c59a33796..ee97b570a 100644 --- a/cmake/option.cmake +++ b/cmake/option.cmake @@ -188,9 +188,8 @@ function(setup_compiler_march_for_x86 VAR_NAME_SSE VAR_NAME_AVX2 VAR_NAME_AVX512 endforeach() endfunction() -# iOS: Skip -march flags, architecture is controlled by CMAKE_OSX_ARCHITECTURES +# iOS: Skip -march flags and OpenMP; architecture is controlled by CMAKE_OSX_ARCHITECTURES if(IOS OR CMAKE_SYSTEM_NAME STREQUAL "iOS") - message(STATUS "iOS build detected, skipping -march flags (controlled by CMAKE_OSX_ARCHITECTURES)") return() endif() diff --git a/scripts/build_ios.sh b/scripts/build_ios.sh index ccad68fac..fa8bc681d 100755 --- a/scripts/build_ios.sh +++ b/scripts/build_ios.sh @@ -95,4 +95,4 @@ 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 \ No newline at end of file +# 3: xcrun simctl launch --console booted com.zvec.collection_test diff --git a/src/db/CMakeLists.txt b/src/db/CMakeLists.txt index 307770b15..b2689278a 100644 --- a/src/db/CMakeLists.txt +++ b/src/db/CMakeLists.txt @@ -16,13 +16,12 @@ file(GLOB_RECURSE ALL_DB_SRCS *.cc *.c *.h) cc_library( NAME zvec_db STATIC STRICT SRCS_NO_GLOB PACKED SRCS ${ALL_DB_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/proto/zvec.pb.cc - INCS . ${CMAKE_CURRENT_BINARY_DIR} ${gflags_INCLUDE_DIR} + INCS . ${CMAKE_CURRENT_BINARY_DIR} PUBINCS ${PROJECT_ROOT_DIR}/src/include LIBS zvec_ailego zvec_core glog - gflags roaring rocksdb antlr4 diff --git a/src/db/common/CMakeLists.txt b/src/db/common/CMakeLists.txt index d13884a1c..cc2110aa3 100644 --- a/src/db/common/CMakeLists.txt +++ b/src/db/common/CMakeLists.txt @@ -6,10 +6,9 @@ cc_library( NAME zvec_common STATIC STRICT ALWAYS_LINK SRCS *.cc LIBS glog - gflags zvec_ailego roaring rocksdb - INCS . ${gflags_INCLUDE_DIR} + INCS . VERSION "${PROXIMA_ZVEC_VERSION}" ) diff --git a/thirdparty/glog/CMakeLists.txt b/thirdparty/glog/CMakeLists.txt index 80a1120c1..38083bfa7 100644 --- a/thirdparty/glog/CMakeLists.txt +++ b/thirdparty/glog/CMakeLists.txt @@ -1,12 +1,7 @@ set(BUILD_TESTING OFF CACHE BOOL "Disable Unit Tests" FORCE) set(WITH_GFLAGS OFF CACHE BOOL "Disable find_package(gflags) in glog" FORCE) set(WITH_UNWIND OFF CACHE BOOL "Disable find_package(unwind) in glog" FORCE) -set(HAVE_LIB_GFLAGS FALSE CACHE BOOL "" FORCE) -set(gflags_FOUND FALSE CACHE BOOL "" FORCE) - -# Disable glog install to avoid export conflicts -set(INSTALL_HEADERS OFF CACHE BOOL "Disable install" FORCE) -set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build static lib" FORCE) +set(HAVE_LIB_GFLAGS TRUE CACHE BOOL "") if(NOT MSVC) add_compile_options(-Wno-deprecated-declarations) @@ -16,10 +11,6 @@ set(GLOG_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/glog-0.5.0) if (ANDROID) set(GLOG_ANDROID_PATCH ${CMAKE_CURRENT_SOURCE_DIR}/glog.android.patch) apply_patch_once("glog_android_fix" "${GLOG_SRC_DIR}" "${GLOG_ANDROID_PATCH}") -elseif(IOS) - # iOS uses the same patch as non-Android platforms - set(GLOG_PATCH ${CMAKE_CURRENT_SOURCE_DIR}/glog.patch) - apply_patch_once("glog_fix" "${GLOG_SRC_DIR}" "${GLOG_PATCH}") else() set(GLOG_PATCH ${CMAKE_CURRENT_SOURCE_DIR}/glog.patch) apply_patch_once("glog_fix" "${GLOG_SRC_DIR}" "${GLOG_PATCH}") @@ -31,8 +22,7 @@ add_subdirectory(glog-0.5.0) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${_SAVED_CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) unset(_SAVED_CMAKE_ARCHIVE_OUTPUT_DIRECTORY) -# Only add dependency when gflags is being used -# add_dependencies(glog gflags) +add_dependencies(glog gflags) if(MSVC) # Modern MSVC (1900+/VS2015+) provides snprintf in the CRT. diff --git a/thirdparty/lz4/CMakeLists.txt b/thirdparty/lz4/CMakeLists.txt index 4dc8b8927..5e73245f2 100644 --- a/thirdparty/lz4/CMakeLists.txt +++ b/thirdparty/lz4/CMakeLists.txt @@ -140,5 +140,3 @@ set(lz4_LIBRARIES ${lz4_LIBRARY_DIR}/${LZ4_LIB_NAME} PARENT_SCOPE) set(lz4_INCLUDE_DIR "${EXTERNAL_BINARY_DIR}/usr/local/include" PARENT_SCOPE) set(lz4_INCLUDE_DIRS "${EXTERNAL_BINARY_DIR}/usr/local/include" PARENT_SCOPE) set(lz4_VERSION 1.9.4 PARENT_SCOPE) -set(lz4_VERSION 1.9.4 PARENT_SCOPE) -set(lz4_VERSION 1.9.4 PARENT_SCOPE) From 055ba7e005f03fbe5e90b20a469bbd8a7c890f9d Mon Sep 17 00:00:00 2001 From: "xufeihong.xfh" Date: Tue, 7 Apr 2026 23:06:34 +0800 Subject: [PATCH 5/9] fix: cmake minimum version --- cmake/bazel.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/bazel.cmake b/cmake/bazel.cmake index 30ee0cef3..34efc7d88 100644 --- a/cmake/bazel.cmake +++ b/cmake/bazel.cmake @@ -301,7 +301,7 @@ ## ) ## -cmake_minimum_required(VERSION 3.1 FATAL_ERROR) +cmake_minimum_required(VERSION 3.13 FATAL_ERROR) include(CMakeParseArguments) # Using AppleClang instead of Clang (Compiler id) @@ -2159,7 +2159,7 @@ function(_fetch_content) set( CMAKELISTS_CONTENT - "cmake_minimum_required(VERSION 3.1)\n" + "cmake_minimum_required(VERSION 3.13)\n" "project(${DL_ARGS_NAME})\n" "include(ExternalProject)\n" "ExternalProject_Add(\n" From 11f7b22866d64825686943a95bd3f8109640b5e9 Mon Sep 17 00:00:00 2001 From: "xufeihong.xfh" Date: Tue, 7 Apr 2026 23:12:28 +0800 Subject: [PATCH 6/9] fix: cmake minimum version --- thirdparty/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index 1c552fa0b..22f06ceae 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1 FATAL_ERROR) +cmake_minimum_required(VERSION 3.13 FATAL_ERROR) cmake_policy(SET CMP0048 NEW) project(thirdparty) From 36684957fb4bc8d648c36c998368cbece6771f27 Mon Sep 17 00:00:00 2001 From: "xufeihong.xfh" Date: Tue, 7 Apr 2026 23:18:47 +0800 Subject: [PATCH 7/9] fix: cmake minimum version in ci --- .github/workflows/06-ios-build.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/06-ios-build.yml b/.github/workflows/06-ios-build.yml index 698d32a46..732bc19c4 100644 --- a/.github/workflows/06-ios-build.yml +++ b/.github/workflows/06-ios-build.yml @@ -42,7 +42,7 @@ jobs: - name: Build host protoc run: | if [ ! -f "build_host/bin/protoc" ]; then - cmake -S . -B build_host -DCMAKE_BUILD_TYPE=Release + cmake -S . -B build_host -DCMAKE_BUILD_TYPE=Release -DCMAKE_POLICY_VERSION_MINIMUM=3.5 cmake --build build_host --target protoc --parallel $(sysctl -n hw.ncpu) else echo "Using cached host protoc" @@ -71,7 +71,8 @@ jobs: -DBUILD_TOOLS=OFF \ -DCMAKE_INSTALL_PREFIX="./install" \ -DGLOBAL_CC_PROTOBUF_PROTOC="$GITHUB_WORKSPACE/build_host/bin/protoc" \ - -DIOS=ON + -DIOS=ON \ + -DCMAKE_POLICY_VERSION_MINIMUM=3.5 cmake --build build_ios_${{ matrix.platform }} --parallel $NPROC From 9b980c9a4ef4b13a2d8f8531a2ddcfe91df22ca3 Mon Sep 17 00:00:00 2001 From: "xufeihong.xfh" Date: Wed, 8 Apr 2026 10:54:07 +0800 Subject: [PATCH 8/9] fix: add all test in ci --- .github/workflows/06-ios-build.yml | 42 +++++++++--- cmake/bazel.cmake | 28 ++++++-- scripts/build_ios.sh | 67 +++++++++++++++++++ tests/c/CMakeLists.txt | 14 ++++ tests/c/c_api_test.c | 21 +++--- tests/c/utils.c | 34 ++++++++-- .../flat/flat_streamer_buffer_time_test.cc | 9 +-- .../hnsw_rabitq/hnsw_rabitq_streamer_test.cc | 6 +- tests/core/interface/index_interface_test.cc | 7 +- tests/test_util.h | 15 +++++ 10 files changed, 202 insertions(+), 41 deletions(-) diff --git a/.github/workflows/06-ios-build.yml b/.github/workflows/06-ios-build.yml index 732bc19c4..2b852fd8b 100644 --- a/.github/workflows/06-ios-build.yml +++ b/.github/workflows/06-ios-build.yml @@ -80,7 +80,7 @@ jobs: if: matrix.test_on_simulator run: | NPROC=$(sysctl -n hw.ncpu) - cmake --build build_ios_${{ matrix.platform }} --target collection_test --parallel $NPROC + cmake --build build_ios_${{ matrix.platform }} --target unittest --parallel $NPROC - name: Boot iOS Simulator if: matrix.test_on_simulator @@ -101,17 +101,43 @@ jobs: xcrun simctl boot "$DEVICE_ID" echo "Booted simulator: $DEVICE_ID" - - name: Run collection_test + - name: Run all tests on simulator 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 + FAILED_TESTS="" + PASSED=0 + TOTAL=0 + + for APP in build_ios_${{ matrix.platform }}/bin/*_test.app; do + [ -d "$APP" ] || continue + TEST_NAME=$(basename "$APP" .app) + BUNDLE_ID="com.zvec.${TEST_NAME}" + TOTAL=$((TOTAL + 1)) + + echo "::group::Running ${TEST_NAME}" + xcrun simctl install "$DEVICE_ID" "$APP" + xcrun simctl launch --console "$DEVICE_ID" "$BUNDLE_ID" 2>&1 | tee /tmp/${TEST_NAME}.log + + if grep -q '\[ FAILED \]' /tmp/${TEST_NAME}.log; then + echo "::error::${TEST_NAME} has failing tests" + FAILED_TESTS="${FAILED_TESTS} ${TEST_NAME}" + elif grep -q '\[ PASSED \]' /tmp/${TEST_NAME}.log; then + PASSED=$((PASSED + 1)) + elif grep -qE 'Failed: 0$' /tmp/${TEST_NAME}.log; then + # c_api_test uses a custom test framework (not GTest) + PASSED=$((PASSED + 1)) + else + echo "::warning::${TEST_NAME} produced no recognisable test summary" + FAILED_TESTS="${FAILED_TESTS} ${TEST_NAME}" + fi + echo "::endgroup::" + done + + echo "Test summary: ${PASSED}/${TOTAL} passed" + if [ -n "$FAILED_TESTS" ]; then + echo "::error::Failed tests:${FAILED_TESTS}" exit 1 fi - grep -q '\[ PASSED \]' /tmp/collection_test.log - name: Shutdown Simulator if: matrix.test_on_simulator && always() diff --git a/cmake/bazel.cmake b/cmake/bazel.cmake index 34efc7d88..829948229 100644 --- a/cmake/bazel.cmake +++ b/cmake/bazel.cmake @@ -314,11 +314,16 @@ enable_testing() # Add unittest target if(NOT TARGET unittest) - add_custom_target( - unittest - COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure - --build-config $ - ) + if(IOS) + # iOS: build-only target; tests are run on simulator separately + add_custom_target(unittest) + else() + add_custom_target( + unittest + COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure + --build-config $ + ) + endif() endif() # Directories of target output @@ -1068,6 +1073,19 @@ function(cc_test) # 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") + # Arrow's iOS code references CoreFoundation symbols; link Apple frameworks + list(APPEND CC_ARGS_LDFLAGS + -framework CoreFoundation + -framework CoreGraphics + -framework CoreData + -framework CoreText + -framework Security + -framework Foundation + -Wl,-U,_MallocExtension_ReleaseFreeMemory + -Wl,-U,_ProfilerStart + -Wl,-U,_ProfilerStop + -Wl,-U,_RegisterThriftProtocol + ) endif() add_executable(${CC_ARGS_NAME} EXCLUDE_FROM_ALL ${CC_ARGS_SRCS}) diff --git a/scripts/build_ios.sh b/scripts/build_ios.sh index fa8bc681d..1c40ae2cc 100755 --- a/scripts/build_ios.sh +++ b/scripts/build_ios.sh @@ -88,6 +88,73 @@ CORE_COUNT=$(sysctl -n hw.ncpu) make -j$CORE_COUNT echo "step2: Done!!!" + +# step3: build and run all unit tests on simulator +if [ "$PLATFORM" != "OS" ]; then + echo "step3: building and running unit tests on simulator..." + + make -j$CORE_COUNT unittest + + # Boot simulator + 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) +") + xcrun simctl boot "$DEVICE_ID" + echo "Booted simulator: $DEVICE_ID" + + # Run all test .app bundles + FAILED_TESTS="" + PASSED=0 + TOTAL=0 + + for APP in bin/*_test.app; do + [ -d "$APP" ] || continue + TEST_NAME=$(basename "$APP" .app) + BUNDLE_ID="com.zvec.${TEST_NAME}" + TOTAL=$((TOTAL + 1)) + + echo "--- Running ${TEST_NAME} ---" + xcrun simctl install "$DEVICE_ID" "$APP" + xcrun simctl launch --console "$DEVICE_ID" "$BUNDLE_ID" 2>&1 | tee /tmp/${TEST_NAME}.log + + if grep -q '\[ FAILED \]' /tmp/${TEST_NAME}.log; then + echo "FAIL: ${TEST_NAME}" + FAILED_TESTS="${FAILED_TESTS} ${TEST_NAME}" + elif grep -q '\[ PASSED \]' /tmp/${TEST_NAME}.log; then + PASSED=$((PASSED + 1)) + elif grep -qE 'Failed: 0$' /tmp/${TEST_NAME}.log; then + # c_api_test uses a custom test framework (not GTest) + PASSED=$((PASSED + 1)) + else + echo "WARN: ${TEST_NAME} produced no recognisable test summary" + FAILED_TESTS="${FAILED_TESTS} ${TEST_NAME}" + fi + done + + # Shutdown simulator + xcrun simctl shutdown "$DEVICE_ID" || true + + echo "" + echo "Test summary: ${PASSED}/${TOTAL} passed" + if [ -n "$FAILED_TESTS" ]; then + echo "Failed tests:${FAILED_TESTS}" + exit 1 + fi + + echo "step3: Done!!!" +else + echo "Skipping tests (device build cannot run on simulator)" +fi + echo "" echo "Build completed successfully!" echo "Output directory: $CURRENT_DIR/$BUILD_DIR" diff --git a/tests/c/CMakeLists.txt b/tests/c/CMakeLists.txt index b5e461a24..9f40ef9ca 100644 --- a/tests/c/CMakeLists.txt +++ b/tests/c/CMakeLists.txt @@ -25,4 +25,18 @@ foreach(CC_SRCS ${ALL_TEST_SRCS}) SRCS ${CC_SRCS} utils.c INCS . .. ../../src ) + + # iOS: embed the shared library inside the .app bundle so the simulator can + # find it at runtime, and patch the executable's rpath accordingly. + if(IOS AND TARGET ${CC_TARGET}) + add_custom_command(TARGET ${CC_TARGET} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory + "$/Frameworks" + COMMAND ${CMAKE_COMMAND} -E copy + "$" + "$/Frameworks/" + COMMAND install_name_tool -add_rpath "@executable_path/Frameworks" + "$/${CC_TARGET}" 2>/dev/null || true + ) + endif() endforeach() diff --git a/tests/c/c_api_test.c b/tests/c/c_api_test.c index ec13227d2..50559594b 100644 --- a/tests/c/c_api_test.c +++ b/tests/c/c_api_test.c @@ -25,6 +25,7 @@ #include #else #include +#include #include #endif @@ -53,15 +54,7 @@ static size_t get_field_count(zvec_collection_schema_t *schema) { // Cross-platform helper function to clean up temporary directories static void cleanup_temp_directory(const char *dir) { -#ifdef _WIN32 - char cmd[512]; - snprintf(cmd, sizeof(cmd), "rmdir /s /q \"%s\" 2>nul", dir); - system(cmd); -#else - char cmd[512]; - snprintf(cmd, sizeof(cmd), "rm -rf %s", dir); - system(cmd); -#endif + zvec_test_delete_dir(dir); } static int test_count = 0; @@ -5357,7 +5350,15 @@ int main(void) { system("rmdir /s /q %TEMP%\\zvec_test_* 2>nul"); system("del /q %TEMP%\\zvec_test_* 2>nul"); #else - system("rm -rf /tmp/zvec_test_*"); + { + glob_t gl; + if (glob("/tmp/zvec_test_*", 0, NULL, &gl) == 0) { + for (size_t gi = 0; gi < gl.gl_pathc; gi++) { + zvec_test_delete_dir(gl.gl_pathv[gi]); + } + globfree(&gl); + } + } #endif printf("Cleanup completed.\n\n"); diff --git a/tests/c/utils.c b/tests/c/utils.c index 6d45febcb..61c118849 100644 --- a/tests/c/utils.c +++ b/tests/c/utils.c @@ -18,6 +18,12 @@ #include #include +#ifndef _WIN32 +#include +#include +#include +#endif + // ============================================================================= // Internal Helper Functions // ============================================================================= @@ -960,10 +966,28 @@ int zvec_test_delete_dir(const char *dir_path) { int result = system(cmd); return (result == 0) ? 0 : -1; #else - // Unix/Linux/macOS platform implementation - char cmd[1024]; - snprintf(cmd, sizeof(cmd), "rm -rf \"%s\" 2>/dev/null", dir_path); - int result = system(cmd); - return (result == 0) ? 0 : -1; + // Unix/Linux/macOS/iOS: pure C recursive removal (no system() call) + struct stat st; + if (stat(dir_path, &st) != 0) { + return -1; // path does not exist + } + if (!S_ISDIR(st.st_mode)) { + return unlink(dir_path); // regular file + } + DIR *dir = opendir(dir_path); + if (!dir) { + return -1; + } + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { + continue; + } + char child[1024]; + snprintf(child, sizeof(child), "%s/%s", dir_path, entry->d_name); + zvec_test_delete_dir(child); // recurse + } + closedir(dir); + return rmdir(dir_path); #endif } diff --git a/tests/core/algorithm/flat/flat_streamer_buffer_time_test.cc b/tests/core/algorithm/flat/flat_streamer_buffer_time_test.cc index 37d28ecd6..a76d5c573 100644 --- a/tests/core/algorithm/flat/flat_streamer_buffer_time_test.cc +++ b/tests/core/algorithm/flat/flat_streamer_buffer_time_test.cc @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -38,15 +39,11 @@ void FlatStreamerTest::SetUp(void) { IndexMeta(IndexMeta::DataType::DT_FP32, dim)); index_meta_ptr_->set_metric("SquaredEuclidean", 0, Params()); - char cmdBuf[100]; - snprintf(cmdBuf, 100, "rm -rf %s", dir_.c_str()); - system(cmdBuf); + zvec::ailego::FileHelper::RemovePath(dir_.c_str()); } void FlatStreamerTest::TearDown(void) { - char cmdBuf[100]; - snprintf(cmdBuf, 100, "rm -rf %s", dir_.c_str()); - system(cmdBuf); + zvec::ailego::FileHelper::RemovePath(dir_.c_str()); } TEST_F(FlatStreamerTest, TestLinearSearchMMap) { diff --git a/tests/core/algorithm/hnsw_rabitq/hnsw_rabitq_streamer_test.cc b/tests/core/algorithm/hnsw_rabitq/hnsw_rabitq_streamer_test.cc index 9bb69fca7..87c8ca204 100644 --- a/tests/core/algorithm/hnsw_rabitq/hnsw_rabitq_streamer_test.cc +++ b/tests/core/algorithm/hnsw_rabitq/hnsw_rabitq_streamer_test.cc @@ -14,8 +14,10 @@ #include "hnsw_rabitq_streamer.h" #include +#include #include #include "zvec/ailego/container/params.h" +#include "zvec/ailego/utility/file_helper.h" #include "zvec/core/framework/index_holder.h" #include "zvec/core/framework/index_streamer.h" #include "hnsw_rabitq_streamer.h" @@ -49,9 +51,7 @@ void HnswRabitqStreamerTest::SetUp(void) { } void HnswRabitqStreamerTest::TearDown(void) { - char cmdBuf[100]; - snprintf(cmdBuf, 100, "rm -rf %s", dir_.c_str()); - system(cmdBuf); + ailego::FileHelper::RemovePath(dir_.c_str()); } TEST_F(HnswRabitqStreamerTest, TestBuildAndSearch) { diff --git a/tests/core/interface/index_interface_test.cc b/tests/core/interface/index_interface_test.cc index bba80121f..4d1aefd0b 100644 --- a/tests/core/interface/index_interface_test.cc +++ b/tests/core/interface/index_interface_test.cc @@ -1348,12 +1348,11 @@ TEST(IndexInterface, Score) { TEST(IndexInterface, HNSWRabitqGeneral) { constexpr uint32_t kDimension = 64; const std::string index_name{"test_rabitq.index"}; - char cmd_buf[256]; - snprintf(cmd_buf, sizeof(cmd_buf), "rm -f %s*", index_name.c_str()); + const std::string cleanup_pattern = index_name + "*"; auto func = [&](const BaseIndexParam::Pointer ¶m, const BaseIndexQueryParam::Pointer &query_param) { - system(cmd_buf); + zvec::test_util::RemoveTestFiles(cleanup_pattern); auto index = IndexFactory::CreateAndInitIndex(*param); ASSERT_NE(nullptr, index); @@ -1376,7 +1375,7 @@ TEST(IndexInterface, HNSWRabitqGeneral) { // Fetch is meaningless for HNSWRabitq index->Close(); - system(cmd_buf); + zvec::test_util::RemoveTestFiles(cleanup_pattern); }; using namespace zvec::core; diff --git a/tests/test_util.h b/tests/test_util.h index 00fedd81b..e4ed8c09c 100644 --- a/tests/test_util.h +++ b/tests/test_util.h @@ -18,6 +18,13 @@ #include #include +#ifdef __APPLE__ +#include +#if TARGET_OS_IOS || TARGET_OS_SIMULATOR +#include +#endif +#endif + #ifdef _MSC_VER #include #include @@ -41,6 +48,14 @@ inline void RemoveTestFiles(const std::string &pattern) { pattern.find('?') != std::string::npos) { #ifdef _WIN32 system(("del /f /q " + pattern + " 2>NUL").c_str()); +#elif defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_SIMULATOR) + glob_t globbuf; + if (glob(pattern.c_str(), 0, nullptr, &globbuf) == 0) { + for (size_t i = 0; i < globbuf.gl_pathc; ++i) { + ailego::FileHelper::RemovePath(globbuf.gl_pathv[i]); + } + globfree(&globbuf); + } #else system(("rm -rf " + pattern).c_str()); #endif From 837010cc6c9015dfbe94a69d51eedeee471c1e00 Mon Sep 17 00:00:00 2001 From: "xufeihong.xfh" Date: Wed, 8 Apr 2026 13:09:54 +0800 Subject: [PATCH 9/9] fix: ci --- .github/workflows/06-ios-build.yml | 8 +++++++- scripts/build_ios.sh | 8 +++++++- tests/db/crash_recovery/CMakeLists.txt | 6 ++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/workflows/06-ios-build.yml b/.github/workflows/06-ios-build.yml index 2b852fd8b..4845d6203 100644 --- a/.github/workflows/06-ios-build.yml +++ b/.github/workflows/06-ios-build.yml @@ -116,7 +116,10 @@ jobs: echo "::group::Running ${TEST_NAME}" xcrun simctl install "$DEVICE_ID" "$APP" + set +eo pipefail xcrun simctl launch --console "$DEVICE_ID" "$BUNDLE_ID" 2>&1 | tee /tmp/${TEST_NAME}.log + LAUNCH_EXIT=${PIPESTATUS[0]} + set -eo pipefail if grep -q '\[ FAILED \]' /tmp/${TEST_NAME}.log; then echo "::error::${TEST_NAME} has failing tests" @@ -126,8 +129,11 @@ jobs: elif grep -qE 'Failed: 0$' /tmp/${TEST_NAME}.log; then # c_api_test uses a custom test framework (not GTest) PASSED=$((PASSED + 1)) + elif [ "$LAUNCH_EXIT" -eq 0 ]; then + echo "::warning::${TEST_NAME} exited 0 but produced no recognisable test summary" + PASSED=$((PASSED + 1)) else - echo "::warning::${TEST_NAME} produced no recognisable test summary" + echo "::error::${TEST_NAME} exited ${LAUNCH_EXIT} with no test summary" FAILED_TESTS="${FAILED_TESTS} ${TEST_NAME}" fi echo "::endgroup::" diff --git a/scripts/build_ios.sh b/scripts/build_ios.sh index 1c40ae2cc..4e3fb466a 100755 --- a/scripts/build_ios.sh +++ b/scripts/build_ios.sh @@ -124,7 +124,10 @@ sys.exit(1) echo "--- Running ${TEST_NAME} ---" xcrun simctl install "$DEVICE_ID" "$APP" + set +e xcrun simctl launch --console "$DEVICE_ID" "$BUNDLE_ID" 2>&1 | tee /tmp/${TEST_NAME}.log + LAUNCH_EXIT=${PIPESTATUS[0]} + set -e if grep -q '\[ FAILED \]' /tmp/${TEST_NAME}.log; then echo "FAIL: ${TEST_NAME}" @@ -134,8 +137,11 @@ sys.exit(1) elif grep -qE 'Failed: 0$' /tmp/${TEST_NAME}.log; then # c_api_test uses a custom test framework (not GTest) PASSED=$((PASSED + 1)) + elif [ "$LAUNCH_EXIT" -eq 0 ]; then + echo "WARN: ${TEST_NAME} exited 0 but produced no recognisable test summary" + PASSED=$((PASSED + 1)) else - echo "WARN: ${TEST_NAME} produced no recognisable test summary" + echo "FAIL: ${TEST_NAME} exited ${LAUNCH_EXIT} with no test summary" FAILED_TESTS="${FAILED_TESTS} ${TEST_NAME}" fi done diff --git a/tests/db/crash_recovery/CMakeLists.txt b/tests/db/crash_recovery/CMakeLists.txt index 12c2423a1..32b5f5610 100644 --- a/tests/db/crash_recovery/CMakeLists.txt +++ b/tests/db/crash_recovery/CMakeLists.txt @@ -1,6 +1,12 @@ include(${PROJECT_ROOT_DIR}/cmake/bazel.cmake) include(${PROJECT_ROOT_DIR}/cmake/option.cmake) +# Crash recovery tests rely on fork()+execvp()+kill() to spawn helper processes +# and simulate crashes. These POSIX process APIs are prohibited on iOS. +if(IOS) + return() +endif() + if(APPLE) set(APPLE_FRAMEWORK_LIBS -framework CoreFoundation