Installing faissR and auditing native capabilities

Build contract

A functional faissR installation requires R development headers, Rcpp >= 1.1.0, Biobase, a C++20 compiler, and ABI-compatible FAISS headers and libraries. Biobase supplies the Bioconductor example workflow in the main vignette; the native nearest-neighbour implementation itself does not call Biobase code. Unix builds also require a Fortran compiler; native Windows builds use the C++ exact fallback instead. CUDA, FAISS GPU, and RAPIDS cuVS are optional. They become mandatory only when their strict build switches are set. The package does not vendor these native libraries and never installs a system package manager dependency silently.

Install or update Rcpp from CRAN before building from source when a Linux distribution supplies an older version. The native metadata constructors require the variadic list-construction API; older versions can fail during compilation.

Use FAISSR_REQUIRE_FAISS=1 for a production or CI build. This makes a missing or unusable FAISS installation fatal. A diagnostic-only build can be emitted on explicitly recognized automated targets that do not provide FAISS. Such an artifact can load and explain the missing capability, but it cannot perform a nearest-neighbour search and is not a functional platform result.

Tested combinations

  • Functional CPU package check: macOS arm64 with R 4.6.0, FAISS 1.14.3, libomp 22.1.x, clang 22.1.1, and GNU Fortran 12.2.0.
  • Publication CPU/CUDA campaign: Debian 13 with R 4.5.3, FAISS 1.14.3, cuVS 26.06, CUDA 13.2, and an NVIDIA L40S with driver 595.58.03. The frozen image did not retain the compiler executable and version.
  • Linux CPU CI definition: Ubuntu with the current Bioconductor devel R, FAISS 1.14.3 built from source, and the hosted GCC/GFortran toolchain recorded by the job.
  • macOS CPU CI definition: macOS with the current Bioconductor devel R, static FAISS supplied through an R-macos recipe prefix, and the hosted clang/GFortran toolchain recorded by the job.

The CI rows describe tracked workflows. They become release evidence only after the corresponding hosted jobs complete successfully.

Linux CPU-only installation

Ubuntu releases do not all provide libfaiss-dev. The following reproducible path builds FAISS 1.14.3 without CUDA, Python bindings, or tests and installs it under /opt/faiss.

sudo apt-get update
sudo apt-get install -y build-essential cmake ninja-build gfortran \
    git libopenblas-dev liblapack-dev

git clone --depth 1 --branch v1.14.3 \
    https://github.com/facebookresearch/faiss.git faiss-1.14.3
cmake -S faiss-1.14.3 -B faiss-1.14.3/build -G Ninja \
    -DFAISS_ENABLE_GPU=OFF -DFAISS_ENABLE_PYTHON=OFF \
    -DBUILD_TESTING=OFF -DBUILD_SHARED_LIBS=ON \
    -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/opt/faiss
cmake --build faiss-1.14.3/build --parallel
sudo cmake --install faiss-1.14.3/build

FAISS_HOME=/opt/faiss \
FAISSR_REQUIRE_FAISS=1 \
FAISSR_USE_CUDA=0 FAISSR_USE_CUVS=0 \
R CMD INSTALL faissR_0.99.47.tar.gz

When the distribution supplies compatible development files, installing libfaiss-dev, libblas-dev, and liblapack-dev and omitting FAISS_HOME is sufficient when those libraries match the R toolchain.

R’s bundled libRblas/libRlapack omit some single-precision routines required by FAISS, including ssyrk_. On Linux, configure checks a small FAISS client by compiling and loading it in a fresh R process. If needed, it adds a complete external LP64 BLAS/LAPACK provider while retaining R’s own numerical-library flags. A failed probe stops installation and records the compiler/loader details in config.log.

sudo apt-get install libfaiss-dev libblas-dev liblapack-dev
FAISSR_NUMERICAL_LIBS="-llapack -lblas" R CMD INSTALL faissR_0.99.47.tar.gz

The explicit FAISSR_NUMERICAL_LIBS setting is optional when automatic detection succeeds. It must match FAISS’s LP64 ABI; use additional -L and runtime-search-path flags for a nonstandard prefix. Do not replace R’s libRblas or libRlapack. The probe verifies linking/loading rather than all possible numerical operations or ABI combinations.

Optional Linux performance configuration

