From 6fdc95855f4280d273934da2538637add04212d0 Mon Sep 17 00:00:00 2001 From: axect Date: Fri, 10 Jul 2026 13:07:58 +0800 Subject: [PATCH] IMPL: Add O3-openblas-system feature and correct BLAS setup docs (JOSS jonaspleyer #98) - New O3-openblas-system feature links the system-installed OpenBLAS via pkg-config instead of compiling OpenBLAS from source; openblas-src is added as an optional dependency solely to forward its system feature. - README Pre-requisite section now states that O3-openblas builds OpenBLAS from source (C/Fortran toolchain, make, network access) and documents the rustls / native-tls requirement of openblas-src 0.10.16+ when used with default-features = false. - Drop the stale Peroxide_BLAS link from the README feature list; point to the Pre-requisite section instead. - CI: o3 job also builds and tests O3-openblas-system; cargo-hack excludes the bare openblas-src flag (no TLS backend on its own) and keeps the new composite flag out of the powerset. --- .github/workflows/Github.yml | 14 ++++++++++---- Cargo.toml | 6 ++++++ README.md | 36 ++++++++++++++++++++---------------- src/lib.rs | 6 +++++- 4 files changed, 41 insertions(+), 21 deletions(-) diff --git a/.github/workflows/Github.yml b/.github/workflows/Github.yml index dd231f1..4719a0f 100644 --- a/.github/workflows/Github.yml +++ b/.github/workflows/Github.yml @@ -30,10 +30,14 @@ jobs: - uses: actions/checkout@v4 - name: Install OpenBLAS / LAPACK run: sudo apt-get update && sudo apt-get install -y libopenblas-dev liblapack-dev gfortran - - name: Build + - name: Build (OpenBLAS from source) run: cargo build --verbose --features O3-openblas - - name: Run tests + - name: Run tests (OpenBLAS from source) run: cargo test --verbose --features O3-openblas + - name: Build (system OpenBLAS via pkg-config) + run: cargo build --verbose --features O3-openblas-system + - name: Run tests (system OpenBLAS via pkg-config) + run: cargo test --verbose --features O3-openblas-system pure-rust: name: Pure-Rust feature set @@ -75,17 +79,19 @@ jobs: # HDF5 features (nc / netcdf) are excluded because they need an external # toolchain (vendor BLAS, HDF5 headers) or a non-Linux platform rather than # being a code problem; plot / pyo3 are exercised by the dedicated plot job. + # openblas-src alone (default-features = false) has no TLS backend for its + # source download, so it is only meaningful through O3-openblas-system. - name: Each feature builds on its own run: > cargo hack build --each-feature --optional-deps --keep-going - --exclude-features O3-accelerate,O3-mkl,O3-netlib,nc,netcdf,plot,pyo3,blas-src,lapack-src + --exclude-features O3-accelerate,O3-mkl,O3-netlib,nc,netcdf,plot,pyo3,blas-src,lapack-src,openblas-src # Pairwise (depth 2) coverage over the pure-Rust / numerical features. The # heavy compile units (arrow / parquet) and the backend / HDF5 / Python # features are excluded so the target dir does not blow up on a CI runner. - name: Pairwise feature powerset (pure-Rust / numerical) run: > cargo hack build --feature-powerset --depth 2 --optional-deps --keep-going - --exclude-features O3,O3-openblas,O3-accelerate,O3-mkl,O3-netlib,nc,netcdf,plot,pyo3,blas-src,lapack-src,arrow,parquet + --exclude-features O3,O3-openblas,O3-openblas-system,O3-accelerate,O3-mkl,O3-netlib,nc,netcdf,plot,pyo3,blas-src,lapack-src,openblas-src,arrow,parquet plot: name: plot (pyo3 + matplotlib) diff --git a/Cargo.toml b/Cargo.toml index c96ff8c..0839b5d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,9 @@ blas = { version = "0.22", optional = true } lapack = { version = "0.19", optional = true } blas-src = { version = "0.14", optional = true, default-features = false } lapack-src = { version = "0.13", optional = true, default-features = false } +# Only used to forward the `system` feature to the `openblas-src` instance +# that `blas-src` / `lapack-src` already pull in (see `O3-openblas-system`). +openblas-src = { version = "0.10", optional = true, default-features = false } serde = { version = "1.0", features = ["derive"], optional = true } rkyv = { version = "0.8", optional = true } json = { version = "0.12", optional = true } @@ -106,6 +109,9 @@ rand = ["dep:rand", "dep:rand_distr"] O3 = ["blas", "lapack"] # Convenience flags that bundle a backend choice for `O3`. O3-openblas = ["O3", "blas-src/openblas", "lapack-src/openblas"] +# Same as `O3-openblas`, but links the OpenBLAS already installed on the +# system (found via pkg-config) instead of compiling OpenBLAS from source. +O3-openblas-system = ["O3-openblas", "openblas-src/system"] O3-accelerate = ["O3", "blas-src/accelerate", "lapack-src/accelerate"] O3-mkl = ["O3", "blas-src/intel-mkl-dynamic-parallel", "lapack-src/intel-mkl-dynamic-parallel"] O3-netlib = ["O3", "blas-src/netlib", "lapack-src/netlib"] diff --git a/README.md b/README.md index 84faceb..b3f7ad7 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ For accelerated linear algebra, plotting, or DataFrame I/O, enable the matching Peroxide provides various features. - `default` - Pure Rust (No dependencies of architecture - Perfect cross compilation) -- `O3` - BLAS & LAPACK (Perfect performance but little bit hard to set-up - Strongly recommend to look [Peroxide with BLAS](https://github.com/Axect/Peroxide_BLAS)) +- `O3-openblas` / `O3-openblas-system` / `O3-accelerate` / `O3-mkl` / `O3-netlib` - BLAS & LAPACK accelerated linear algebra; pick one backend flag (see [Pre-requisite](#pre-requisite)) - `plot` - With matplotlib of python, we can draw any plots. - `complex` - With complex numbers (vector, matrix and integral) - `parallel` - With some parallel functions @@ -76,7 +76,7 @@ Peroxide provides various features. - `serde` - serialization with [Serde](https://serde.rs/). - `rkyv` - serialization with [rkyv](https://rkyv.org). -If you want to do high performance computation and more linear algebra, then choose `O3` feature. +If you want to do high performance computation and more linear algebra, then choose one of the `O3-*` backend features. If you don't want to depend C/C++ or Fortran libraries, then choose `default` feature. If you want to draw plot with some great templates, then choose `plot` feature. @@ -267,25 +267,27 @@ The three groups below depend on external libraries or runtimes; install the rel Those crates only provide function signatures, so the link backend that supplies the actual `dgemv_` / `dpotrf_` / ... symbols must be selected separately. The simplest path is to enable one of the convenience flags below; each pulls in [`blas-src`](https://crates.io/crates/blas-src) and [`lapack-src`](https://crates.io/crates/lapack-src) with the matching backend. -| Convenience flag | Backend | Typical platform / use case | -| ----------------- | ------------------ | --------------------------------------- | -| `O3-openblas` | OpenBLAS | Linux, Windows, macOS via Homebrew | -| `O3-accelerate` | Apple Accelerate | macOS (no extra system install) | -| `O3-mkl` | Intel MKL | Intel CPUs, vendor-tuned performance | -| `O3-netlib` | Netlib reference | Portability, lowest performance | +| Convenience flag | Backend | Build-time requirements | +| -------------------- | ----------------------------- | ------------------------------------------------ | +| `O3-openblas` | OpenBLAS, compiled from source | C + Fortran toolchain, `make`, network access | +| `O3-openblas-system` | System-installed OpenBLAS | `pkg-config` + the OpenBLAS system package | +| `O3-accelerate` | Apple Accelerate | macOS only (no extra system install) | +| `O3-mkl` | Intel MKL | Intel's redistributable (fetched automatically) | +| `O3-netlib` | Netlib reference, compiled from source | `cmake` + Fortran toolchain (lowest performance) | -If you need a backend not in the list above (for example BLIS or R's BLAS), enable the bare `O3` flag and add `blas-src` / `lapack-src` to your downstream binary's `Cargo.toml` with the appropriate features yourself. +`O3-openblas` does **not** use a system-installed OpenBLAS: the [`openblas-src`](https://crates.io/crates/openblas-src) crate downloads the OpenBLAS source tarball during the cargo build and compiles it, so it needs `gcc`, `gfortran`, `make`, and network access, but no BLAS system package. +The download happens over HTTPS through `openblas-src`'s default `rustls` TLS backend; if you depend on `openblas-src` directly with `default-features = false` (as some older guides suggest), you must re-enable one of its `rustls` / `native-tls` features yourself or the build will fail. -System libraries still need to be present on the host for `O3-openblas` and `O3-netlib`; install them with: +`O3-openblas-system` skips the source build and links the OpenBLAS already installed on the host, discovered via `pkg-config`: | Platform | Install | | --------------------- | ---------------------------------------------------- | -| Debian / Ubuntu | `sudo apt install libopenblas-dev liblapack-dev` | -| Fedora / RHEL | `sudo dnf install openblas-devel lapack-devel` | -| Arch Linux | `sudo pacman -S openblas lapack` | -| macOS (Homebrew) | `brew install openblas lapack` | +| Debian / Ubuntu | `sudo apt install libopenblas-dev` | +| Fedora / RHEL | `sudo dnf install openblas-devel` | +| Arch Linux | `sudo pacman -S openblas` | +| macOS (Homebrew) | `brew install openblas` | -`O3-accelerate` and `O3-mkl` ship their own backend (Apple's framework and Intel's redistributable, respectively), so they need no further system packages. +If you need a backend not in the list above (for example BLIS or R's BLAS), enable the bare `O3` flag and add `blas-src` / `lapack-src` to your downstream binary's `Cargo.toml` with the appropriate features yourself. > **Note:** `O3-accelerate` only builds on Apple targets. Enabling it on Linux or Windows fails while compiling `accelerate-src` with ``error: library kind `framework` is only supported on Apple targets``; pick `O3-openblas`, `O3-mkl`, or `O3-netlib` instead. For the same reason, exclude `O3-accelerate` (and `O3-mkl` / `O3-netlib` unless their toolchains are installed) when running tools like `cargo hack --each-feature` on Linux. @@ -335,6 +337,7 @@ cargo add peroxide --features "" # opt-in features | Goal | Command | | ------------------------------------------------- | ------------------------------------------------------------------------- | | Linear algebra on Linux / Windows | `cargo add peroxide --features O3-openblas` | +| Linear algebra with system OpenBLAS | `cargo add peroxide --features O3-openblas-system` | | Linear algebra on macOS | `cargo add peroxide --features O3-accelerate` | | Plotting via Python / matplotlib | `cargo add peroxide --features plot` | | DataFrame + Parquet I/O | `cargo add peroxide --features parquet` | @@ -350,7 +353,8 @@ The remaining single-crate flags exist so advanced users can pull in just one op | Flag | Requires | Purpose | | ---------------- | ----------------------- | ------------------------------------------------------------- | -| `O3-openblas` | OpenBLAS | BLAS / LAPACK accelerated linear algebra (Linux / Windows) | +| `O3-openblas` | OpenBLAS (from source) | BLAS / LAPACK accelerated linear algebra (Linux / Windows) | +| `O3-openblas-system` | OpenBLAS (system) | Same, linking the system-installed OpenBLAS via pkg-config | | `O3-accelerate` | Apple Accelerate | Same, using the Accelerate framework on macOS | | `O3-mkl` | Intel MKL | Same, using Intel MKL | | `O3-netlib` | Netlib | Same, using the reference Netlib BLAS | diff --git a/src/lib.rs b/src/lib.rs index 2698520..995dce9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -140,7 +140,7 @@ //! //! ## Useful tips for features //! -//! * If you want to use _QR_, _SVD_, or _Cholesky Decomposition_, you should use the `O3` feature. These decompositions are not implemented in the `default` feature. +//! * If you want to use _QR_, _SVD_, or _Cholesky Decomposition_, enable one of the BLAS backend features: `O3-openblas` (compiles OpenBLAS from source), `O3-openblas-system` (links the system-installed OpenBLAS), `O3-accelerate`, `O3-mkl`, or `O3-netlib`. These decompositions are not implemented in the `default` feature. The bare `O3` flag is an advanced escape hatch that expects you to supply a `blas-src` / `lapack-src` backend yourself. //! //! * If you want to save your numerical results, consider using the `parquet` or `nc` features, which correspond to the `parquet` and `netcdf` file formats, respectively. These formats are much more efficient than `csv` and `json`. //! @@ -165,6 +165,10 @@ extern crate lapack; extern crate blas_src as _; #[cfg(feature = "lapack-src")] extern crate lapack_src as _; +// `O3-openblas-system` re-exposes `openblas-src` directly so its `system` +// feature can be forwarded; link the crate here for the same reason. +#[cfg(feature = "openblas-src")] +extern crate openblas_src as _; #[cfg(feature = "plot")] extern crate pyo3;