diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 99d4b16c7..119a2eba2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -184,7 +184,7 @@ jobs: run: | cmake -DCMAKE_BUILD_TYPE=Release -DUSEARCH_BUILD_LIB_C=1 -DUSEARCH_BUILD_TEST_CPP=0 -DUSEARCH_BUILD_BENCH_CPP=0 -B ./build_release cmake --build ./build_release --config Release - zip -r usearch_macOS_${{ matrix.arch }}_${{ steps.version.outputs.version }}.zip build_release/libusearch_c.so c/usearch.h + zip -r usearch_macOS_${{ matrix.arch }}_${{ steps.version.outputs.version }}.zip build_release/libusearch_c.* c/usearch.h - name: Upload archive uses: xresloader/upload-to-github-release@v1 @@ -195,13 +195,9 @@ jobs: update_latest_release: true wasm_c_library: - name: WASM builds for C libraries on ${{ matrix.os }} - runs-on: ${{ matrix.os }} + name: WASM builds for C libraries + runs-on: ubuntu-22.04 needs: versioning - strategy: - fail-fast: false - matrix: - os: [ubuntu-22.04, macOS-11, windows-2022] steps: - uses: actions/checkout@v3 with: @@ -224,52 +220,14 @@ jobs: tar xf wasi-sdk-${WASI_VERSION_FULL}-linux.tar.gz rm -rf wasi-sdk-${WASI_VERSION_FULL}-linux.tar.gz export WASI_SDK_PATH=/home/runner/work/usearch/usearch/wasi-sdk-${WASI_VERSION_FULL} - archs=("x86_64" "arm64") + targets=("threads") cd ./c - for arch in "${archs[@]}" + for target in "${targets[@]}" do - ../wasi-sdk-20.0/bin/clang++ --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot -o libusearch_c.so -O3 lib.cpp -I. -I ../include/ -I ../fp16/include/ -shared --target=wasm32-wasi-threads -Wl,--no-entry -nostdlib -D_WASI_EMULATED_MMAN -march="$arch" - tar -czvf usearch_wasm_linux_"$arch"_${{ steps.version.outputs.version }}.tar.gz libusearch_c.so - mv usearch_wasm_linux_"$arch"_${{ steps.version.outputs.version }}.tar.gz ../ && rm -rf libusearch_c.so + ../wasi-sdk-${WASI_VERSION_FULL}/bin/clang++ --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot -o libusearch_c-${target}.wasm -O3 lib.cpp -I. -I ../include/ -I ../fp16/include/ -shared --target=wasm32-wasi-$target -Wl,--no-entry -mexec-model=reactor -D_WASI_EMULATED_MMAN -lwasi-emulated-mman + tar -czvf usearch_wasm_${target}_${{ steps.version.outputs.version }}.tar.gz libusearch_c-${target}.wasm + mv usearch_wasm_${target}_${{ steps.version.outputs.version }}.tar.gz ../ && rm -rf libusearch_c-${target}.wasm done - if: matrix.os == 'ubuntu-22.04' - - - name: Build library on MacOS - run: | - export WASI_VERSION=20 - export WASI_VERSION_FULL=${WASI_VERSION}.0 - wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_VERSION}/wasi-sdk-${WASI_VERSION_FULL}-macos.tar.gz - tar xf wasi-sdk-${WASI_VERSION_FULL}-macos.tar.gz - rm -rf wasi-sdk-${WASI_VERSION_FULL}-macos.tar.gz - export WASI_SDK_PATH=/Users/runner/work/usearch/usearch/wasi-sdk-${WASI_VERSION_FULL} - archs=("x86_64" "arm64") - cd ./c - for arch in "${archs[@]}" - do - ../wasi-sdk-20.0/bin/clang++ --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot -o libusearch_c.so -O3 lib.cpp -I. -I ../include/ -I ../fp16/include/ -shared --target=wasm32-wasi-threads -Wl,--no-entry -nostdlib -D_WASI_EMULATED_MMAN -march="$arch" - zip -r usearch_wasm_macos_"$arch"_${{ steps.version.outputs.version }}.zip libusearch_c.so - mv usearch_wasm_macos_"$arch"_${{ steps.version.outputs.version }}.zip ../ && rm -rf libusearch_c.so - done - if: matrix.os == 'macOS-11' - - - name: Build library on Windows - run: | - export WASI_VERSION=20 - export WASI_VERSION_FULL=${WASI_VERSION}.0 - curl -LOJ https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_VERSION}/wasi-sdk-${WASI_VERSION_FULL}.m-mingw.tar.gz - tar xf wasi-sdk-${WASI_VERSION_FULL}.m-mingw.tar.gz - rm -rf wasi-sdk-${WASI_VERSION_FULL}.m-mingw.tar.gz - export WASI_SDK_PATH=/d/a/usearch/usearch/wasi-sdk-${WASI_VERSION_FULL}+m - archs=("x64" "x86") - cd ./c - for arch in "${archs[@]}" - do - ../wasi-sdk-20.0+m/bin/clang++ --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot -o libusearch_c.so -O3 lib.cpp -I. -I ../include/ -I ../fp16/include/ -shared --target=wasm32-wasi-threads -Wl,--no-entry -nostdlib -D_WASI_EMULATED_MMAN -march="$arch" - tar -cvf usearch_wasm_windows_"$arch"_${{ steps.version.outputs.version }}.tar.gz libusearch_c.so - mv usearch_wasm_windows_"$arch"_${{ steps.version.outputs.version }}.tar.gz ../ && rm -rf libusearch_c.so - done - shell: bash - if: matrix.os == 'windows-2022' - name: Upload archive uses: xresloader/upload-to-github-release@v1 diff --git a/c/lib.cpp b/c/lib.cpp index 1ba127643..8891ccd61 100644 --- a/c/lib.cpp +++ b/c/lib.cpp @@ -104,6 +104,7 @@ search_result_t search_(index_dense_t* index, void const* vector, scalar_kind_t extern "C" { +__attribute__((export_name("usearch_init"))) USEARCH_EXPORT usearch_index_t usearch_init(usearch_init_options_t* options, usearch_error_t* error) { assert(options && error); @@ -127,15 +128,18 @@ USEARCH_EXPORT usearch_index_t usearch_init(usearch_init_options_t* options, use return result_ptr; } +__attribute__((export_name("usearch_free"))) USEARCH_EXPORT void usearch_free(usearch_index_t index, usearch_error_t*) { delete reinterpret_cast(index); } +__attribute__((export_name("usearch_serialized_length"))) USEARCH_EXPORT size_t usearch_serialized_length(usearch_index_t index, usearch_error_t*) { assert(index); return reinterpret_cast(index)->serialized_length(); } +__attribute__((export_name("usearch_save"))) USEARCH_EXPORT void usearch_save(usearch_index_t index, char const* path, usearch_error_t* error) { assert(index && path && error); @@ -144,6 +148,7 @@ USEARCH_EXPORT void usearch_save(usearch_index_t index, char const* path, usearc *error = result.error.release(); } +__attribute__((export_name("usearch_load"))) USEARCH_EXPORT void usearch_load(usearch_index_t index, char const* path, usearch_error_t* error) { assert(index && path && error); @@ -152,6 +157,7 @@ USEARCH_EXPORT void usearch_load(usearch_index_t index, char const* path, usearc *error = result.error.release(); } +__attribute__((export_name("usearch_view"))) USEARCH_EXPORT void usearch_view(usearch_index_t index, char const* path, usearch_error_t* error) { assert(index && path && error); @@ -160,6 +166,7 @@ USEARCH_EXPORT void usearch_view(usearch_index_t index, char const* path, usearc *error = result.error.release(); } +__attribute__((export_name("usearch_metadata"))) USEARCH_EXPORT void usearch_metadata(char const* path, usearch_init_options_t* options, usearch_error_t* error) { assert(path && options && error); @@ -178,6 +185,7 @@ USEARCH_EXPORT void usearch_metadata(char const* path, usearch_init_options_t* o options->metric = NULL; } +__attribute__((export_name("usearch_save_buffer"))) USEARCH_EXPORT void usearch_save_buffer(usearch_index_t index, void* buffer, size_t length, usearch_error_t* error) { assert(index && buffer && length && error); @@ -187,6 +195,7 @@ USEARCH_EXPORT void usearch_save_buffer(usearch_index_t index, void* buffer, siz *error = result.error.release(); } +__attribute__((export_name("usearch_load_buffer"))) USEARCH_EXPORT void usearch_load_buffer(usearch_index_t index, void const* buffer, size_t length, usearch_error_t* error) { @@ -197,6 +206,7 @@ USEARCH_EXPORT void usearch_load_buffer(usearch_index_t index, void const* buffe *error = result.error.release(); } +__attribute__((export_name("usearch_view_buffer"))) USEARCH_EXPORT void usearch_view_buffer(usearch_index_t index, void const* buffer, size_t length, usearch_error_t* error) { @@ -207,6 +217,7 @@ USEARCH_EXPORT void usearch_view_buffer(usearch_index_t index, void const* buffe *error = result.error.release(); } +__attribute__((export_name("usearch_metadata_buffer"))) USEARCH_EXPORT void usearch_metadata_buffer(void const* buffer, size_t length, usearch_init_options_t* options, usearch_error_t* error) { @@ -227,28 +238,34 @@ USEARCH_EXPORT void usearch_metadata_buffer(void const* buffer, size_t length, u options->metric = NULL; } +__attribute__((export_name("usearch_size"))) USEARCH_EXPORT size_t usearch_size(usearch_index_t index, usearch_error_t*) { // return reinterpret_cast(index)->size(); } +__attribute__((export_name("usearch_capacity"))) USEARCH_EXPORT size_t usearch_capacity(usearch_index_t index, usearch_error_t*) { return reinterpret_cast(index)->capacity(); } +__attribute__((export_name("usearch_dimensions"))) USEARCH_EXPORT size_t usearch_dimensions(usearch_index_t index, usearch_error_t*) { return reinterpret_cast(index)->dimensions(); } +__attribute__((export_name("usearch_connectivity"))) USEARCH_EXPORT size_t usearch_connectivity(usearch_index_t index, usearch_error_t*) { return reinterpret_cast(index)->connectivity(); } +__attribute__((export_name("usearch_reserve"))) USEARCH_EXPORT void usearch_reserve(usearch_index_t index, size_t capacity, usearch_error_t* error) { assert(index && error); if (!reinterpret_cast(index)->reserve(capacity)) *error = "Out of memory!"; } +__attribute__((export_name("usearch_add"))) USEARCH_EXPORT void usearch_add( // usearch_index_t index, usearch_key_t key, void const* vector, usearch_scalar_kind_t kind, // usearch_error_t* error) { @@ -259,16 +276,19 @@ USEARCH_EXPORT void usearch_add( *error = result.error.release(); } +__attribute__((export_name("usearch_contains"))) USEARCH_EXPORT bool usearch_contains(usearch_index_t index, usearch_key_t key, usearch_error_t*) { assert(index); return reinterpret_cast(index)->contains(key); } +__attribute__((export_name("usearch_count"))) USEARCH_EXPORT size_t usearch_count(usearch_index_t index, usearch_key_t key, usearch_error_t*) { assert(index); return reinterpret_cast(index)->count(key); } +__attribute__((export_name("usearch_search"))) USEARCH_EXPORT size_t usearch_search( // usearch_index_t index, void const* vector, usearch_scalar_kind_t kind, size_t results_limit, // usearch_key_t* found_keys, usearch_distance_t* found_distances, usearch_error_t* error) { @@ -284,6 +304,7 @@ USEARCH_EXPORT size_t usearch_search( return result.dump_to(found_keys, found_distances); } +__attribute__((export_name("usearch_get"))) USEARCH_EXPORT size_t usearch_get( // usearch_index_t index, usearch_key_t key, size_t count, // void* vectors, usearch_scalar_kind_t kind, usearch_error_t*) { @@ -292,6 +313,7 @@ USEARCH_EXPORT size_t usearch_get( // return get_(reinterpret_cast(index), key, count, vectors, scalar_kind_to_cpp(kind)); } +__attribute__((export_name("usearch_remove"))) USEARCH_EXPORT size_t usearch_remove(usearch_index_t index, usearch_key_t key, usearch_error_t* error) { assert(index && error); @@ -301,6 +323,7 @@ USEARCH_EXPORT size_t usearch_remove(usearch_index_t index, usearch_key_t key, u return result.completed; } +__attribute__((export_name("usearch_rename"))) USEARCH_EXPORT size_t usearch_rename( // usearch_index_t index, usearch_key_t from, usearch_key_t to, usearch_error_t* error) { @@ -311,6 +334,7 @@ USEARCH_EXPORT size_t usearch_rename( // return result.completed; } +__attribute__((export_name("usearch_distance"))) USEARCH_EXPORT usearch_distance_t usearch_distance( // void const* vector_first, void const* vector_second, // usearch_scalar_kind_t scalar_kind, size_t dimensions, // @@ -321,6 +345,7 @@ USEARCH_EXPORT usearch_distance_t usearch_distance( // return metric((byte_t const*)vector_first, (byte_t const*)vector_second); } +__attribute__((export_name("usearch_exact_search"))) USEARCH_EXPORT void usearch_exact_search( // void const* dataset, size_t dataset_count, size_t dataset_stride, // void const* queries, size_t queries_count, size_t queries_stride, //