Skip to content

Commit aa33387

Browse files
Michael Norrisfacebook-github-bot
Michael Norris
authored andcommitted
Re-add example of how to build, link, and test an external SWIG module""
Summary: prior issues: 1. Nightlies were breaking due to yaml changes. Those are reverted. 2. AIX build broke (external). Fix is to add a conditional in tests/CMakeLists.txt. 3. Build issue facebookresearch#3944 Differential Revision: D64440629
1 parent eff0898 commit aa33387

6 files changed

+306
-26
lines changed

faiss/python/CMakeLists.txt

+29
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ configure_swigfaiss(swigfaiss.swig)
6060
configure_swigfaiss(swigfaiss_avx2.swig)
6161
configure_swigfaiss(swigfaiss_avx512.swig)
6262
configure_swigfaiss(swigfaiss_sve.swig)
63+
configure_swigfaiss(faiss_example_external_module.swig)
6364

6465
if(TARGET faiss)
6566
# Manually add headers as extra dependencies of swigfaiss.
@@ -73,6 +74,8 @@ if(TARGET faiss)
7374
"${faiss_SOURCE_DIR}/faiss/${h}")
7475
list(APPEND SWIG_MODULE_swigfaiss_sve_EXTRA_DEPS
7576
"${faiss_SOURCE_DIR}/faiss/${h}")
77+
list(APPEND SWIG_MODULE_faiss_example_external_module_EXTRA_DEPS
78+
"${faiss_SOURCE_DIR}/faiss/${h}")
7679
endforeach()
7780
if(FAISS_ENABLE_ROCM)
7881
foreach(h ${FAISS_GPU_HEADERS})
@@ -82,6 +85,8 @@ if(TARGET faiss)
8285
"${faiss_SOURCE_DIR}/faiss/gpu-rocm/${h}")
8386
list(APPEND SWIG_MODULE_swigfaiss_avx512_EXTRA_DEPS
8487
"${faiss_SOURCE_DIR}/faiss/gpu-rocm/${h}")
88+
list(APPEND SWIG_MODULE_faiss_example_external_module_EXTRA_DEPS
89+
"${faiss_SOURCE_DIR}/faiss/gpu-rocm/${h}")
8590
endforeach()
8691
else()
8792
foreach(h ${FAISS_GPU_HEADERS})
@@ -93,6 +98,8 @@ if(TARGET faiss)
9398
"${faiss_SOURCE_DIR}/faiss/gpu/${h}")
9499
list(APPEND SWIG_MODULE_swigfaiss_sve_EXTRA_DEPS
95100
"${faiss_SOURCE_DIR}/faiss/gpu/${h}")
101+
list(APPEND SWIG_MODULE_faiss_example_external_module_EXTRA_DEPS
102+
"${faiss_SOURCE_DIR}/faiss/gpu/${h}")
96103
endforeach()
97104
endif()
98105
else()
@@ -151,25 +158,37 @@ if(NOT FAISS_OPT_LEVEL STREQUAL "sve")
151158
set_target_properties(swigfaiss_sve PROPERTIES EXCLUDE_FROM_ALL TRUE)
152159
endif()
153160

161+
set_property(SOURCE faiss_example_external_module.swig
162+
PROPERTY SWIG_MODULE_NAME faiss_example_external_module)
163+
swig_add_library(faiss_example_external_module
164+
TYPE SHARED
165+
LANGUAGE python
166+
SOURCES faiss_example_external_module.swig
167+
)
168+
set_property(TARGET faiss_example_external_module PROPERTY SWIG_COMPILE_OPTIONS -doxygen)
169+
154170
if(NOT WIN32)
155171
# NOTE: Python does not recognize the dylib extension.
156172
set_target_properties(swigfaiss PROPERTIES SUFFIX .so)
157173
set_target_properties(swigfaiss_avx2 PROPERTIES SUFFIX .so)
158174
set_target_properties(swigfaiss_avx512 PROPERTIES SUFFIX .so)
159175
set_target_properties(swigfaiss_sve PROPERTIES SUFFIX .so)
176+
set_target_properties(faiss_example_external_module PROPERTIES SUFFIX .so)
160177
else()
161178
# we need bigobj for the swig wrapper
162179
target_compile_options(swigfaiss PRIVATE /bigobj)
163180
target_compile_options(swigfaiss_avx2 PRIVATE /bigobj)
164181
target_compile_options(swigfaiss_avx512 PRIVATE /bigobj)
165182
target_compile_options(swigfaiss_sve PRIVATE /bigobj)
183+
target_compile_options(faiss_example_external_module PRIVATE /bigobj)
166184
endif()
167185

