Skip to content

Commit f227da1

Browse files
alibeklfcfacebook-github-bot
authored andcommitted
Add pip install support via scikit-build-core + cibuildwheel
Summary: Add official pip wheel packaging for `faiss-cpu`, enabling `pip install faiss-cpu` from PyPI. Builds wheels across Linux x86_64/aarch64, macOS arm64/x86_64, and Windows x86_64 for Python 3.10-3.13. **New files:** - `pyproject.toml`: scikit-build-core build backend config with cibuildwheel settings. Uses Dynamic Dispatch (`FAISS_OPT_LEVEL=dd`) for runtime SIMD selection, OpenBLAS for BLAS, and disables GPU/MKL/SVS. - `.github/workflows/build-pip.yml`: CI workflow using cibuildwheel to build wheels on 5 platform runners. Publishes to PyPI via OIDC trusted publishers on tag push. - `tests/test_wheel_smoke.py`: 11-check smoke test suite validating import, OpenMP, BLAS (FlatL2/FlatIP), index factory (IVF+PQ), HNSW, serialization roundtrip, GC safety, contrib imports, and SIMD level detection. **Modified files:** - `python/CMakeLists.txt`: Added `install()` targets so scikit-build-core can package the SWIG extension module, Python source files, and contrib subpackage into wheels. - `.github/workflows/build.yml`: Wired `build-pip.yml` into the root CI trigger so pip builds run alongside conda builds. Differential Revision: D95258115
1 parent d2f8d35 commit f227da1

5 files changed

Lines changed: 412 additions & 0 deletions

File tree

