| |
1 /*! |
| |
2 Build script for `pointsource_pde` |
| |
3 */ |
| |
4 |
| |
5 //use pyo3::{prepare_freethreaded_python, types::PyModule, PyErr, Python}; |
| |
6 use conda_build::python_config; |
| |
7 use std::env::split_paths; |
| |
8 use std::fs::File; |
| |
9 use std::io::Write; |
| |
10 use std::path::PathBuf; |
| |
11 use std::process::Command; |
| |
12 |
| |
13 const REQUIRED_PYTHON_MODULES: [&str; 7] = [ |
| |
14 "dolfinx", "ufl", "numpy", "time", "petsc4py", "mpi4py", "json", |
| |
15 ]; |
| |
16 |
| |
17 const DOLFINX_ACCESS_CXX_SOURCES: [&str; 3] = |
| |
18 ["nanobind_helpers.cc", "minmax_p2.cc", "function.cc"]; |
| |
19 |
| |
20 const PY_SRC: [&str; 7] = [ |
| |
21 "src/dolfinx_extras.py", |
| |
22 "src/compose.py", |
| |
23 "src/measure.py", |
| |
24 "src/quadratic_dataterm.py", |
| |
25 "src/convection_diffusion.py", |
| |
26 "src/laser_sampling.py", |
| |
27 "src/full_sampling.py", |
| |
28 ]; |
| |
29 |
| |
30 fn main() -> Result<(), std::io::Error> { |
| |
31 // Check Python module availability. |
| |
32 // This doesn't necessarily work in a Conda setup. |
| |
33 // prepare_freethreaded_python(); |
| |
34 // Python::with_gil(|py| { |
| |
35 // for m in REQUIRED_PYTHON_MODULES { |
| |
36 // PyModule::import(py, m)?; |
| |
37 // } |
| |
38 // Ok::<_, PyErr>(()) |
| |
39 // })?; |
| |
40 |
| |
41 let (pyc_e, py_is_conda) = python_config(); |
| |
42 let py_path = pyc_e.and_then(|pyc| pyc.exec_prefix_path())?; |
| |
43 let py_exec = py_path.join("bin").join("python3"); |
| |
44 let import_check_code = REQUIRED_PYTHON_MODULES |
| |
45 .map(|m| format!("import {}\n", m)) |
| |
46 .concat(); |
| |
47 let res = Command::new(&py_exec) |
| |
48 .args(["-c", import_check_code.as_ref()]) |
| |
49 .status()?; |
| |
50 if !res.success() { |
| |
51 return Err(std::io::Error::other(format!( |
| |
52 "Failed to load required Python modules (python execuitable {}{})", |
| |
53 py_exec.display(), |
| |
54 if py_is_conda { " from Conda" } else { "" } |
| |
55 ))); |
| |
56 } |
| |
57 |
| |
58 // Set up local-to-crate paths |
| |
59 let cc_mod_name = "dolfinx_access"; |
| |
60 let crate_name = "pointsource_pde"; |
| |
61 let src = PathBuf::from("src"); |
| |
62 let cc_mod_root = src.join(cc_mod_name); |
| |
63 let bridge = src.join(format!("{cc_mod_name}.rs")); |
| |
64 let cc_sources = DOLFINX_ACCESS_CXX_SOURCES.map(|f| cc_mod_root.join(f)); |
| |
65 let mut include_dirs = Vec::from([PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("include")]); |
| |
66 |
| |
67 // Add (an estimate of) dolfinx ldflags. This shouldn't really be our problem to deal with, |
| |
68 // but everything that is not piss, is shit. |
| |
69 add_dep_ldflags("DEP_DOLFINX_LDFLAGS"); |
| |
70 |
| |
71 // Add external include paths |
| |
72 add_dep_includes(&mut include_dirs, "DEP_DOLFINX_INCLUDE"); |
| |
73 add_dep_includes(&mut include_dirs, "DEP_NANOBIND_INCLUDE"); |
| |
74 |
| |
75 // This may be useful to enable sometimes, when there's |
| |
76 // trouble location GSL. |
| |
77 // pkg_config::Config::new().probe("gsl").unwrap(); |
| |
78 |
| |
79 // Build the bridge |
| |
80 cxx_build::bridge(&bridge) |
| |
81 .std("c++20") |
| |
82 .files(&cc_sources) |
| |
83 .includes(&include_dirs) |
| |
84 .compile(crate_name); |
| |
85 |
| |
86 for dep in PY_SRC { |
| |
87 println!("cargo::rerun-if-changed={}", dep); |
| |
88 } |
| |
89 |
| |
90 let header_prefix = PathBuf::from("include").join(cc_mod_name); |
| |
91 let headers = DOLFINX_ACCESS_CXX_SOURCES |
| |
92 .into_iter() |
| |
93 .map(|s| header_prefix.join(s.replace(".cc", ".h"))); |
| |
94 |
| |
95 for dep in cc_sources |
| |
96 .into_iter() |
| |
97 .chain(headers) |
| |
98 .chain(std::iter::once(bridge)) |
| |
99 { |
| |
100 println!("cargo:rerun-if-changed={}", dep.display()); |
| |
101 } |
| |
102 |
| |
103 // Generate .clangd |
| |
104 let mut dot_clangd = File::create(".clangd")?; |
| |
105 write!( |
| |
106 dot_clangd, |
| |
107 "\ |
| |
108 # Automatically generated by build.rs |
| |
109 CompileFlags: |
| |
110 Add: |
| |
111 " |
| |
112 )?; |
| |
113 for i in include_dirs { |
| |
114 writeln!(dot_clangd, " - --include-directory={}", i.display())?; |
| |
115 } |
| |
116 |
| |
117 Ok(()) |
| |
118 } |
| |
119 |
| |
120 /// Add list of include directions in the environment variable `dep` to |
| |
121 /// `include_dirs`. |
| |
122 fn add_dep_includes(include_dirs: &mut Vec<PathBuf>, dep: &str) { |
| |
123 if let Some(include) = std::env::var_os(&dep) { |
| |
124 include_dirs.extend(split_paths(&include).collect::<Vec<_>>()); |
| |
125 } else { |
| |
126 panic!("{dep} unset."); |
| |
127 } |
| |
128 } |
| |
129 |
| |
130 fn add_dep_ldflags(dep: &str) { |
| |
131 if let Some(ldflags) = std::env::var_os(&dep) { |
| |
132 for lp in split_paths(&ldflags) { |
| |
133 println!("cargo:rustc-link-arg=-Wl,{}", lp.display()); |
| |
134 } |
| |
135 } else { |
| |
136 panic!("{dep} unset."); |
| |
137 } |
| |
138 } |