168186
if(FAISS_ENABLE_GPU)
169187
if(FAISS_ENABLE_ROCM)
170188
target_link_libraries(swigfaiss PRIVATE hip::host)
171189
target_link_libraries(swigfaiss_avx2 PRIVATE hip::host)
172190
target_link_libraries(swigfaiss_avx512 PRIVATE hip::host)
191+
target_link_libraries(faiss_example_external_module PRIVATE hip::host)
173192
else()
174193
find_package(CUDAToolkit REQUIRED)
175194
if(FAISS_ENABLE_RAFT)
@@ -220,12 +239,21 @@ target_link_libraries(swigfaiss_sve PRIVATE
220239
OpenMP::OpenMP_CXX
221240
)
222241

242+
target_link_libraries(faiss_example_external_module PRIVATE
243+
Python::Module
244+
Python::NumPy
245+
OpenMP::OpenMP_CXX
246+
swigfaiss
247+
faiss
248+
)
249+
223250
# Hack so that python_callbacks.h can be included as
224251
# `#include <faiss/python/python_callbacks.h>`.
225252
target_include_directories(swigfaiss PRIVATE ${PROJECT_SOURCE_DIR}/../..)
226253
target_include_directories(swigfaiss_avx2 PRIVATE ${PROJECT_SOURCE_DIR}/../..)
227254
target_include_directories(swigfaiss_avx512 PRIVATE ${PROJECT_SOURCE_DIR}/../..)
228255
target_include_directories(swigfaiss_sve PRIVATE ${PROJECT_SOURCE_DIR}/../..)
256+
target_include_directories(faiss_example_external_module PRIVATE ${PROJECT_SOURCE_DIR}/../..)
229257

