Wed, 22 Apr 2026 23:46:40 -0500
Add packaging script, remove alg_tools, measures, and pointsource_pde installation instruction from README.
/*! Build script for `pointsource_pde` */ #![feature(path_is_empty)] //use pyo3::{prepare_freethreaded_python, types::PyModule, PyErr, Python}; use conda_build::python_config; use std::env::split_paths; use std::fs::File; use std::io::Write; use std::path::PathBuf; use std::process::Command; const REQUIRED_PYTHON_MODULES: [&str; 7] = [ "dolfinx", "ufl", "numpy", "time", "petsc4py", "mpi4py", "json", ]; const DOLFINX_ACCESS_CXX_SOURCES: [&str; 3] = ["nanobind_helpers.cc", "minmax_p2.cc", "function.cc"]; const PY_SRC: [&str; 7] = [ "src/dolfinx_extras.py", "src/compose.py", "src/measure.py", "src/quadratic_dataterm.py", "src/convection_diffusion.py", "src/laser_sampling.py", "src/full_sampling.py", ]; fn main() -> Result<(), std::io::Error> { // Check Python module availability. // This doesn't necessarily work in a Conda setup. // prepare_freethreaded_python(); // Python::with_gil(|py| { // for m in REQUIRED_PYTHON_MODULES { // PyModule::import(py, m)?; // } // Ok::<_, PyErr>(()) // })?; let (pyc_e, _prefix_override, _py_type) = python_config(); let py_path = pyc_e.and_then(|pyc| pyc.exec_prefix_path())?; let py_exec = py_path.join("bin").join("python3"); let import_check_code = REQUIRED_PYTHON_MODULES .map(|m| format!("import {}\n", m)) .concat(); let res = Command::new(&py_exec) .args(["-c", import_check_code.as_ref()]) .status()?; if !res.success() { return Err(std::io::Error::other(format!( "Failed to load required Python modules (python execuitable {})", py_exec.display(), ))); } // Set up local-to-crate paths let cc_mod_name = "dolfinx_access"; let crate_name = "pointsource_pde"; let src = PathBuf::from("src"); let cc_mod_root = src.join(cc_mod_name); let bridge = src.join(format!("{cc_mod_name}.rs")); let cc_sources = DOLFINX_ACCESS_CXX_SOURCES.map(|f| cc_mod_root.join(f)); let mut include_dirs = Vec::from([PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("include")]); // Add (an estimate of) dolfinx ldflags. This shouldn't really be our problem to deal with, // but everything that is not piss, is shit. add_dep_ldflags("DEP_DOLFINX_LDFLAGS"); // Add external include paths add_dep_includes(&mut include_dirs, "DEP_DOLFINX_INCLUDE"); add_dep_includes(&mut include_dirs, "DEP_NANOBIND_INCLUDE"); // This may be useful to enable sometimes, when there's // trouble location GSL. // pkg_config::Config::new().probe("gsl").unwrap(); // Build the bridge cxx_build::bridge(&bridge) .std("c++20") .files(&cc_sources) .includes(&include_dirs) .compile(crate_name); for dep in PY_SRC { println!("cargo::rerun-if-changed={}", dep); } let header_prefix = PathBuf::from("include").join(cc_mod_name); let headers = DOLFINX_ACCESS_CXX_SOURCES .into_iter() .map(|s| header_prefix.join(s.replace(".cc", ".h"))); for dep in cc_sources .into_iter() .chain(headers) .chain(std::iter::once(bridge)) { println!("cargo:rerun-if-changed={}", dep.display()); } // Generate .clangd let mut dot_clangd = File::create(".clangd")?; write!( dot_clangd, "\ # Automatically generated by build.rs CompileFlags: Add: " )?; for i in include_dirs { writeln!(dot_clangd, " - --include-directory={}", i.display())?; } Ok(()) } /// Add list of include directions in the environment variable `dep` to /// `include_dirs`. fn add_dep_includes(include_dirs: &mut Vec<PathBuf>, dep: &str) { if let Some(include) = std::env::var_os(&dep) { include_dirs.extend(split_paths(&include).collect::<Vec<_>>()); } else { panic!("{dep} unset."); } } fn add_dep_ldflags(dep: &str) { if let Some(ldflags) = std::env::var_os(&dep) { for lp in split_paths(&ldflags) { if !lp.is_empty() { println!("cargo:rustc-link-arg=-Wl,{}", lp.display()); } } } else { panic!("{dep} unset."); } }