nanobind-sys/build.rs

Fri, 08 May 2026 17:16:34 -0500

author
Tuomo Valkonen <tuomov@iki.fi>
date
Fri, 08 May 2026 17:16:34 -0500
changeset 4
49b062acace9
parent 3
c3a4f4bb87f7
permissions
-rw-r--r--

Do not directly depend on ndarray, but through numpy

use anyhow::bail;
use build_print::info;
use cc;
use conda_build::python_config;
use std::env;
use std::path::PathBuf;

const NANOBIND_SOURCES: [&str; 7] = [
    "common.cpp",
    "trampoline.cpp",
    "nb_func.cpp",
    "nb_type.cpp",
    "nb_internals.cpp",
    "error.cpp",
    "implicit.cpp",
];

fn main() -> Result<(), anyhow::Error> {
    // Need to build it
    let (pyc_e, prefix_override, py_type) = python_config();

    // This is very clumsy due to PythonConfig::Error not supporting
    // conversion into std::error::Error, just std::io::Error.
    let (pyc, mut includes, _py_ldflags) = pyc_e
        .and_then(|pyc| {
            pyc.include_paths()
                .and_then(|ip| pyc.ldflags().map(|ld| (pyc, ip, ld)))
        })
        .map_err(|e| anyhow::Error::from(std::io::Error::from(e)))?;

    let prefix = prefix_override.ok_or_else(|| pyc.prefix_path()).unwrap();
    let version = pyc.semantic_version().unwrap();

    let nanobind_root = ({
            info!("{}{}Python {} found at prefix {}", py_type.unwrap_or(""), if py_type.is_none() { "" } else { " "},  version, prefix.display());
            let nanobind_root = prefix
                .join("lib")
                .join(format!("python{}.{}", version.major, version.minor))
                .join("site-packages")
                .join("nanobind");
            if !nanobind_root.exists() {
                info!("… but no nanobind installed there");
                None
            } else {
                Some(nanobind_root)
            }
        })
        .map_or_else(|| {
            let last_ditch = "/usr/share/nanobind";
            let nanobind_root = PathBuf::from(last_ditch);
            if !nanobind_root.exists() {
                bail!("Could not find nanobind in known locations. The recommended installation method is with pip at system Python location, or with Conda into the active environment. Also /usr/share/nanobind was attempted.");
            } else {
                info!("Found in {last_ditch}.");
                Ok(nanobind_root)
            }
        }, Ok)?;

    let nanobind_src = nanobind_root.join("src");

    println!("cargo:rerun-if-changed=build.rs");

    //println!("cargo:rustc-link-arg={}", py_ldflags);

    includes.extend([
        nanobind_root.join("include"),
        nanobind_root.join("ext/robin_map/include"),
    ]);

    println!(
        "cargo:include={}",
        env::join_paths(&includes)?.into_string().unwrap()
    );

    cc::Build::new()
        .std("c++20")
        .files(NANOBIND_SOURCES.map(|f| nanobind_src.join(f)))
        .includes(includes)
        //.flags(pyc.cflags()?)
        .compile("nanobind-sys");

    Ok(())
}

mercurial