diff --git a/.github/workflows/05-windows-build.yml b/.github/workflows/05-windows-build.yml index 7d69f78..ca0be0c 100644 --- a/.github/workflows/05-windows-build.yml +++ b/.github/workflows/05-windows-build.yml @@ -4,20 +4,21 @@ on: workflow_call: workflow_dispatch: +permissions: + contents: read + jobs: # Windows build and test matrix build-and-test-windows: name: Build & Test (${{ matrix.platform }}) - runs-on: ${{ matrix.os }} + runs-on: ${{ matrix.platform }} strategy: fail-fast: false matrix: include: - - os: windows-2022 - platform: windows-2022-x64 - - os: windows-2025 - platform: windows-2025-x64 + - platform: windows-2022 + - platform: windows-2025 steps: - name: Show env info diff --git a/.github/workflows/build_wheel_on_windows.yml b/.github/workflows/build_wheel_on_windows.yml index f156a3d..3cbaf31 100644 --- a/.github/workflows/build_wheel_on_windows.yml +++ b/.github/workflows/build_wheel_on_windows.yml @@ -207,7 +207,7 @@ jobs: $PSNativeCommandUseErrorActionPreference = $false $found = $false for ($i = 1; $i -le 30; $i++) { - python -m pip install -f @indexArgs --dry-run "zvec==$version" 1>$null 2>$null + python -m pip install --force-reinstall @indexArgs --dry-run "zvec==$version" 1>$null 2>$null if ($LASTEXITCODE -eq 0) { Write-Host "Version $version is available." $found = $true @@ -225,5 +225,5 @@ jobs: python -m venv test_env $venvPython = "test_env/Scripts/python.exe" & $venvPython -m pip install --upgrade pip - & $venvPython -m pip install @indexArgs "zvec==$version" + & $venvPython -m pip install --force-reinstall @indexArgs "zvec==$version" & $venvPython -c "import zvec; print('Import OK:', zvec.__version__)" diff --git a/CMakeLists.txt b/CMakeLists.txt index 55e3159..ad9df29 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,9 +5,9 @@ set(CC_CXX_STANDARD 17) if(MSVC) set(INTTYPES_FORMAT VC7) - add_compile_options(/FS) # handle .pdb + add_compile_options(/FS) # handle .pdb concurrency add_compile_options(/EHsc) # def c++ exception behavior - add_compile_options(/Zc:preprocessor) + add_compile_options(/Zc:preprocessor /Zc:__cplusplus) add_compile_options(/we4716) # -Werror=return-type ###### reduce output length to make vibe coding work better :) should be removed or solved later @@ -54,7 +54,6 @@ endif() include_directories(${PROJECT_ROOT_DIR}/src/include) include_directories(${PROJECT_ROOT_DIR}/src) -include_directories(${PROJECT_ROOT_DIR}) option(BUILD_PYTHON_BINDINGS "Build Python bindings using pybind11" OFF) message(STATUS "BUILD_PYTHON_BINDINGS:${BUILD_PYTHON_BINDINGS}") @@ -130,14 +129,4 @@ if(BUILD_PYTHON_BINDINGS) message(STATUS "Zvec install path: ${ZVEC_PY_INSTALL_DIR}") install(TARGETS _zvec LIBRARY DESTINATION ${ZVEC_PY_INSTALL_DIR}) - - if(MSVC) - install(FILES - $ - $ - $ - $ - DESTINATION ${ZVEC_PY_INSTALL_DIR} - ) - endif() endif() diff --git a/cmake/bazel.cmake b/cmake/bazel.cmake index 2910cc1..925df57 100644 --- a/cmake/bazel.cmake +++ b/cmake/bazel.cmake @@ -392,7 +392,14 @@ if(NOT MSVC) ) unset(_COMPILER_FLAGS) else() - # Replace the default compiling flags + option(ZVEC_USE_STATIC_CRT "Use static CRT (/MT) instead of dynamic CRT (/MD), default=ON" ON) + + if(ZVEC_USE_STATIC_CRT) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>" CACHE STRING "" FORCE) + else() + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL$<$:Debug>" CACHE STRING "" FORCE) + endif() + set( _COMPILER_FLAGS CMAKE_CXX_FLAGS @@ -406,14 +413,21 @@ else() CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS_MINSIZEREL ) - foreach(COMPILER_FLAG ${_COMPILER_FLAGS}) - string(REPLACE "/MT" "/MD" ${COMPILER_FLAG} "${${COMPILER_FLAG}}") - string(REGEX REPLACE "/W[0-9]" "" ${COMPILER_FLAG} "${${COMPILER_FLAG}}") - endforeach() + if(ZVEC_USE_STATIC_CRT) + foreach(COMPILER_FLAG ${_COMPILER_FLAGS}) + string(REPLACE "/MD" "/MT" ${COMPILER_FLAG} "${${COMPILER_FLAG}}") + string(REGEX REPLACE "/W[0-9]" "" ${COMPILER_FLAG} "${${COMPILER_FLAG}}") + endforeach() + else() + foreach(COMPILER_FLAG ${_COMPILER_FLAGS}) + string(REPLACE "/MT" "/MD" ${COMPILER_FLAG} "${${COMPILER_FLAG}}") + string(REGEX REPLACE "/W[0-9]" "" ${COMPILER_FLAG} "${${COMPILER_FLAG}}") + endforeach() + endif() unset(_COMPILER_FLAGS) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) - # Build shared library as default - set(BUILD_SHARED_LIBS ON) + set(BUILD_SHARED_LIBS OFF) endif() set(CMAKE_C_FLAGS_ASAN ${CMAKE_C_FLAGS_DEBUG}) diff --git a/cmake/option.cmake b/cmake/option.cmake index e399ebc..a4560f7 100644 --- a/cmake/option.cmake +++ b/cmake/option.cmake @@ -288,7 +288,7 @@ else() set(HOST_ARCH unknown) message(WARNING "unknown host arch: ${CMAKE_SYSTEM_PROCESSOR}") endif() - message(STATUS "host arch: ${HOST_ARCH}") + # message(STATUS "host arch: ${HOST_ARCH}") if (HOST_ARCH MATCHES "^(arm|arm64)$") _setup_armv8_march() diff --git a/examples/c++/CMakeLists.txt b/examples/c++/CMakeLists.txt index 13b8d7c..3c8a15e 100644 --- a/examples/c++/CMakeLists.txt +++ b/examples/c++/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.13) +cmake_minimum_required(VERSION 3.26) cmake_policy(SET CMP0077 NEW) project(zvec-example-c++) set(CMAKE_CXX_STANDARD 17) @@ -20,14 +20,31 @@ set(ZVEC_DEPENDENCY_LIB_DIR ${CMAKE_BINARY_DIR}/../../../${HOST_BUILD_DIR}/exter include_directories(${ZVEC_INCLUDE_DIR}) link_directories(${ZVEC_LIB_DIR} ${ZVEC_DEPENDENCY_LIB_DIR}) +# Support multi-config builds (libs in Release/ or Debug/ subdirectories) +if (CMAKE_BUILD_TYPE) + link_directories( + ${ZVEC_LIB_DIR}/${CMAKE_BUILD_TYPE} + ${ZVEC_DEPENDENCY_LIB_DIR}/${CMAKE_BUILD_TYPE} + ) +endif () +set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + # --- Determine debug/release library names --- if(CMAKE_BUILD_TYPE STREQUAL "Debug") set(GLOG_LIB glogd) - set(GFLAGS_LIB gflags_nothreads_debug) + if (WIN32) + set(GFLAGS_LIB gflags_nothreads_static_debug) + else () + set(GFLAGS_LIB gflags_nothreads_debug) + endif () set(PROTOBUF_LIB protobufd) else() set(GLOG_LIB glog) - set(GFLAGS_LIB gflags_nothreads) + if (WIN32) + set(GFLAGS_LIB gflags_nothreads_static) + else () + set(GFLAGS_LIB gflags_nothreads) + endif () set(PROTOBUF_LIB protobuf) endif() @@ -48,7 +65,6 @@ if (NOT WIN32) ${CMAKE_DL_LIBS} ) - set(zvec_db_deps roaring rocksdb diff --git a/examples/c++/core/main.cc b/examples/c++/core/main.cc index ac941f1..2aaa3f7 100644 --- a/examples/c++/core/main.cc +++ b/examples/c++/core/main.cc @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -46,9 +47,7 @@ Index::Pointer create_index(const BaseIndexParam::Pointer ¶m, } int main() { - char cmd_buf[100]; - snprintf(cmd_buf, 100, "rm -f %s", index_name.c_str()); - system(cmd_buf); + std::filesystem::remove(index_name); auto param = HNSWIndexParamBuilder() .WithMetricType(MetricType::kInnerProduct) diff --git a/examples/c++/db/main.cc b/examples/c++/db/main.cc index c3ed16b..3cb5bb6 100644 --- a/examples/c++/db/main.cc +++ b/examples/c++/db/main.cc @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -188,8 +189,7 @@ CollectionSchema::Ptr create_schema() { int main() { std::string path = "./demo"; - std::string rm_cmd = "rm -rf " + path; - system(rm_cmd.c_str()); + std::filesystem::remove_all(path); auto schema = create_schema(); CollectionOptions options{false, true}; diff --git a/src/binding/c/CMakeLists.txt b/src/binding/c/CMakeLists.txt index f800b56..7ca8604 100644 --- a/src/binding/c/CMakeLists.txt +++ b/src/binding/c/CMakeLists.txt @@ -106,22 +106,21 @@ endif() # This creates a truly self-contained library with zero external dependencies # Users only need to link libzvec_c_api.so without installing any dependencies if(MSVC) - # Windows MSVC: Use /WHOLEARCHIVE flag for static libraries only - # Note: roaring might be a DLL on Windows, so we don't apply WHOLEARCHIVE to it target_link_options(zvec_c_api PRIVATE ${ZVEC_WHOLE_ARCHIVE_PREFIX}$ ${ZVEC_WHOLE_ARCHIVE_PREFIX}$ ${ZVEC_WHOLE_ARCHIVE_PREFIX}$ ${ZVEC_WHOLE_ARCHIVE_PREFIX}$ + ${ZVEC_WHOLE_ARCHIVE_PREFIX}$ ) - + target_link_libraries(zvec_c_api PRIVATE zvec_db zvec_core zvec_ailego zvec_turbo - roaring # May be DLL on Windows, link normally + roaring ${ZVEC_CXX_STD_LIB} Threads::Threads ) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7308514..7be2294 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,6 +1,9 @@ include(${PROJECT_ROOT_DIR}/cmake/bazel.cmake) include(${PROJECT_ROOT_DIR}/cmake/option.cmake) +# TODO(windows): this is for test_util.h, should be removed +include_directories(${PROJECT_ROOT_DIR}) + cc_directories(ailego) cc_directories(db) cc_directories(core) diff --git a/thirdparty/CRoaring/CMakeLists.txt b/thirdparty/CRoaring/CMakeLists.txt index af6dfb3..3322b65 100644 --- a/thirdparty/CRoaring/CMakeLists.txt +++ b/thirdparty/CRoaring/CMakeLists.txt @@ -1,4 +1,7 @@ set(ENABLE_ROARING_TESTS OFF CACHE BOOL "Disable testing in CRoaring" FORCE) +if(MSVC) + set(ROARING_BUILD_STATIC ON CACHE BOOL "" FORCE) +endif() set(_SAVED_CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${EXTERNAL_LIB_DIR}) diff --git a/thirdparty/antlr/CMakeLists.txt b/thirdparty/antlr/CMakeLists.txt index 1f84eab..6a296eb 100644 --- a/thirdparty/antlr/CMakeLists.txt +++ b/thirdparty/antlr/CMakeLists.txt @@ -2,7 +2,9 @@ set(ANTLR_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/antlr4) set(ANTLR_PATCH ${CMAKE_CURRENT_SOURCE_DIR}/antlr4.patch) apply_patch_once("antlr4_fix" "${ANTLR_SRC_DIR}" "${ANTLR_PATCH}") -set(WITH_STATIC_CRT OFF CACHE BOOL "Use dynamic CRT for antlr4" FORCE) +if(MSVC) + set(WITH_STATIC_CRT ${ZVEC_USE_STATIC_CRT} CACHE BOOL "" FORCE) +endif() add_subdirectory(antlr4/runtime/Cpp/) target_include_directories(antlr4_static INTERFACE diff --git a/thirdparty/arrow/CMakeLists.txt b/thirdparty/arrow/CMakeLists.txt index f1d0bdb..0a76184 100644 --- a/thirdparty/arrow/CMakeLists.txt +++ b/thirdparty/arrow/CMakeLists.txt @@ -6,6 +6,10 @@ else() set(ARROW_PATCH ${CMAKE_CURRENT_SOURCE_DIR}/arrow.patch) apply_patch_once("arrow_fix" "${ARROW_SRC_DIR}" "${ARROW_PATCH}") endif() +if(MSVC) + set(ARROW_WIN_PATCH ${CMAKE_CURRENT_SOURCE_DIR}/arrow.windows.patch) + apply_patch_once("arrow_windows_crt_fix" "${ARROW_SRC_DIR}" "${ARROW_WIN_PATCH}") +endif() include(ExternalProject) include(ProcessorCount) @@ -58,7 +62,19 @@ if(ANDROID) LOG_INSTALL ON ) elseif (MSVC) - set(ARROW_EXTRA_CMAKE_ARGS -DCMAKE_C_FLAGS=/FS -DCMAKE_CXX_FLAGS=/FS) + if(ZVEC_USE_STATIC_CRT) + set(_ARROW_CRT_FLAG "/MT") + set(_ARROW_MSVC_RUNTIME "MultiThreaded$<$:Debug>") + else() + set(_ARROW_CRT_FLAG "/MD") + set(_ARROW_MSVC_RUNTIME "MultiThreadedDLL$<$:Debug>") + endif() + set(ARROW_EXTRA_CMAKE_ARGS + "-DCMAKE_C_FLAGS=/FS ${_ARROW_CRT_FLAG}" + "-DCMAKE_CXX_FLAGS=/FS ${_ARROW_CRT_FLAG}" + -DARROW_USE_STATIC_CRT=${ZVEC_USE_STATIC_CRT} + "-DCMAKE_MSVC_RUNTIME_LIBRARY=${_ARROW_MSVC_RUNTIME}" + ) ExternalProject_Add( ARROW.BUILD PREFIX arrow SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/apache-arrow-21.0.0 diff --git a/thirdparty/arrow/arrow.windows.patch b/thirdparty/arrow/arrow.windows.patch new file mode 100644 index 0000000..2087c76 --- /dev/null +++ b/thirdparty/arrow/arrow.windows.patch @@ -0,0 +1,25 @@ +diff --git a/cpp/cmake_modules/ThirdpartyToolchain.cmake b/cpp/cmake_modules/ThirdpartyToolchain.cmake +--- a/cpp/cmake_modules/ThirdpartyToolchain.cmake ++++ b/cpp/cmake_modules/ThirdpartyToolchain.cmake +@@ -862,10 +862,18 @@ + foreach(CONFIG DEBUG MINSIZEREL RELEASE RELWITHDEBINFO) + set(EP_CXX_FLAGS_${CONFIG} "${CMAKE_CXX_FLAGS_${CONFIG}}") + set(EP_C_FLAGS_${CONFIG} "${CMAKE_C_FLAGS_${CONFIG}}") +- if(CONFIG STREQUAL DEBUG) +- set(EP_MSVC_RUNTIME_LIBRARY MultiThreadedDebugDLL) ++ if(ARROW_USE_STATIC_CRT) ++ if(CONFIG STREQUAL DEBUG) ++ set(EP_MSVC_RUNTIME_LIBRARY MultiThreadedDebug) ++ else() ++ set(EP_MSVC_RUNTIME_LIBRARY MultiThreaded) ++ endif() + else() +- set(EP_MSVC_RUNTIME_LIBRARY MultiThreadedDLL) ++ if(CONFIG STREQUAL DEBUG) ++ set(EP_MSVC_RUNTIME_LIBRARY MultiThreadedDebugDLL) ++ else() ++ set(EP_MSVC_RUNTIME_LIBRARY MultiThreadedDLL) ++ endif() + endif() + string(APPEND EP_CXX_FLAGS_${CONFIG} + " ${CMAKE_CXX_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_${EP_MSVC_RUNTIME_LIBRARY}}") diff --git a/thirdparty/googletest/CMakeLists.txt b/thirdparty/googletest/CMakeLists.txt index c2cbc97..0ba5ddf 100644 --- a/thirdparty/googletest/CMakeLists.txt +++ b/thirdparty/googletest/CMakeLists.txt @@ -6,8 +6,11 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") endif() if (MSVC) - set(BUILD_SHARED_LIBS OFF) - set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + if(NOT ZVEC_USE_STATIC_CRT) + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + else() + set(gtest_force_shared_crt OFF CACHE BOOL "" FORCE) + endif() endif () diff --git a/thirdparty/lz4/CMakeLists.txt b/thirdparty/lz4/CMakeLists.txt index 3b3ef86..6b3f57b 100644 --- a/thirdparty/lz4/CMakeLists.txt +++ b/thirdparty/lz4/CMakeLists.txt @@ -60,6 +60,7 @@ if(MSVC) CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTERNAL_BINARY_DIR}/usr/local -DCMAKE_INSTALL_LIBDIR=lib + -DCMAKE_MSVC_RUNTIME_LIBRARY=${CMAKE_MSVC_RUNTIME_LIBRARY} -DBUILD_SHARED_LIBS=OFF -DBUILD_STATIC_LIBS=ON -DLZ4_BUILD_CLI=OFF diff --git a/thirdparty/protobuf/CMakeLists.txt b/thirdparty/protobuf/CMakeLists.txt index 7e4c1b2..0eebf94 100644 --- a/thirdparty/protobuf/CMakeLists.txt +++ b/thirdparty/protobuf/CMakeLists.txt @@ -1,5 +1,8 @@ set(protobuf_BUILD_TESTS OFF CACHE BOOL "Disable testing in protobuf" FORCE) set(protobuf_WITH_ZLIB ON CACHE BOOL "Disable zlib support in protobuf" FORCE) +if(MSVC) + set(protobuf_MSVC_STATIC_RUNTIME ${ZVEC_USE_STATIC_CRT} CACHE BOOL "" FORCE) +endif() set(_SAVED_CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${EXTERNAL_LIB_DIR}) diff --git a/thirdparty/rocksdb/CMakeLists.txt b/thirdparty/rocksdb/CMakeLists.txt index 721e2f7..334a67c 100644 --- a/thirdparty/rocksdb/CMakeLists.txt +++ b/thirdparty/rocksdb/CMakeLists.txt @@ -6,6 +6,14 @@ endif() set(ROCKSDB_BUILD_SHARED OFF CACHE BOOL "Disable install in rocksdb" FORCE) +if(MSVC) + if(ZVEC_USE_STATIC_CRT) + set(WITH_MD_LIBRARY OFF CACHE BOOL "build rocksdb with MT to match project CRT" FORCE) + else() + set(WITH_MD_LIBRARY ON CACHE BOOL "build rocksdb with MD to match project CRT" FORCE) + endif() +endif() + set(WITH_TESTS OFF CACHE BOOL "Disable testing in rocksdb" FORCE) set(WITH_ALL_TESTS OFF CACHE BOOL "Build all test, rather than a small subset" FORCE) set(WITH_BENCHMARK_TOOLS OFF CACHE BOOL "Disable benchmarks in rocksdb" FORCE)