An ABI-compatible LP64 OpenBLAS build is an optional CPU performance configuration for FAISS, not a requirement to replace R’s configured BLAS. Benefits depend on the method, matrix shape, query batch size, and threading; graph traversal does not necessarily benefit from a faster dense BLAS. Keep the BLAS, LAPACK, and Fortran link flags reported by R CMD config. Do not overwrite libRblas or mix incompatible integer or compiler ABIs.

When benchmarking FAISS OpenMP parallelism, start with one BLAS thread to avoid nested thread-pool oversubscription. For a pthread OpenBLAS build, for example, start R with OPENBLAS_NUM_THREADS=1 and choose faissR’s n_threads explicitly. An OpenMP OpenBLAS build instead shares OMP_NUM_THREADS control; check the installed provider before setting thread limits. Compare alternative settings on representative workloads in separate R sessions, and retain the configuration only when observed runtime improves without changing results. This is an opt-in deployment choice, not a modification of publication results. See the OpenBLAS runtime documentation for provider-specific thread controls.

macOS CPU-only installation

Bioconductor and CRAN macOS binary builders use the R-macos recipes system for static native dependencies. faissR’s configure detects /opt/R/arm64 and /opt/R/x86_64. The repository contains a candidate FAISS recipe that must pass the upstream arm64 and x86_64 recipe builds before submission.

For a source build outside a prepared binary-builder environment, point the package at compatible FAISS and OpenMP prefixes. configure does not invoke a system package manager:

FAISS_HOME=/path/to/faiss \
LIBOMP_HOME=/path/to/openmp \
FAISSR_REQUIRE_FAISS=1 \
R CMD INSTALL faissR_0.99.47.tar.gz

Alternatively, pass separate FAISS paths with --configure-vars='INCLUDE_DIR=... LIB_DIR=...'. An already active conda or mamba environment is also accepted when it contains faiss-cpu and libomp; set both FAISS_HOME and LIBOMP_HOME to $CONDA_PREFIX. configure never creates or modifies the environment.

Windows CPU-only installation

Use an Rtools-compatible FAISS CPU build, not an MSVC binary. Set FAISS_HOME to its installation prefix, containing include/faiss and lib/libfaiss.a or lib/libfaiss.dll.a. The configure step compiles and loads a small DLL using the active R toolchain. It checks all required single- and double-precision BLAS/LAPACK symbols before compiling the package, and tries the complete Rtools -llapack -lblas libraries when R’s own libraries are insufficient. R’s LAPACK_LIBS, BLAS_LIBS, and FLIBS are retained.

Sys.setenv(FAISS_HOME = "C:/local/faiss", FAISSR_REQUIRE_FAISS = "1")
install.packages("Rcpp")
install.packages("faissR_0.99.47.tar.gz", repos = NULL, type = "source")

For nonstandard numerical libraries, set FAISSR_NUMERICAL_LIBS to the complete LP64 linker flags. A failed explicit selection is an error, not a silent fallback; inspect config.log. Without a compatible FAISS build, only the diagnostic profile is available unless strict mode rejects installation. The reproducible native Windows build recipe and test instructions are in docs/package-testing.md in the source repository.

Linux CUDA and cuVS installation

The CUDA toolkit, driver, FAISS GPU build, cuVS, R, and C++ runtime must come from one compatible stack. faissR never installs or changes an NVIDIA driver. On Debian or Ubuntu, do not add a distribution CUDA metapackage to a server whose driver is managed separately. With NVIDIA’s repository, a versioned cuda-toolkit-X-Y package installs development tools without the driver; the cuda and cuda-runtime-X-Y metapackages can include driver packages. Inspect a package-manager simulation before changing a shared machine.

Several CUDA toolkits can coexist in separate prefixes. Select one explicitly with CUDA_HOME; FAISS GPU and cuVS must have been built for a compatible CUDA stack. After those providers have been installed, use strict switches so that a CPU-only build cannot be mistaken for the requested GPU build:

CUDA_HOME=/usr/local/cuda \
FAISS_HOME=/opt/faiss-gpu \
CUVS_HOME=/opt/rapids \
FAISSR_REQUIRE_FAISS=1 \
FAISSR_REQUIRE_CUDA=1 \
FAISSR_REQUIRE_CUDA_RUNTIME=1 \
FAISSR_REQUIRE_CUVS=1 \
R CMD INSTALL faissR_0.99.47.tar.gz

