Skip to content

Commit 6d314a8

Browse files
committed
Adding support for disabling exceptions
Adding a mode of error handling that does not rely on C++ exceptions, with Abseil-like Status and StatusOr return types (but not adding a dependency on Abseil). The old exceptions-based API is still available, and the new functions are suffixed with "NoExceptions". Refactoring the CMake build system. Organizing examples and tests and reducing repetition. Adding the HNSWLIB_ENABLE_EXCEPTIONS option (ON by default). Exceptions are also enabled when building Python bindings, and in a few examples/tests where the code currently relies on exception handling, even if HNSWLIB_ENABLE_EXCEPTIONS is set to OFF. Adding ctest support. The only tests not supported by ctest are test_updates invoked with and without the "update" argument, because that requires installing numpy and running a data generation script and doing that from a CMake test might be controversial. Those tests are still run as part of GitHub Actions CI. Enabling sanitizer support using ENABLE_ASAN / ENABLE_UBSAN / ENABLE_TSAN / ENABLE_MSAN CMake options. Adding a combined ASAN/UBSAN build type to the C++ test matrix in GitHub Actions in non-Windows builds. Also adding Clang compiler on Ubuntu to the build matrix. Making sure that assertions are enabled during tests. Using the RelWithDebInfo build type and customizing it to remove the NDEBUG flag. Also removing the default /EHsc flag when building with MSVC and instead enabling exceptions when needed. Fixing race conditions when accessing random number generators and distributions from multiple threads in multiThreadLoad_test. These race conditions were caught using ASAN/UBSAN.
1 parent 39fd33b commit 6d314a8

27 files changed

+870
-262
lines changed

.github/workflows/build.yml

Lines changed: 79 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@ name: HNSW CI
33
on: [push, pull_request]
44

55
jobs:
6-
test_python:
7-
runs-on: ${{ matrix.os }}
6+
python:
7+
runs-on: ${{ matrix.os }}-latest
88
strategy:
99
matrix:
10-
os: [ubuntu-latest, windows-latest, macos-latest]
11-
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
10+
os: [ubuntu, windows, macos]
11+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13.2"]
1212
steps:
1313
- uses: actions/checkout@v4
1414
- uses: actions/setup-python@v5
1515
with:
1616
python-version: ${{ matrix.python-version }}
17-
17+
1818
- name: Build and install
1919
run: python -m pip install .
2020

@@ -36,11 +36,34 @@ jobs:
3636
python -m unittest discover -v --start-directory tests/python --pattern "bindings_test*.py"
3737
shell: bash
3838

39-
test_cpp:
40-
runs-on: ${{ matrix.os }}
39+
cpp:
40+
runs-on: ${{ matrix.os }}-latest
4141
strategy:
4242
matrix:
43-
os: [ubuntu-latest, windows-latest, macos-latest]
43+
os: [ubuntu, windows, macos]
44+
sanitizer: [no_sanitizers, asan_ubsan]
45+
exceptions: [no_exceptions, with_exceptions]
46+
compiler: [clang, gcc, msvc]
47+
exclude:
48+
# No sanitizers on Windows
49+
- os: windows
50+
sanitizer: asan_ubsan
51+
# No sanitizers on macOS -- might not be well supported on arm64
52+
- os: macos
53+
sanitizer: asan_ubsan
54+
# No clang or gcc on Windows
55+
- os: windows
56+
compiler: clang
57+
- os: windows
58+
compiler: gcc
59+
# No MSVC on Unix
60+
- os: ubuntu
61+
compiler: msvc
62+
- os: macos
63+
compiler: msvc
64+
# No GCC on macOS
65+
- os: macos
66+
compiler: gcc
4467
steps:
4568
- uses: actions/checkout@v4
4669
- uses: actions/setup-python@v5
@@ -51,11 +74,48 @@ jobs:
5174
run: |
5275
mkdir build
5376
cd build
54-
cmake ..
55-
if [ "$RUNNER_OS" == "Windows" ]; then
56-
cmake --build ./ --config Release
77+
cmake_cmd=( cmake -S .. -B . )
78+
if [[ "${RUNNER_OS}" != "Windows" ]]; then
79+
c_compiler="${{matrix.compiler}}"
80+
if [[ "${c_compiler}" == "gcc" ]]; then
81+
cxx_compiler=g++
82+
elif [[ "${c_compiler}" == "clang" ]]; then
83+
cxx_compiler=clang++
84+
else
85+
echo "Invalid compiler ${c_compiler} for OS ${RUNNER_OS}" >&2
86+
exit 1
87+
fi
88+
cmake_cmd+=(
89+
-DCMAKE_BUILD_TYPE=RelWithDebInfo
90+
-DCMAKE_C_COMPILER=${c_compiler}
91+
-DCMAKE_CXX_COMPILER=${cxx_compiler}
92+
)
93+
fi
94+
if [[ "${{ matrix.sanitizer }}" == "asan_ubsan" ]]; then
95+
cmake_cmd+=( -DENABLE_ASAN=ON -DENABLE_UBSAN=ON )
96+
fi
97+
if [[ "${{ matrix.exceptions }}" == "with_exceptions" ]]; then
98+
cmake_cmd+=( -DHNSWLIB_ENABLE_EXCEPTIONS=ON )
99+
else
100+
cmake_cmd+=( -DHNSWLIB_ENABLE_EXCEPTIONS=OFF )
101+
fi
102+
if [[ "${RUNNER_OS}" != "Windows" ]]; then
103+
cmake_cmd+=( -G Ninja )
104+
fi
105+
"${cmake_cmd[@]}"
106+
107+
# This is essential for debugging the the build, e.g. tracking down
108+
# if exceptions are enabled or NDEBUG is specified when it should not
109+
# be.
110+
echo
111+
echo "Contents of CMakeCache.txt:"
112+
echo
113+
cat CMakeCache.txt
114+
echo
115+
if [[ "${RUNNER_OS}" == "Windows" ]]; then
116+
cmake --build ./ --config RelWithDebInfo --verbose
57117
else
58-
make
118+
ninja -v
59119
fi
60120
shell: bash
61121

@@ -67,26 +127,16 @@ jobs:
67127
shell: bash
68128

69129
- name: Test
70-
timeout-minutes: 15
130+
# Without sanitizers, 15 minutes might be sufficient.
131+
timeout-minutes: 30
71132
run: |
72133
cd build
73-
if [ "$RUNNER_OS" == "Windows" ]; then
74-
cp ./Release/* ./
134+
if [[ "${RUNNER_OS}" == "Windows" ]]; then
135+
cp "./RelWithDebInfo/"* ./
75136
fi
76-
./example_search
77-
./example_filter
78-
./example_replace_deleted
79-
./example_mt_search
80-
./example_mt_filter
81-
./example_mt_replace_deleted
82-
./example_multivector_search
83-
./example_epsilon_search
84-
./searchKnnCloserFirst_test
85-
./searchKnnWithFilter_test
86-
./multiThreadLoad_test
87-
./multiThread_replace_test
137+
ctest --build-config "RelWithDebInfo"
138+
# These tests could be ctest-enabled in CMakeLists.txt, but that
139+
# requires auto-generating test data and installing numpy for that.
88140
./test_updates
89141
./test_updates update
90-
./multivector_search_test
91-
./epsilon_search_test
92142
shell: bash

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ var/
1111
.vs/
1212
**.DS_Store
1313
*.pyc
14+
venv/
15+
tests/cpp/data/

0 commit comments

Comments
 (0)