.github/workflows/build-pip.yml

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
#
3+
# This source code is licensed under the MIT license found in the
4+
# LICENSE file in the root directory of this source tree.
5+
6+
name: Build pip wheels
7+
8+
on:
9+
workflow_call:
10+
workflow_dispatch:
11+
pull_request:
12+
branches:
13+
- main
14+
paths:
15+
- 'pyproject.toml'
16+
- 'faiss/python/**'
17+
- '.github/workflows/build-pip.yml'
18+
19+
jobs:
20+
build-wheels:
21+
name: Build wheels on ${{ matrix.os }}
22+
runs-on: ${{ matrix.os }}
23+
strategy:
24+
fail-fast: false
25+
matrix:
26+
os: [ubuntu-latest, macos-14, macos-13, windows-2022, 2-core-ubuntu-arm]
27+
steps:
28+
- name: Checkout
29+
uses: actions/checkout@v4
30+
with:
31+
fetch-depth: 0
32+
fetch-tags: true
33+
34+
- name: Build wheels
35+
uses: pypa/cibuildwheel@v2.22
36+
env:
37+
CIBW_BUILD_VERBOSITY: 1
38+
39+
- name: Upload wheels
40+
uses: actions/upload-artifact@v4
41+
with:
42+
name: wheels-${{ matrix.os }}
43+
path: wheelhouse/*.whl
44+
45+
build-sdist:
46+
name: Build source distribution
47+
runs-on: ubuntu-latest
48+
steps:
49+
- name: Checkout
50+
uses: actions/checkout@v4
51+
with:
52+
fetch-depth: 0
53+
fetch-tags: true
54+
55+
- name: Build sdist
56+
run: pipx run build --sdist
57+
58+
- name: Upload sdist
59+
uses: actions/upload-artifact@v4
60+
with:
61+
name: sdist
62+
path: dist/*.tar.gz
63+
64+
publish:
65+
name: Publish to PyPI
66+
needs: [build-wheels, build-sdist]
67+
runs-on: ubuntu-latest
68+
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
69+
environment:
70+
name: pypi
71+
url: https://pypi.org/p/faiss-cpu
72+
permissions:
73+
id-token: write
74+
steps:
75+
- name: Download all artifacts
76+
uses: actions/download-artifact@v4
77+
with:
78+
path: dist
79+
merge-multiple: true
80+
81+
- name: Publish to PyPI
82+
uses: pypa/gh-action-pypi-publish@release/v1

.github/workflows/build.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ jobs:
1515
secrets:
1616
ANACONDA_API_TOKEN: ${{ secrets.ANACONDA_API_TOKEN }}
1717
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
18+
build-pip:
19+
uses: ./.github/workflows/build-pip.yml

faiss/python/CMakeLists.txt

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,3 +332,51 @@ configure_file(array_conversions.py array_conversions.py COPYONLY)
332332

333333
# file(GLOB files "${PROJECT_SOURCE_DIR}/../../contrib/*.py")
334334
file(COPY ${PROJECT_SOURCE_DIR}/../../contrib DESTINATION .)
335+
336+
# =============================================================================
337+
# Install targets for scikit-build-core / pip wheel packaging.
338+
# These install the Python package into the wheel via cmake --install.
339+
# =============================================================================
340+
341+
# Install the SWIG extension module (.so/.pyd)
342+
install(TARGETS swigfaiss
343+
LIBRARY DESTINATION faiss
344+
RUNTIME DESTINATION faiss
345+
)
346+
347+
# Install SWIG-generated Python wrapper
348+
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/swigfaiss.py"
349+
DESTINATION faiss
350+
)
351+
352+
# Install hand-written Python source files
353+
install(FILES
354+
"${CMAKE_CURRENT_SOURCE_DIR}/__init__.py"
355+
"${CMAKE_CURRENT_SOURCE_DIR}/loader.py"
356+
"${CMAKE_CURRENT_SOURCE_DIR}/class_wrappers.py"
357+
"${CMAKE_CURRENT_SOURCE_DIR}/extra_wrappers.py"
358+
"${CMAKE_CURRENT_SOURCE_DIR}/gpu_wrappers.py"
359+
"${CMAKE_CURRENT_SOURCE_DIR}/array_conversions.py"
360+
DESTINATION faiss
361+
)
362+
363+
# Install type stubs if present
364+
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/__init__.pyi")
365+
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/__init__.pyi" DESTINATION faiss)
366+
endif()
367+
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/py.typed")
368+
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/py.typed" DESTINATION faiss)
369+
endif()
370+
371+
# Install contrib subpackage (excluding Meta-internal *_fb.py files)
372+
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../contrib/"
373+
DESTINATION faiss/contrib
374+
FILES_MATCHING PATTERN "*.py"
375+
PATTERN "*_fb.py" EXCLUDE
376+
)
377+
378+
# Install contrib/torch subpackage data files
379+
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../contrib/torch/"
380+
DESTINATION faiss/contrib/torch
381+
FILES_MATCHING PATTERN "*.md"
382+
)

pyproject.toml

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
#
3+
# This source code is licensed under the MIT license found in the
4+
# LICENSE file in the root directory of this source tree.
5+
6+
[build-system]
7+
requires = ["scikit-build-core>=0.10", "numpy>=2.0"]
8+
build-backend = "scikit_build_core.build"
9+
10+
[project]
11+
name = "faiss-cpu"
12+
version = "1.14.0"
13+
description = "A library for efficient similarity search and clustering of dense vectors."
14+
readme = "README.md"
15+
license = "MIT"
16+
requires-python = ">=3.10"
17+
authors = [
18+
{name = "Meta AI Research"},
19+
]
20+
keywords = ["search", "nearest-neighbors", "clustering", "vectors", "similarity"]
21+
classifiers = [
22+
"Development Status :: 5 - Production/Stable",
23+
"Intended Audience :: Developers",
24+
"Intended Audience :: Science/Research",
25+
"License :: OSI Approved :: MIT License",
26+
"Operating System :: MacOS :: MacOS X",
27+
"Operating System :: Microsoft :: Windows",
28+
"Operating System :: POSIX :: Linux",
29+
"Programming Language :: C++",
30+
"Programming Language :: Python :: 3",
31+
"Programming Language :: Python :: 3.10",
32+
"Programming Language :: Python :: 3.11",
33+
"Programming Language :: Python :: 3.12",
34+
"Programming Language :: Python :: 3.13",
35+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
36+
]
37+
dependencies = ["numpy>=1.25", "packaging"]
38+
39+
[project.urls]
40+
Homepage = "https://github.com/facebookresearch/faiss"
41+
Documentation = "https://github.com/facebookresearch/faiss/wiki"
42+
Repository = "https://github.com/facebookresearch/faiss"
43+
Issues = "https://github.com/facebookresearch/faiss/issues"
44+
45+
[tool.scikit-build]
46+
cmake.build-type = "Release"
47+
48+
# Exclude C++ headers, cmake configs, and pkgconfig from the wheel.
49+
# Only the Python package (faiss/) and bundled shared libs remain.
50+
wheel.exclude = ["include/**", "share/**", "lib/cmake/**", "lib/pkgconfig/**"]
51+
52+
[tool.scikit-build.cmake.define]
53+
FAISS_OPT_LEVEL = "dd"
54+
FAISS_ENABLE_GPU = "OFF"
55+
FAISS_ENABLE_PYTHON = "ON"
56+
FAISS_ENABLE_MKL = "OFF"
57+
FAISS_ENABLE_C_API = "OFF"
58+
FAISS_ENABLE_EXTRAS = "OFF"
59+
FAISS_ENABLE_SVS = "OFF"
60+
BUILD_TESTING = "OFF"
61+
BUILD_SHARED_LIBS = "ON"
62+
63+
[tool.cibuildwheel]
64+
build = "cp310-* cp311-* cp312-* cp313-*"
65+
skip = "*-win32 *-manylinux_i686 *-musllinux_*"
66+
test-requires = ["numpy>=2.0,<3.0", "pytest"]
67+
test-command = "python -m pytest {project}/tests/test_wheel_smoke.py -v"
68+
69+
[tool.cibuildwheel.linux]
70+
before-all = "yum install -y openblas-devel swig"
71+
72+
[tool.cibuildwheel.macos]
73+
before-all = "brew install libomp openblas swig"
74+
75+
[tool.cibuildwheel.macos.environment]
76+
# Help CMake find brew-installed OpenBLAS and libomp on macOS
77+
CMAKE_PREFIX_PATH = "/opt/homebrew/opt/openblas;/opt/homebrew/opt/libomp;/usr/local/opt/openblas;/usr/local/opt/libomp"
78+
79+
[tool.cibuildwheel.windows]
80+
before-all = "choco install -y openblas swig"
81+
82+
[tool.cibuildwheel.windows.environment]
83+
# Dynamic Dispatch is not yet supported on Windows (the DD cmake block is
84+
# gated behind if(NOT WIN32)). Fall back to generic baseline, matching the
85+
# conda recipe which also builds "vanilla (no avx)" on Windows.
86+
CMAKE_ARGS = "-DFAISS_OPT_LEVEL=generic"

0 commit comments

Comments
 (0)