Configuration compiles and links a small CUDA probe and records the toolkit, runtime, driver API, and device compute capability. A visible GPU is required at configuration only when FAISSR_REQUIRE_CUDA_RUNTIME=1; omit that switch for a build image that intentionally has no attached GPU. FAISSR_CUDA_ARCH accepts space-separated numeric capabilities such as "80 90 120". The highest requested architecture is also retained as Parallel Thread Execution (PTX) code for forward compatibility; set FAISSR_CUDA_PTX_ARCH explicitly to choose another PTX target or to none to disable it.

CUDA compatibility is reported per component. Native faissR kernels, FAISS GPU, and direct cuVS are separate capabilities, and availability of one does not establish compatibility of the others. The reproducible multi-toolkit test matrix is documented in .github/package-check/CUDA.md.

Native RAPIDS builds are Linux-oriented; WSL2 is the documented Windows route for CUDA/cuVS.

Audit the installed capability

Loading is not enough to establish a functional native installation. Inspect the provider table and run a small CPU search:

library(faissR)

backend_info()
#>          backend available knn_available
#> 1            cpu      TRUE          TRUE
#> 2          faiss      TRUE          TRUE
#> 3 faiss_gpu_cuvs     FALSE         FALSE
#> 4           cuvs     FALSE         FALSE
#> 5           cuda     FALSE         FALSE
#>                                                                                             public_call
#> 1                                                                                       backend = "cpu"
#> 2 backend = "cpu" or "cuda", method = "flat"/"ivf"/"ivfpq"/"hnsw"/"ivfpq_fastscan"/"cagra" as supported
#> 3                                                      backend = "cuda", method = "ivf"/"ivfpq"/"cagra"
#> 4                   backend = "cuda", method = "bruteforce"/"hnsw"/"nndescent"/"ivfpq_fastscan"/"cagra"
#> 5                                                                                      backend = "cuda"
#>   public_backends
#> 1             cpu
#> 2       cpu, cuda
#> 3            cuda
#> 4            cuda
#> 5            cuda
#>                                                                                        supported_methods
#> 1          auto, exact, flat, bruteforce, grid, hnsw, ivf, ivfpq, ivfpq_fastscan, vamana, nsg, nndescent
#> 2      flat, ivf, ivfpq, hnsw, ivfpq_fastscan, nsg; GPU flat/ivf/ivfpq/cagra when FAISS GPU is available
#> 3                                                                                      ivf, ivfpq, cagra
#> 4                                                     bruteforce, hnsw, nndescent, ivfpq_fastscan, cagra
#> 5 grid, flat, bruteforce, hnsw, ivf, ivfpq, ivfpq_fastscan, vamana, nsg, nndescent, cagra where compiled
#>                                                                                                                                                                                                                                       supported_metrics
#> 1                                                                                                                                                                       euclidean, cosine, correlation; method-specific exclusions in nn_capabilities()
#> 2 euclidean, cosine, correlation for Flat/IVF/IVFPQ/HNSW and CPU IVFPQ FastScan where available; public NSG uses the native CPU route, with deterministic FAISS HNSW seeding on large high-dimensional CPU inputs; explicit FAISS NSG is Euclidean-only
#> 3                                                                                                                                                                                                euclidean, cosine, correlation for IVF/IVFPQ and CAGRA
#> 4                                                                                  euclidean, cosine, correlation for direct brute force, direct IVF/PQ, HNSW from CAGRA, direct CAGRA, and direct cuVS NN-descent using metric transforms where needed
#> 5                                                                                                                                                                     euclidean, cosine, correlation where the selected CUDA method supports the metric
#>                                                                                                                           resolved_route
#> 1                                                                                                              implementation label: cpu
#> 2                              implementation labels include faiss_flat_l2, faiss_ivf, faiss_hnsw, faiss_ivfpq_fastscan, and faiss_gpu_*
#> 3                                                 implementation labels include faiss_gpu_ivf_flat, faiss_gpu_ivfpq, and faiss_gpu_cagra
#> 4 implementation labels include cuda_cuvs_bruteforce, cuda_cuvs_hnsw, cuda_cuvs_nndescent, cuda_cuvs_ivfpq_fastscan, and cuda_cuvs_cagra
#> 5                                         implementation labels include cuda_grid, cuda_vamana, and cuda_nsg; exact CUDA may report cuda
#>                  device
#> 1 CPU (4 logical cores)
#> 2                   CPU
#> 3                  <NA>
#> 4              CUDA GPU
#> 5                  <NA>
#>                                                                runtime
#> 1                                                  x86_64-pc-linux-gnu
#> 2 FAISS C++ library 1.13.2, CPU-only FAISS headers, FastScan available
#> 3 FAISS C++ library 1.13.2, CPU-only FAISS headers, FastScan available
#> 4                                          package_not_built_with_cuvs
#> 5                                          package_not_built_with_cuda
#>                                                                                                                                        note
#> 1                                                                                                      Native CPU path is always available.
#> 2 Real FAISS C++ KNN is available behind public CPU/CUDA method requests; IVFPQ FastScan CPU search requires linked FAISS FastScan support.
#> 3             FAISS GPU cuVS-integrated IVF/CAGRA requests are unavailable; CUDA requests fail unless another validated route is available.
#> 4                                                   RAPIDS cuVS CUDA KNN is unavailable; cuVS-backed public CUDA method requests will fail.
#> 5                                                                         Native CUDA KNN is unavailable; explicit CUDA requests will fail.
head(nn_capabilities(runtime = TRUE))
#>   method backend      metric supported exact            implementation
#> 1   auto     cpu   euclidean      TRUE    NA  shape-aware CPU selector
#> 2   auto     cpu      cosine      TRUE    NA  shape-aware CPU selector
#> 3   auto     cpu correlation      TRUE    NA  shape-aware CPU selector
#> 4   auto    cuda   euclidean      TRUE    NA shape-aware CUDA selector
#> 5   auto    cuda      cosine      TRUE    NA shape-aware CUDA selector
#> 6   auto    cuda correlation      TRUE    NA shape-aware CUDA selector
#>   implementation_status
#> 1             supported
#> 2             supported
#> 3             supported
#> 4             supported
#> 5             supported
#> 6             supported
#>                                                                                                                      notes
#> 1              Selects among exact, grid, FAISS, and package-owned graph routes using shape, metric, k, and target recall.
#> 2              Selects among exact, grid, FAISS, and package-owned graph routes using shape, metric, k, and target recall.
#> 3              Selects among exact, grid, FAISS, and package-owned graph routes using shape, metric, k, and target recall.
#> 4 Selects among CUDA grid, exhaustive FAISS GPU/cuVS, and IVF-Flat routes using shape, k, target recall, and availability.
#> 5      Selects among transformed exhaustive and graph CUDA routes using shape, k, target recall, and runtime availability.
#> 6      Selects among transformed exhaustive and graph CUDA routes using shape, k, target recall, and runtime availability.
#>   resolved_backend runtime_available     runtime_reason
#> 1         cpu_auto              TRUE          available
#> 2         cpu_auto              TRUE          available
#> 3         cpu_auto              TRUE          available
#> 4        cuda_auto             FALSE missing_cuda_route
#> 5        cuda_auto             FALSE missing_cuda_route
#> 6        cuda_auto             FALSE missing_cuda_route
#>                                                                                                       runtime_notes
#> 1                                                                                    Native CPU route is available.
#> 2                                                                                    Native CPU route is available.
#> 3                                                                                    Native CPU route is available.
#> 4                                       CUDA auto Euclidean route requires native CUDA, FAISS GPU, or cuVS support.
#> 5 CUDA auto non-Euclidean route requires FAISS GPU Flat, cuVS graph support, or an eligible native CUDA grid route.
#> 6 CUDA auto non-Euclidean route requires FAISS GPU Flat, cuVS graph support, or an eligible native CUDA grid route.

