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

add package/faiss #25272

Open
wants to merge 2 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
9 changes: 9 additions & 0 deletions recipes/faiss/all/conandata.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
sources:
"1.8.0":
url: "https://github.com/facebookresearch/faiss/archive/refs/tags/v1.8.0.tar.gz"
sha256: "56ece0a419d62eaa11e39022fa27c8ed6d5a9b9eb7416cc5a0fdbeab07ec2f0c"
patches:
"1.8.0":
- patch_file: "patches/1.8.0-0001-fix-c_api-installation.patch"
patch_description: "Add installation of faiss_c_api library"
patch_type: "conan"
163 changes: 163 additions & 0 deletions recipes/faiss/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import os

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

required_conan_version = ">=1.53.0"

class FaissRecipe(ConanFile):
name = "faiss"
description = "Faiss - a library for efficient similarity search and clustering of dense vectors"
license = "MIT"
url = "https://github.com/conan-io/conan-center-index"
homepage = "https://github.com/facebookresearch/faiss"
topics = ("approximate-nearest-neighbor", "similarity-search", "clustering", "gpu")
package_type = "library"
settings = "os", "arch", "compiler", "build_type"
options = {
"shared": [True, False],
"fPIC": [True, False],
"opt_level": ["generic", "avx2", "avx512"],
"enable_c_api": [True, False],
"enable_gpu": [False, "cuda"],
}
default_options = {
"shared": False,
"fPIC": True,
"opt_level": "avx2",
"enable_c_api": False,
"enable_gpu": False,
}

@property
def _min_cppstd(self):
return 17

@property
def _compilers_minimum_version(self):
return {
"gcc": "7",
"clang": "5",
"apple-clang": "9",
"msvc": "191",
"Visual Studio": "15",
}

def export_sources(self):
export_conandata_patches(self)
copy(self, "*.cmake", self.recipe_folder, self.export_sources_folder)

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

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

def configure(self):
if self.options.shared:
self.options.rm_safe("fPIC")
# TODO: current openblas recipe does not export all below options yet
# self.options["openblas"].use_openmp = True
# self.options["openblas"].use_thread = False
# self.options["openblas"].use_locking = False
# self.options["openblas"].num_threads = 512

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

def requirements(self):
self.requires("openblas/0.3.27")
self.requires("openmp/system")

def validate(self):
if self.settings.compiler.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 self.settings.arch != "x86_64" and self.options.opt_level != "generic":
raise ConanInvalidConfiguration(f"-o opt_level={self.options.opt_level} is only supported on x86_64")
if self.options.enable_gpu and not self.options.shared:
raise ConanInvalidConfiguration(f"-o enable_gpu={self.options.enable_gpu} is only supported with -o shared=True")

def build_requirements(self):
self.tool_requires("cmake/[>=3.24 <4]")

def generate(self):
VirtualBuildEnv(self).generate()
tc = CMakeToolchain(self)
tc.cache_variables["FAISS_OPT_LEVEL"] = self.options.opt_level
tc.cache_variables["FAISS_ENABLE_C_API"] = self.options.enable_c_api
tc.cache_variables["FAISS_ENABLE_GPU"] = bool(self.options.enable_gpu)
tc.cache_variables["FAISS_ENABLE_RAFT"] = False
tc.cache_variables["FAISS_ENABLE_PYTHON"] = False
tc.cache_variables["BUILD_TESTING"] = False
tc.generate()
deps = CMakeDeps(self)
deps.generate()

def _patch_sources(self):
apply_conandata_patches(self)
# Disable irrelevant subdirs
save(self, os.path.join(self.source_folder, "demos", "CMakeLists.txt"), "")
save(self, os.path.join(self.source_folder, "benchs", "CMakeLists.txt"), "")
save(self, os.path.join(self.source_folder, "tutorial", "cpp", "CMakeLists.txt"), "")

def build(self):
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"))
cmake = CMake(self)
cmake.install()
rmdir(self, os.path.join(self.package_folder, "share"))
if self.options.enable_gpu:
copy(self, "faiss-cuda-support.cmake",
self.export_sources_folder,
os.path.join(self.package_folder, "lib", "cmake", "faiss"))

@property
def _enabled_opt_levels(self):
levels = self.__class__.options["opt_level"]
return levels[:levels.index(self.options.opt_level) + 1]

def package_info(self):
self.cpp_info.set_property("cmake_file_name", "faiss")

for level in self._enabled_opt_levels:
lib = "faiss" if level == "generic" else f"faiss_{level}"
component = self.cpp_info.components[lib]
component.set_property("cmake_target_name", lib)
component.libs = [lib]
component.requires = ["openblas::openblas", "openmp::openmp"]
if self.settings.os in ["Linux", "FreeBSD"]:
component.system_libs.append("m")
if self.options.enable_gpu:
component.builddirs = [os.path.join("lib", "cmake", "faiss")]

