Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

usearch: new recipe #22931

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions recipes/usearch/all/conan_deps.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
if(USEARCH_USE_FP16LIB)
find_package(fp16 REQUIRED CONFIG)
link_libraries(fp16::fp16)
endif()
9 changes: 9 additions & 0 deletions recipes/usearch/all/conandata.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
sources:
"2.13.1":
url: "https://github.com/unum-cloud/usearch/archive/v2.13.1.tar.gz"
sha256: "58b17ec9625e5f489dcc78f29e9dcd809cb2d39567957181a1e514c43acf6392"
patches:
"2.13.1":
- patch_file: "patches/0001-fix-lib-installation.patch"
patch_type: "conan"
patch_description: "Fix C lib installation"
170 changes: 170 additions & 0 deletions recipes/usearch/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import os

from conan import ConanFile
from conan.errors import ConanInvalidConfiguration
from conan.tools.build import check_min_cppstd, stdcpp_library
from conan.tools.cmake import CMakeToolchain, CMakeDeps, CMake, cmake_layout
from conan.tools.files import get, copy, rmdir, export_conandata_patches, apply_conandata_patches, replace_in_file
from conan.tools.microsoft import is_msvc
from conan.tools.scm import Version

required_conan_version = ">=1.53.0"


class USearchConan(ConanFile):
name = "usearch"
license = "Apache-2.0"
description = "Smaller & Faster Single-File Vector Search Engine from Unum"
homepage = "https://unum-cloud.github.io/usearch/"
topics = ("search", "vector", "simd", "header-only")
url = "https://github.com/conan-io/conan-center-index"

package_type = "library"
options = {
"header_only": [True, False],
"shared": [True, False],
"fPIC": [True, False],
"with_fp16": [True, False],
"with_jemalloc": [True, False],
# "with_openmp": [True, False], # TODO: add after #22353 has been merged
# "with_simsimd": [True, False], # TODO: add simsimd to CCI
}
default_options = {
"header_only": True,
"shared": False,
"fPIC": True,
"with_fp16": True,
"with_jemalloc": False,
# "with_openmp": False,
# "with_simsimd": False,
}
settings = "os", "arch", "compiler", "build_type"
no_copy_source = True

@property
def _min_cppstd(self):
return 11

@property
def _compilers_minimum_version(self):
return {
"gcc": "6",
}

def export_sources(self):
copy(self, "conan_deps.cmake", self.recipe_folder, os.path.join(self.export_sources_folder, "src"))
export_conandata_patches(self)

def config_options(self):
if self.settings.os == "Windows":
del self.options.fPIC

def configure(self):
if self.options.header_only:
del self.options.shared
self.options.rm_safe("fPIC")
self.package_type = "header-library"
elif self.options.shared:
self.options.rm_safe("fPIC")

def layout(self):
cmake_layout(self, src_folder="src")

def package_id(self):
if self.info.options.header_only:
self.info.clear()

def requirements(self):
if self.options.with_fp16:
self.requires("fp16/cci.20210320", transitive_headers=True)
if self.options.with_jemalloc:
self.requires("jemalloc/5.3.0")
# if self.options.with_openmp:
# self.requires("llvm-openmp/17.0.6")

def validate(self):
if self.settings.compiler.get_safe("cppstd"):
check_min_cppstd(self, self._min_cppstd)
minimum_version = self._compilers_minimum_version.get(str(self.settings.compiler), False)
if minimum_version and Version(self.settings.compiler.version) < minimum_version:
raise ConanInvalidConfiguration(
f"{self.ref} requires C++{self._min_cppstd}, which your compiler does not support."
)

if is_msvc(self) and not self.options.header_only and not self.options.shared:
# test_package fails with STATUS_ACCESS_VIOLATION
raise ConanInvalidConfiguration("usearch does not support static linkage with MSVC")

def source(self):
get(self, **self.conan_data["sources"][self.version], strip_root=True)

def generate(self):
if not self.options.header_only:
tc = CMakeToolchain(self)
tc.variables["CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS"] = True
tc.variables["CMAKE_PROJECT_usearch_INCLUDE"] = "conan_deps.cmake"
tc.variables["USEARCH_USE_OPENMP"] = self.options.get_safe("with_openmp", False)
tc.variables["USEARCH_USE_SIMSIMD"] = self.options.get_safe("with_simsimd", False)
tc.variables["USEARCH_USE_JEMALLOC"] = self.options.with_jemalloc
tc.variables["USEARCH_USE_FP16LIB"] = self.options.with_fp16
tc.variables["USEARCH_INSTALL"] = True
tc.variables["USEARCH_BUILD_LIB_C"] = True
tc.variables["USEARCH_BUILD_TEST_CPP"] = False
tc.variables["USEARCH_BUILD_BENCH_CPP"] = False
if self.options.with_jemalloc:
tc.variables["JEMALLOC_ROOT_DIR"] = self.dependencies["jemalloc"].package_folder
tc.cache_variables["CMAKE_POLICY_DEFAULT_CMP0077"] = "NEW"
tc.generate()
deps = CMakeDeps(self)
deps.generate()