if (faiss_available()) {
    x <- matrix(seq_len(240), ncol = 6)
    ans <- nn(x, k = 3, method = "exact", backend = "cpu")
    stopifnot(identical(dim(ans$indices), c(nrow(x), 3L)))
} else {
    message("Diagnostic-only build: native FAISS searches are unavailable.")
}

c(
    faiss_gpu = faiss_gpu_available(),
    cuda = cuda_available(),
    cuvs = cuvs_available()
)
#> faiss_gpu      cuda      cuvs 
#>     FALSE     FALSE     FALSE

Do not infer GPU support from nvidia-smi alone. The package must have been compiled against the provider and the runtime device must also be available.

Common failures

  • FAISS headers or library not found: no compatible prefix was discovered. Set FAISS_HOME, then verify include/faiss/IndexFlat.h and lib/libfaiss.*.
  • omp.h not found on macOS: FAISS headers require an OpenMP runtime that clang cannot see. Use the R-macos recipe/toolchain runtime or set LIBOMP_HOME to a compatible prefix.
  • The package loads but faiss_available() is false: this is a diagnostic-only artifact. Install from source with FAISS and set FAISSR_REQUIRE_FAISS=1.
  • Loading reports an undefined BLAS symbol such as ssyrk_: R’s bundled libraries may lack single-precision FAISS dependencies. Install complete LP64 BLAS/LAPACK development libraries. The Linux compile/load probe records failures in config.log; use FAISSR_NUMERICAL_LIBS to select a custom provider. Adding R’s link flags alone is not always sufficient.
  • libfaiss or GLIBCXX_* load failure: the runtime linker and compiler ABI do not match. Use one compiler/runtime stack and expose its library directory through the platform linker path.
  • CUDA requested but nvcc is missing: the CUDA toolkit was not found. Set CUDA_HOME or NVCC, then check nvcc --version.
  • The CUDA compiler/linker probe fails: the selected compiler, headers, runtime libraries, or architecture flags do not form a coherent toolkit. Inspect config.log; do not repair this by replacing the host driver.
  • The CUDA runtime probe reports no device: run nvidia-smi, then compare the compiled toolkit, runtime, driver API, and compute capability shown by backend_info(). A build-only host may omit FAISSR_REQUIRE_CUDA_RUNTIME=1.
  • cuVS route unavailable: cuVS was absent at compile time or cannot load at runtime. Set CUVS_HOME, use FAISSR_REQUIRE_CUVS=1, and repair the runtime library path.