if self.options.enable_c_api:
self.cpp_info.components["faiss_c"].set_property("cmake_target_name", "faiss_c")
self.cpp_info.components["faiss_c"].libs = ["faiss_c"]
self.cpp_info.components["faiss_c"].requires = ["faiss"]
if not self.options.shared and stdcpp_library(self):
self.cpp_info.components["faiss_c"].system_libs.append(stdcpp_library(self))

if self.options.enable_gpu:
cmake_module = os.path.join("lib", "cmake", "faiss", "faiss-cuda-support.cmake")
self.cpp_info.set_property("cmake_build_modules", [cmake_module])

def compatibility(self):
levels = self.__class__.options["opt_level"]
compatible_levels = levels[levels.index(self.options.opt_level)+1:]
return [{"options": [("opt_level", level)]} for level in compatible_levels]
7 changes: 7 additions & 0 deletions recipes/faiss/all/faiss-cuda-support.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
include(CMakeFindDependencyMacro)
find_dependency(CUDAToolkit)
foreach(target faiss faiss_avx2 faiss_avx512 faiss_sve)
if(TARGET ${target})
target_link_libraries(${target} INTERFACE CUDA::cudart CUDA::cublas)
endif()
endforeach()
14 changes: 14 additions & 0 deletions recipes/faiss/all/patches/1.8.0-0001-fix-c_api-installation.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--- a/c_api/CMakeLists.txt
+++ b/c_api/CMakeLists.txt
@@ -57,3 +57,11 @@ target_link_libraries(example_c PRIVATE faiss_c)
if(FAISS_ENABLE_GPU)
add_subdirectory(gpu)
endif()
+
+include(GNUInstallDirs)
+install(TARGETS faiss_c
+ EXPORT faiss-targets
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+)
88 changes: 88 additions & 0 deletions recipes/faiss/all/test_package/.clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
AccessModifierOffset: -1
AlignAfterOpenBracket: AlwaysBreak
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlinesLeft: true
AlignOperands: false
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: true
BinPackArguments: false # at some point, set this to true
BinPackParameters: false # at some point, set this to true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ForEachMacros: [ FOR_EACH_RANGE, FOR_EACH, ]
IncludeCategories:
- Regex: '^<.*\.h(pp)?>'
Priority: 1
- Regex: '^<.*'
Priority: 2
- Regex: '.*'
Priority: 3
IndentCaseLabels: true
IndentWidth: 4
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 4
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: false
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 2000000
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 8
UseTab: Never
...
8 changes: 8 additions & 0 deletions recipes/faiss/all/test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.15)
project(test_package CXX)

find_package(faiss CONFIG REQUIRED)

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


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

def layout(self):
cmake_layout(self)

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

def generate(self):
tc = CMakeToolchain(self)
if str(self.dependencies["faiss"].options.enable_gpu) == "True":
tc.preprocessor_definitions["WITH_GPU"] = 1
tc.generate()

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.bindir, "test_package")
self.run(bin_path, env="conanrun")
65 changes: 65 additions & 0 deletions recipes/faiss/all/test_package/test_package.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include <faiss/IndexFlat.h>
#ifdef WITH_GPU
#include <faiss/gpu/GpuIndexFlat.h>
#include <faiss/gpu/StandardGpuResources.h>
#endif

using faiss::idx_t;

int main() {
int d = 64; // dimension
int nb = 10000; // database size
int nq = 10; // nb of queries
float* xb = new float[d * nb];
float* xq = new float[d * nq];
for (int i = 0; i < nb; i++) {
for (int j = 0; j < d; j++)
xb[d * i + j] = drand48();
xb[d * i] += i / 1000.;
}
for (int i = 0; i < nq; i++) {
for (int j = 0; j < d; j++)
xq[d * i + j] = drand48();
xq[d * i] += i / 1000.;
}

#ifndef WITH_GPU
faiss::IndexFlatL2 index(d); // call constructor
printf("CPU index:\n");
#else
faiss::gpu::StandardGpuResources res;
faiss::gpu::GpuIndexFlatL2 index(&res, d);
printf("GPU index:\n");
#endif

printf("is_trained = %s\n", index.is_trained ? "true" : "false");
index.add(nb, xb); // add vectors to the index
printf("ntotal = %ld\n", index.ntotal);

int k = 4;
{ // sanity check: search 5 first vectors of xb
idx_t* I = new idx_t[k * 5];
float* D = new float[k * 5];
index.search(5, xb, k, D, I);
printf("I=\n");
for (int i = 0; i < 5; i++) {
for (int j = 0; j < k; j++)
printf("%5ld ", I[i * k + j]);
printf("\n");
}
delete[] I;
delete[] D;
}
{ // search xq
idx_t* I = new idx_t[k * nq];
float* D = new float[k * nq];
index.search(nq, xq, k, D, I);
for (int i = 0; i < 5; i++) {
for (int j = 0; j < k; j++)
printf("%5ld ", I[i * k + j]);
printf("\n");
}
delete[] I;
delete[] D;
}
}
3 changes: 3 additions & 0 deletions recipes/faiss/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
versions:
"1.8.0":
folder: all