230258
find_package(Python REQUIRED
231259
COMPONENTS Development NumPy
@@ -251,6 +279,7 @@ target_link_libraries(swigfaiss PRIVATE faiss_python_callbacks)
251279
target_link_libraries(swigfaiss_avx2 PRIVATE faiss_python_callbacks)
252280
target_link_libraries(swigfaiss_avx512 PRIVATE faiss_python_callbacks)
253281
target_link_libraries(swigfaiss_sve PRIVATE faiss_python_callbacks)
282+
target_link_libraries(faiss_example_external_module PRIVATE faiss_python_callbacks)
254283

255284
configure_file(setup.py setup.py COPYONLY)
256285
configure_file(__init__.py __init__.py COPYONLY)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
// This is an example of how an external module can be added via SWIG.
9+
10+
%module faiss_example_external_module;
11+
12+
13+
// Put C++ includes here
14+
%{
15+
16+
#include <faiss/impl/FaissException.h>
17+
#include <faiss/impl/IDSelector.h>
18+
19+
%}
20+
21+
#pragma SWIG nowarn=322
22+
23+
typedef unsigned char uint8_t;
24+
typedef unsigned short uint16_t;
25+
typedef unsigned int uint32_t;
26+
27+
typedef signed char int8_t;
28+
typedef short int16_t;
29+
typedef int int32_t;
30+
31+
#ifdef SWIGWORDSIZE64
32+
typedef unsigned long uint64_t;
33+
typedef long int64_t;
34+
#else
35+
typedef unsigned long long uint64_t;
36+
typedef long long int64_t;
37+
#endif
38+
39+
typedef uint64_t size_t;
40+
41+
// This means: assume what's declared in these .h files is provided
42+
// by the Faiss module.
43+
%import(module="faiss") "faiss/MetricType.h"
44+
%import(module="faiss") "faiss/impl/IDSelector.h"
45+
46+
// functions to be parsed here
47+
48+
// This is important to release GIL and do Faiss exception handing
49+
%exception {
50+
Py_BEGIN_ALLOW_THREADS
51+
try {
52+
$action
53+
} catch(faiss::FaissException & e) {
54+
PyEval_RestoreThread(_save);
55+
56+
if (PyErr_Occurred()) {
57+
// some previous code already set the error type.
58+
} else {
59+
PyErr_SetString(PyExc_RuntimeError, e.what());
60+
}
61+
SWIG_fail;
62+
} catch(std::bad_alloc & ba) {
63+
PyEval_RestoreThread(_save);
64+
PyErr_SetString(PyExc_MemoryError, "std::bad_alloc");
65+
SWIG_fail;
66+
}
67+
Py_END_ALLOW_THREADS
68+
}
69+
70+
71+
// any class or function declared below will be made available
72+
// in the module.
73+
%inline %{
74+
75+
struct IDSelectorModulo : faiss::IDSelector {
76+
int mod;
77+
78+
IDSelectorModulo(int mod): mod(mod) {}
79+
80+
bool is_member(faiss::idx_t id) const {
81+
return id % mod == 0;
82+
}
83+
84+
~IDSelectorModulo() override {}
85+
};
86+
87+
faiss::idx_t sum_of_idx(size_t n, const faiss::idx_t *tab) {
88+
faiss::idx_t sum = 0;
89+
for(size_t i = 0; i < n; i++) {
90+
sum += tab[i];
91+
}
92+
return sum;
93+
}
94+
95+
float sum_of_float32(size_t n, const float *tab) {
96+
float sum = 0;
97+
for(size_t i = 0; i < n; i++) {
98+
sum += tab[i];
99+
}
100+
return sum;
101+
}
102+
103+
double sum_of_float64(size_t n, const double *tab) {
104+
double sum = 0;
105+
for(size_t i = 0; i < n; i++) {
106+
sum += tab[i];
107+
}
108+
return sum;
109+
}
110+
111+
%}
112+
113+
/**********************************************
114+
* To test if passing a swig_ptr on all array types works
115+
**********************************************/
116+
117+
%define SUM_OF_TYPE(ty)
118+
119+
%inline %{
120+
121+
ty##_t sum_of_##ty (size_t n, const ty##_t * tab) {
122+
ty##_t sum = 0;
123+
for(size_t i = 0; i < n; i++) {
124+
sum += tab[i];
125+
}
126+
return sum;
127+
}
128+
129+
%}
130+
131+
%enddef
132+
133+
SUM_OF_TYPE(uint8);
134+
SUM_OF_TYPE(uint16);
135+
SUM_OF_TYPE(uint32);
136+
SUM_OF_TYPE(uint64);
137+
138+
SUM_OF_TYPE(int8);
139+
SUM_OF_TYPE(int16);
140+
SUM_OF_TYPE(int32);
141+
SUM_OF_TYPE(int64);

faiss/python/setup.py

+38-20
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
# LICENSE file in the root directory of this source tree.
55

66
from __future__ import print_function
7-
from setuptools import setup, find_packages
7+
88
import os
9-
import shutil
109
import platform
10+
import shutil
11+
12+
from setuptools import find_packages, setup
1113

1214
# make the faiss python package dir
1315
shutil.rmtree("faiss", ignore_errors=True)
@@ -20,25 +22,32 @@
2022
shutil.copyfile("extra_wrappers.py", "faiss/extra_wrappers.py")
2123
shutil.copyfile("array_conversions.py", "faiss/array_conversions.py")
2224

23-
ext = ".pyd" if platform.system() == 'Windows' else ".so"
24-
prefix = "Release/" * (platform.system() == 'Windows')
25+
ext = ".pyd" if platform.system() == "Windows" else ".so"
26+
prefix = "Release/" * (platform.system() == "Windows")
2527

2628
swigfaiss_generic_lib = f"{prefix}_swigfaiss{ext}"
2729
swigfaiss_avx2_lib = f"{prefix}_swigfaiss_avx2{ext}"
2830
swigfaiss_avx512_lib = f"{prefix}_swigfaiss_avx512{ext}"
2931
callbacks_lib = f"{prefix}libfaiss_python_callbacks{ext}"
3032
swigfaiss_sve_lib = f"{prefix}_swigfaiss_sve{ext}"
33+
faiss_example_external_module_lib = f"_faiss_example_external_module{ext}"
3134