Checks and licenses

The source tarball should be checked in the same strict environment used for installation:

R CMD build .
FAISS_HOME=/opt/faiss FAISSR_REQUIRE_FAISS=1 \
    R CMD check --as-cran faissR_0.99.47.tar.gz
Rscript -e 'BiocCheck::BiocCheck("faissR_0.99.47.tar.gz", `new-package`=TRUE)'

faissR and FAISS use the Expat License. R package metadata records this license template as MIT + file LICENSE. cuVS is Apache-2.0-licensed, and CUDA is governed by the NVIDIA CUDA SDK EULA. These external components are supplied by the system and are not redistributed in the package. The installed THIRD_PARTY_LICENSES.md records links and the distribution boundary.

Session information

sessionInfo()
#> R version 4.6.1 (2026-06-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 26.04.1 LTS
#> 
#> Matrix products: default
#> BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 
#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.32.so;  LAPACK version 3.12.0
#> 
#> locale:
#>  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
#>  [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
#>  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
#>  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
#>  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
#> 
#> time zone: Etc/UTC
#> tzcode source: system (glibc)
#> 
#> attached base packages:
#> [1] stats4    stats     graphics  grDevices utils     datasets  methods  
#> [8] base     
#> 
#> other attached packages:
#>  [1] SingleCellExperiment_1.35.2 SummarizedExperiment_1.43.0
#>  [3] Biobase_2.73.2              GenomicRanges_1.65.4       
#>  [5] Seqinfo_1.3.2               IRanges_2.47.5             
#>  [7] S4Vectors_0.51.10           BiocGenerics_0.59.12       
#>  [9] generics_0.1.4              MatrixGenerics_1.25.0      
#> [11] matrixStats_1.5.0           faissR_0.99.47             
#> [13] BiocStyle_2.41.0           
#> 
#> loaded via a namespace (and not attached):
#>  [1] Matrix_1.7-6        jsonlite_2.0.0      compiler_4.6.1     
#>  [4] BiocManager_1.30.27 Rcpp_1.1.2          parallel_4.6.1     
#>  [7] jquerylib_0.1.4     yaml_2.3.12         fastmap_1.2.0      
#> [10] lattice_0.23-1      XVector_0.53.0      R6_2.6.1           
#> [13] S4Arrays_1.13.1     knitr_1.52          DelayedArray_0.39.6
#> [16] maketools_1.3.2     bslib_0.12.0        rlang_1.3.0        
#> [19] cachem_1.1.0        xfun_0.61           sass_0.4.10        
#> [22] sys_3.4.3           otel_0.2.0          SparseArray_1.13.2 
#> [25] cli_3.6.6           digest_0.6.39       grid_4.6.1         
#> [28] lifecycle_1.0.5     evaluate_1.0.5      buildtools_1.0.0   
#> [31] abind_1.4-8         rmarkdown_2.32      tools_4.6.1        
#> [34] htmltools_0.5.9