diff --git a/CMakeLists.txt b/CMakeLists.txt index b423d8b..e14859e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,11 @@ cmake_policy(SET CMP0077 NEW) if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin" AND (NOT DEFINED CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET STREQUAL "")) - set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0" CACHE STRING + set(ZVEC_MACOS_DEPLOYMENT_TARGET "$ENV{MACOSX_DEPLOYMENT_TARGET}") + if(NOT ZVEC_MACOS_DEPLOYMENT_TARGET) + set(ZVEC_MACOS_DEPLOYMENT_TARGET "11.0") + endif() + set(CMAKE_OSX_DEPLOYMENT_TARGET "${ZVEC_MACOS_DEPLOYMENT_TARGET}" CACHE STRING "Minimum macOS version" FORCE) endif() @@ -22,308 +26,17 @@ if(MSVC) endif() -# Parallelism for the external zvec build -set(ZVEC_BUILD_JOBS "" CACHE STRING "Parallel build jobs for external zvec project") -include(ProcessorCount) -if(NOT ZVEC_BUILD_JOBS) - ProcessorCount(ZVEC_BUILD_JOBS) - if(NOT ZVEC_BUILD_JOBS OR ZVEC_BUILD_JOBS EQUAL 0) - set(ZVEC_BUILD_JOBS 6) - endif() -endif() - - -# Path variables +# Build zvec and its dependencies. set(ZVEC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/zvec) -set(ZVEC_BINARY_DIR ${CMAKE_BINARY_DIR}/zvec-build) -set(ZVEC_DEPENDENCY_LIB_DIR ${ZVEC_BINARY_DIR}/external/usr/local/lib) - -get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) -if(is_multi_config) - set(ZVEC_LIB_DIR ${ZVEC_BINARY_DIR}/lib/Release) - set(ZVEC_DEPENDENCY_LIB_DIR_MULTI_CONFIG ${ZVEC_DEPENDENCY_LIB_DIR}/Release) -else() - set(ZVEC_LIB_DIR ${ZVEC_BINARY_DIR}/lib) -endif() - - -# External build byproducts -if(WIN32) - set(ZVEC_DB_LIB ${ZVEC_LIB_DIR}/zvec.lib) - set(ZVEC_BYPRODUCTS - ${ZVEC_LIB_DIR}/zvec_ailego.lib - ${ZVEC_LIB_DIR}/zvec_core.lib - ${ZVEC_LIB_DIR}/zvec_turbo.lib - ${ZVEC_DB_LIB} - ) -else() - set(ZVEC_DB_LIB ${ZVEC_LIB_DIR}/libzvec.a) - set(ZVEC_BYPRODUCTS - ${ZVEC_LIB_DIR}/libzvec_ailego.a - ${ZVEC_LIB_DIR}/libzvec_core.a - ${ZVEC_LIB_DIR}/libzvec_turbo.a - ${ZVEC_DB_LIB} - ) -endif() - -# ExternalProject does not preserve zvec's CMake target graph. Mirror its -# RaBitQ support checks and forward rabitq_fastscan -> rabitq_core explicitly. -set(ZVEC_RABITQ_SUPPORTED OFF) -set(ZVEC_RABITQ_LIBS) -if(NOT ANDROID AND NOT IOS AND CMAKE_SIZEOF_VOID_P EQUAL 8 - AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|AMD64)$" - AND (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR (WIN32 AND MSVC))) - if(MSVC) - set(ZVEC_RABITQ_AVX2_FLAGS "/arch:AVX2") - set(ZVEC_RABITQ_AVX512_FLAGS "/arch:AVX512") - set(ZVEC_RABITQ_AVX512_POPCNT_FLAGS "/arch:AVX512") - else() - set(ZVEC_RABITQ_AVX2_FLAGS "-mavx2 -mfma") - set(ZVEC_RABITQ_AVX512_FLAGS "-mavx512f -mavx512bw -mavx512dq -mfma") - set(ZVEC_RABITQ_AVX512_POPCNT_FLAGS - "-mavx512f -mavx512bw -mavx512dq -mavx512vpopcntdq -mfma") - endif() - - include(CheckCXXCompilerFlag) - set(ZVEC_RABITQ_SUPPORTED ON) - foreach(variant AVX2 AVX512 AVX512_POPCNT) - check_cxx_compiler_flag("${ZVEC_RABITQ_${variant}_FLAGS}" - ZVEC_COMPILER_SUPPORTS_RABITQ_${variant}) - if(NOT ZVEC_COMPILER_SUPPORTS_RABITQ_${variant}) - set(ZVEC_RABITQ_SUPPORTED OFF) - endif() - endforeach() -endif() -if(ZVEC_RABITQ_SUPPORTED) - foreach(component fastscan core) - list(APPEND ZVEC_RABITQ_LIBS - ${ZVEC_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}rabitq_${component}${CMAKE_STATIC_LIBRARY_SUFFIX}) - endforeach() - list(APPEND ZVEC_BYPRODUCTS ${ZVEC_RABITQ_LIBS}) -endif() - - -# External build of zvec -include(ExternalProject) -set(ZVEC_BUILD_TARGETS - --target zvec_ailego - --target zvec_core - --target zvec_turbo - --target zvec -) -set(ZVEC_CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release) -set(ZVEC_BUILD_ENV) -if(APPLE) - list(APPEND ZVEC_CMAKE_ARGS - "-DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=${CMAKE_OSX_DEPLOYMENT_TARGET}" - ) - set(ZVEC_BUILD_ENV ${CMAKE_COMMAND} -E env - "MACOSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}" - ) -endif() -if(MSVC) - list(APPEND ZVEC_CMAKE_ARGS - "-DBUILD_SHARED_LIBS=OFF" - "-DCMAKE_C_FLAGS=/MP" - "-DCMAKE_CXX_FLAGS=/MP" - "-DBUILD_TOOLS=OFF" - "-DCMAKE_POLICY_DEFAULT_CMP0091=NEW" - "-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded" - ) -endif() -ExternalProject_Add(zvec - SOURCE_DIR ${ZVEC_SOURCE_DIR} - BINARY_DIR ${ZVEC_BINARY_DIR} - INSTALL_COMMAND "" # Skip installation - CMAKE_ARGS ${ZVEC_CMAKE_ARGS} - BUILD_ALWAYS ON - USES_TERMINAL_BUILD TRUE - TEST_COMMAND "" - BUILD_BYPRODUCTS - ${ZVEC_BYPRODUCTS} - BUILD_COMMAND - ${ZVEC_BUILD_ENV} ${CMAKE_COMMAND} --build --config Release --parallel ${ZVEC_BUILD_JOBS} ${ZVEC_BUILD_TARGETS} -) - - -# Add include and library search paths -include_directories(${ZVEC_SOURCE_DIR}/src/include/) -link_directories(${ZVEC_LIB_DIR} ${ZVEC_DEPENDENCY_LIB_DIR} ${ZVEC_DEPENDENCY_LIB_DIR_MULTI_CONFIG}) - - -# --- Determine debug/release library names --- -if(CMAKE_BUILD_TYPE STREQUAL "Debug") - set(GLOG_LIB glogd) - set(GFLAGS_LIB gflags_nothreads_debug) -else() - set(GLOG_LIB glog) - if(WIN32) - set(GFLAGS_LIB gflags_nothreads_static) - else() - set(GFLAGS_LIB gflags_nothreads) - endif() -endif() - -# --- Dependency groups --- -find_package(Threads REQUIRED) - -set(zvec_core_deps - ${ZVEC_RABITQ_LIBS} -) - -if (NOT WIN32) - set(zvec_ailego_deps - arrow - parquet - arrow_bundled_dependencies - ${CMAKE_THREAD_LIBS_INIT} - ${CMAKE_DL_LIBS} - ) - set(zvec_db_deps - roaring - rocksdb - arrow - arrow_acero - arrow_bundled_dependencies - arrow_compute - parquet - antlr4-runtime - ${GLOG_LIB} - ${GFLAGS_LIB} - FastPFOR - lz4 - snowball - utf8proc - ) -else () - set(zvec_ailego_deps - arrow_static - parquet_static - arrow_bundled_dependencies - ${CMAKE_THREAD_LIBS_INIT} - ${CMAKE_DL_LIBS} - ) - set(zvec_db_deps - roaring - rocksdb - arrow_static - arrow_acero_static - arrow_bundled_dependencies - arrow_compute_static - parquet_static - antlr4-runtime-static - ${GLOG_LIB} - ${GFLAGS_LIB} - FastPFOR - lz4 - snowball - utf8proc_static - rpcrt4 - shlwapi - ) -endif () - - -# --- Create INTERFACE targets for Zvec components --- - -# zvec_ailego: links libzvec_ailego.a + its deps -add_library(zvec-ailego INTERFACE) -if(WIN32) - target_link_libraries(zvec-ailego INTERFACE - zvec_ailego - ${zvec_ailego_deps} - ) -else() - target_link_libraries(zvec-ailego INTERFACE - -lzvec_ailego - ${zvec_ailego_deps} - ) -endif() - -# Core and Turbo register factories through static initializers. Keep all their -# objects so algorithms and quantizers requested by name remain available. -add_library(zvec-core INTERFACE) -if(CMAKE_SYSTEM_NAME STREQUAL "Linux") - target_link_libraries(zvec-core INTERFACE - -Wl,--whole-archive - zvec_core - zvec_turbo - -Wl,--no-whole-archive - -Wl,--start-group - zvec-ailego - ${zvec_core_deps} - -Wl,--end-group - ) -elseif(APPLE) - target_link_libraries(zvec-core INTERFACE - "-Wl,-force_load,${ZVEC_LIB_DIR}/libzvec_core.a" - "-Wl,-force_load,${ZVEC_LIB_DIR}/libzvec_turbo.a" - zvec-ailego - ${zvec_core_deps} - ) -elseif(ANDROID) - target_link_libraries(zvec-core INTERFACE - -Wl,--whole-archive - zvec_core - zvec_turbo - -Wl,--no-whole-archive - -Wl,--start-group - zvec-ailego - ${zvec_core_deps} - -Wl,--end-group - ) -elseif(WIN32) - target_link_libraries(zvec-core INTERFACE - zvec_core - zvec_turbo - zvec-ailego - ${zvec_core_deps} - ) - target_link_options(zvec-core INTERFACE - "/WHOLEARCHIVE:zvec_core" - "/WHOLEARCHIVE:zvec_turbo" - ) -else() - message(FATAL_ERROR "Unsupported platform: ${CMAKE_SYSTEM_NAME}") -endif() - -# zvec-db: links the engine DB static library + all deps. -add_library(zvec-db INTERFACE) -if(CMAKE_SYSTEM_NAME STREQUAL "Linux") - target_link_libraries(zvec-db INTERFACE - ${ZVEC_DB_LIB} - zvec-core - zvec-ailego - -Wl,--start-group - ${zvec_db_deps} - -Wl,--end-group - ) -elseif(APPLE) - target_link_libraries(zvec-db INTERFACE - ${ZVEC_DB_LIB} - zvec-core - zvec-ailego - ${zvec_db_deps} - ) -elseif(ANDROID) - target_link_libraries(zvec-db INTERFACE - ${ZVEC_DB_LIB} - zvec-core - zvec-ailego - -Wl,--start-group - ${zvec_db_deps} - -Wl,--end-group - ) -elseif(WIN32) - target_link_libraries(zvec-db INTERFACE - ${ZVEC_DB_LIB} - zvec-core - zvec-ailego - ${zvec_db_deps} - ) -else() - message(FATAL_ERROR "Unsupported platform: ${CMAKE_SYSTEM_NAME}") -endif() +set(BUILD_SHARED_LIBS OFF) +set(BUILD_ZVEC_SHARED OFF) +set(BUILD_ZVEC_AILEGO_SHARED OFF) +set(BUILD_ZVEC_CORE_SHARED OFF) +set(BUILD_C_BINDINGS OFF) +set(BUILD_PYTHON_BINDINGS OFF) +set(BUILD_TOOLS OFF) +set(BUILD_CPP_EXAMPLES OFF) +add_subdirectory(${ZVEC_SOURCE_DIR} ${CMAKE_BINARY_DIR}/zvec-build EXCLUDE_FROM_ALL) # --- The main target library --- @@ -340,8 +53,6 @@ add_library(${PROJECT_NAME} SHARED src/binding/types.cc ) -add_dependencies(${PROJECT_NAME} zvec) - target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/node_modules/node-addon-api @@ -352,9 +63,13 @@ target_include_directories(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME} PRIVATE ${CMAKE_JS_LIB} - zvec-db + zvec ) +# Keep algorithm and quantizer factories registered by static initializers. +set_property(TARGET ${PROJECT_NAME} PROPERTY LINK_LIBRARY_OVERRIDE + "WHOLE_ARCHIVE,zvec_core,zvec_turbo") + if(MSVC) target_link_libraries(${PROJECT_NAME} PRIVATE delayimp) endif() diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a012476..a055234 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -69,14 +69,6 @@ After modifying the binding code, you should run the test suite to ensure your c npm run test:unit ``` -### Editor Configuration - -If you are using **clangd** for code intelligence, you may want to merge the compilation database. This is necessary because the project relies on external submodules, which results in separate **compile_commands.json** files. - -```bash -python ./scripts/merge_compile_commands.py -``` - ## Local Distribution If you prefer to build the binding from source and generate a single, self-contained package (including the pre-built binary for your current platform), use the local packing script. diff --git a/scripts/build.js b/scripts/build.js index 20990cf..f733f08 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -52,7 +52,11 @@ try { console.log(`\nCompiling native addon. Jobs: ${JOBS}, Build type: ${BUILD_TYPE}.`); console.log(`Running command: ${cmd}\n`); - execSync(cmd, { stdio: 'inherit', cwd: PACKAGE_ROOT }); + const buildEnv = { ...process.env }; + if (process.platform === 'darwin') { + buildEnv.MACOSX_DEPLOYMENT_TARGET ||= '11.0'; + } + execSync(cmd, { stdio: 'inherit', cwd: PACKAGE_ROOT, env: buildEnv }); const artifacts = verifyBuildArtifacts(PACKAGE_ROOT, BUILD_TYPE); console.log(`✅ Native addon compiled at: ${artifacts.binaryPath}`); } catch (error) { diff --git a/scripts/merge_compile_commands.py b/scripts/merge_compile_commands.py deleted file mode 100644 index b64079c..0000000 --- a/scripts/merge_compile_commands.py +++ /dev/null @@ -1,20 +0,0 @@ -import json - -main_db = "build/compile_commands.json" -zvec_db = "build/zvec-build/compile_commands.json" - -# Load both files -with open(main_db) as f: - main = json.load(f) - -with open(zvec_db) as f: - zvec = json.load(f) - -# Merge -merged = main + zvec - -# Overwrite the original main compile_commands.json -with open(main_db, "w") as f: - json.dump(merged, f, indent=2) - -print(f"Merged {len(merged)} entries into {main_db}")