3235
found_swigfaiss_generic = os.path.exists(swigfaiss_generic_lib)
3336
found_swigfaiss_avx2 = os.path.exists(swigfaiss_avx2_lib)
3437
found_swigfaiss_avx512 = os.path.exists(swigfaiss_avx512_lib)
3538
found_callbacks = os.path.exists(callbacks_lib)
3639
found_swigfaiss_sve = os.path.exists(swigfaiss_sve_lib)
40+
found_faiss_example_external_module_lib = os.path.exists(
41+
faiss_example_external_module_lib
42+
)
3743

38-
assert (found_swigfaiss_generic or found_swigfaiss_avx2 or found_swigfaiss_avx512 or found_swigfaiss_sve), \
39-
f"Could not find {swigfaiss_generic_lib} or " \
40-
f"{swigfaiss_avx2_lib} or {swigfaiss_avx512_lib} or {swigfaiss_sve_lib}. " \
44+
assert (
45+
found_swigfaiss_generic or found_swigfaiss_avx2 or found_swigfaiss_avx512 or found_swigfaiss_sve or found_faiss_example_external_module_lib
46+
), (
47+
f"Could not find {swigfaiss_generic_lib} or "
48+
f"{swigfaiss_avx2_lib} or {swigfaiss_avx512_lib} or {swigfaiss_sve_lib} or {faiss_example_external_module_lib}. "
4149
f"Faiss may not be compiled yet."
50+
)
4251

4352
if found_swigfaiss_generic:
4453
print(f"Copying {swigfaiss_generic_lib}")
@@ -64,7 +73,17 @@
6473
shutil.copyfile("swigfaiss_sve.py", "faiss/swigfaiss_sve.py")
6574
shutil.copyfile(swigfaiss_sve_lib, f"faiss/_swigfaiss_sve{ext}")
6675

67-
long_description="""
76+
if found_faiss_example_external_module_lib:
77+
print(f"Copying {faiss_example_external_module_lib}")
78+
shutil.copyfile(
79+
"faiss_example_external_module.py", "faiss/faiss_example_external_module.py"
80+
)
81+
shutil.copyfile(
82+
faiss_example_external_module_lib,
83+
f"faiss/_faiss_example_external_module{ext}",
84+
)
85+
86+
long_description = """
6887
Faiss is a library for efficient similarity search and clustering of dense
6988
vectors. It contains algorithms that search in sets of vectors of any size,
7089
up to ones that possibly do not fit in RAM. It also contains supporting
@@ -73,20 +92,19 @@
7392
are implemented on the GPU. It is developed by Facebook AI Research.
7493
"""
7594
setup(
76-
name='faiss',
77-
version='1.9.0',
78-
description='A library for efficient similarity search and clustering of dense vectors',
95+
name="faiss",
96+
version="1.9.0",
97+
description="A library for efficient similarity search and clustering of dense vectors",
7998
long_description=long_description,
80-
url='https://github.com/facebookresearch/faiss',
81-
author='Matthijs Douze, Jeff Johnson, Herve Jegou, Lucas Hosseini',
82-
author_email='matthijs@meta.com',
83-
license='MIT',
84-
keywords='search nearest neighbors',
85-
86-
install_requires=['numpy', 'packaging'],
87-
packages=['faiss', 'faiss.contrib', 'faiss.contrib.torch'],
99+
url="https://github.com/facebookresearch/faiss",
100+
author="Matthijs Douze, Jeff Johnson, Herve Jegou, Lucas Hosseini",
101+
author_email="matthijs@meta.com",
102+
license="MIT",
103+
keywords="search nearest neighbors",
104+
install_requires=["numpy", "packaging"],
105+
packages=["faiss", "faiss.contrib", "faiss.contrib.torch"],
88106
package_data={
89-
'faiss': ['*.so', '*.pyd'],
107+
"faiss": ["*.so", "*.pyd"],
90108
},
91109
zip_safe=False,
92110
)

0 commit comments

Comments
 (0)