def _patch_sources(self):
apply_conandata_patches(self)
# Disable address sanitizer, which is not compatible with Conan packages
replace_in_file(self, os.path.join(self.source_folder, "CMakeLists.txt"),
"-fsanitize=address", "")

def build(self):
if not self.options.header_only:
self._patch_sources()
cmake = CMake(self)
cmake.configure()
cmake.build()

def package(self):
copy(self, "LICENSE", self.source_folder, os.path.join(self.package_folder, "licenses"))
if not self.options.header_only:
cmake = CMake(self)
cmake.install()
rmdir(self, os.path.join(self.package_folder, "share"))
else:
copy(self, "*",
src=os.path.join(self.source_folder, "include"),
dst=os.path.join(self.package_folder, "include"))

def package_info(self):
self.cpp_info.set_property("cmake_file_name", "usearch")
self.cpp_info.set_property("cmake_target_name", "usearch::usearch")
self.cpp_info.set_property("pkg_config_name", "usearch")

if self.options.header_only:
self.cpp_info.bindirs = []
self.cpp_info.libdirs = []
else:
prefix = "lib" if self.settings.os == "Windows" else ""
self.cpp_info.libs = [prefix + "usearch_c"]

if stdcpp_library(self):
self.cpp_info.system_libs.append(stdcpp_library(self))

self.cpp_info.defines += [
f"USEARCH_USE_OPENMP={int(self.options.get_safe('with_openmp', False))}",
f"USEARCH_USE_FP16LIB={int(bool(self.options.with_fp16))}",
f"USEARCH_USE_SIMSIMD={int(self.options.get_safe('with_simsimd', False))}",
]

if self.settings.os in ["Linux", "FreeBSD"]:
self.cpp_info.system_libs.append("pthread")
elif self.settings.os == "Macos":
self.cpp_info.frameworks.append("CoreFoundation")
self.cpp_info.frameworks.append("Security")
26 changes: 26 additions & 0 deletions recipes/usearch/all/patches/0001-fix-lib-installation.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--- c/CMakeLists.txt
+++ c/CMakeLists.txt
@@ -9,17 +9,13 @@
# This article discusses a better way to allow building either static or shared libraries:
# https://alexreinking.com/blog/building-a-dual-shared-and-static-library-with-cmake.html
if (USEARCH_BUILD_LIB_C)
- add_library(usearch_c SHARED lib.cpp)
- add_library(usearch_static_c STATIC lib.cpp)
-
- # Set the compile options for the static library
- if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
- target_compile_options(usearch_static_c PRIVATE -static-libstdc++)
- elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
- target_compile_options(usearch_static_c PRIVATE -static)
- endif ()
+ add_library(usearch_c lib.cpp)

setup_target(usearch_c)
- setup_target(usearch_static_c)

+ install(TARGETS usearch_c
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib
+ RUNTIME DESTINATION bin)
+ install(FILES usearch.h DESTINATION include)
endif ()
8 changes: 8 additions & 0 deletions recipes/usearch/all/test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.8)
project(test_package LANGUAGES CXX)

find_package(usearch REQUIRED CONFIG)

add_executable(${PROJECT_NAME} test_package.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE usearch::usearch)
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_11)
26 changes: 26 additions & 0 deletions recipes/usearch/all/test_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from conan import ConanFile
from conan.tools.build import can_run
from conan.tools.cmake import CMake, cmake_layout
import os


class TestPackageConan(ConanFile):
settings = "os", "arch", "compiler", "build_type"
generators = "CMakeToolchain", "CMakeDeps", "VirtualRunEnv"
test_type = "explicit"

def layout(self):
cmake_layout(self)

def requirements(self):
self.requires(self.tested_reference_str)

def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()

def test(self):
if can_run(self):
bin_path = os.path.join(self.cpp.build.bindirs[0], "test_package")
self.run(bin_path, env="conanrun")
19 changes: 19 additions & 0 deletions recipes/usearch/all/test_package/test_package.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include <usearch/index.hpp>
#include <usearch/index_dense.hpp>

int main()
{
using namespace unum::usearch;

metric_punned_t metric(256, metric_kind_t::l2sq_k, scalar_kind_t::f32_k);
index_dense_t index = index_dense_t::make(metric);
float vec[3] = {0.1, 0.3, 0.2};

index.reserve(10);
index.add(42, &vec[0]);
auto results = index.search(&vec[0], 5);

if (results.size() != 1)
return EXIT_FAILURE;
return EXIT_SUCCESS;
}
3 changes: 3 additions & 0 deletions recipes/usearch/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
versions:
"2.13.1":
folder: all
Loading