futhark_bindgen/
lib.rs

1pub(crate) use std::collections::BTreeMap;
2
3mod compiler;
4mod error;
5pub(crate) mod generate;
6pub mod manifest;
7mod package;
8
9pub use compiler::Compiler;
10pub use error::Error;
11pub use generate::{Config, Generate, OCaml, Rust};
12pub use manifest::Manifest;
13pub use package::Package;
14
15/// `Backend` is used to select a backend when running the `futhark` executable
16#[derive(Debug, serde::Deserialize, PartialEq, Eq, Clone, Copy)]
17pub enum Backend {
18    /// Sequential C backend: `futhark c`
19    ///
20    /// Requires a C compiler
21    #[serde(rename = "c")]
22    C,
23
24    /// CUDA backend: `futhark cuda`
25    ///
26    /// Requires the CUDA runtime and a C compiler
27    #[serde(rename = "cuda")]
28    CUDA,
29
30    /// OpenCL backend: `futhark opencl`
31    ///
32    /// Requires OpenCL and a C compiler
33    #[serde(rename = "opencl")]
34    OpenCL,
35
36    /// Multicore C backend: `futhark multicore`
37    ///
38    /// Requires a C compiler
39    #[serde(rename = "multicore")]
40    Multicore,
41
42    /// ISPC backend: `futhark ispc`
43    ///
44    /// Requires the `ispc` compiler in your `$PATH`
45    /// and a C compiler
46    #[serde(rename = "ispc")]
47    ISPC,
48
49    /// HIP backend: `futhark hip`
50    ///
51    /// Requires a C compiler
52    #[serde(rename = "hip")]
53    HIP,
54}
55
56impl Backend {
57    /// Get the name of a backend
58    pub fn to_str(&self) -> &'static str {
59        match self {
60            Backend::C => "c",
61            Backend::CUDA => "cuda",
62            Backend::OpenCL => "opencl",
63            Backend::Multicore => "multicore",
64            Backend::ISPC => "ispc",
65            Backend::HIP => "hip",
66        }
67    }
68
69    /// Return the backend specified by the given name if valid
70    pub fn from_name(name: &str) -> Option<Backend> {
71        match name.to_ascii_lowercase().as_str() {
72            "c" => Some(Backend::C),
73            "cuda" => Some(Backend::CUDA),
74            "opencl" => Some(Backend::OpenCL),
75            "multicore" => Some(Backend::Multicore),
76            "ispc" => Some(Backend::ISPC),
77            _ => None,
78        }
79    }
80
81    /// Get the backend from the `FUTHARK_BACKEND` environment variable
82    pub fn from_env() -> Option<Backend> {
83        match std::env::var("FUTHARK_BACKEND") {
84            Ok(name) => Backend::from_name(&name),
85            Err(_) => None,
86        }
87    }
88
89    /// Returns the C libraries that need to be linked for a backend
90    pub fn required_c_libs(&self) -> &'static [&'static str] {
91        match self {
92            Backend::CUDA => &["cuda", "cudart", "nvrtc", "m"],
93            Backend::OpenCL => &["OpenCL", "m"],
94            Backend::Multicore | Backend::ISPC => &["pthread", "m"],
95            Backend::HIP => &["hiprtc", "amdhip64"],
96            _ => &[],
97        }
98    }
99}
100
101#[cfg(feature = "build")]
102/// Generate the bindings and link the Futhark C code
103///
104/// `backend` selects the backend to use when generating C code: `futhark $backend --lib`
105///
106/// `src` is the full path to your Futhark code
107///
108/// `dest` is expected to be a relative path that will
109/// be appended to `$OUT_DIR`
110pub fn build(
111    backend: Backend,
112    src: impl AsRef<std::path::Path>,
113    dest: impl AsRef<std::path::Path>,
114) {
115    let out = std::path::PathBuf::from(std::env::var("OUT_DIR").unwrap());
116    let dest = std::path::PathBuf::from(&out).join(dest);
117    let lib = Compiler::new(backend, src)
118        .with_output_dir(out)
119        .compile()
120        .expect("Compilation failed");
121
122    let mut config = Config::new(&dest).expect("Unable to configure codegen");
123    let mut gen = config.detect().expect("Invalid output language");
124    gen.generate(&lib, &mut config)
125        .expect("Code generation failed");
126    lib.link();
127}