mkl_rs_build/
lib.rs

1use anyhow::{anyhow, Result};
2use pkg_config::Config;
3use bindgen::{MacroTypeVariation, NonCopyUnionStyle, EnumVariation, AliasVariation, FieldVisibilityKind, Builder};
4use std::{collections::HashSet, path::PathBuf, env::{var, set_var}};
5
6const OUT_DIR_ENV: &str = "OUT_DIR";
7const MINIMUM_VERSION: &str = "2024";
8
9/// Build MKL with the given configuration environment variable feature
10/// e.g. `build_with("CARGO_FEATURE_STATIC_ILP64_IOMP");`
11pub fn build_with(config: &str) -> Result<()> {
12    set_var(config, "1");
13    build()
14}
15
16/// Emit link and pkg-config information for linking MKL
17pub fn build() -> Result<()> {
18    let config = if var("CARGO_FEATURE_DYNAMIC_ILP64_GOMP").is_ok() {
19        "mkl-dynamic-ilp64-gomp"
20    } else if var("CARGO_FEATURE_DYNAMIC_ILP64_IOMP").is_ok() {
21        "mkl-dynamic-ilp64-iomp"
22    } else if var("CARGO_FEATURE_DYNAMIC_ILP64_SEQ").is_ok() {
23        "mkl-dynamic-ilp64-seq"
24    } else if var("CARGO_FEATURE_DYNAMIC_LP64_GOMP").is_ok() {
25        "mkl-dynamic-lp64-gomp"
26    } else if var("CARGO_FEATURE_DYNAMIC_LP64_IOMP").is_ok() {
27        "mkl-dynamic-lp64-iomp"
28    } else if var("CARGO_FEATURE_DYNAMIC_LP64_SEQ").is_ok() {
29        "mkl-dynamic-lp64-seq"
30    } else if var("CARGO_FEATURE_STATIC_ILP64_GOMP").is_ok() {
31        "mkl-static-ilp64-gomp"
32    } else if var("CARGO_FEATURE_STATIC_ILP64_IOMP").is_ok() {
33        "mkl-static-ilp64-iomp"
34    } else if var("CARGO_FEATURE_STATIC_ILP64_SEQ").is_ok() {
35        "mkl-static-ilp64-seq"
36    } else if var("CARGO_FEATURE_STATIC_LP64_GOMP").is_ok() {
37        "mkl-static-lp64-gomp"
38    } else if var("CARGO_FEATURE_STATIC_LP64_IOMP").is_ok() {
39        "mkl-static-lp64-iomp"
40    } else if var("CARGO_FEATURE_STATIC_LP64_SEQ").is_ok() {
41        "mkl-static-lp64-seq"
42    } else if var("CARGO_FEATURE_SDL").is_ok() {
43        "mkl-sdl"
44    } else {
45        return Err(anyhow::anyhow!("At least one of the following features must be enabled: dynamic-ilp64-gomp, dynamic-ilp64-iomp, dynamic-ilp64-seq, dynamic-lp64-gomp, dynamic-lp64-iomp, dynamic-lp64-seq, static-ilp64-gomp, static-ilp64-iomp, static-ilp64-seq, static-lp64-gomp, static-lp64-iomp, static-lp64-seq, sdl"));
46
47    };
48
49    let library = if config.contains("dynamic") {
50        Config::new()
51            .atleast_version(MINIMUM_VERSION)
52            .probe(config)?
53    } else {
54        Config::new()
55            .atleast_version(MINIMUM_VERSION)
56            .statik(true)
57            .probe(config)?
58    };
59
60    println!("cargo:warning={library:?}");
61
62    let lib_paths = library.link_files.iter()
63        .filter_map(|p| p.parent().map(|p| p.to_path_buf()))
64        .chain(library.link_paths.iter().map(|p| p.to_path_buf()))
65        .collect::<HashSet<_>>();
66
67    let ld_library_paths = lib_paths.iter()
68        .filter_map(|p| p.to_str())
69        .map(|p| p.to_string())
70        .collect::<Vec<_>>();
71
72    let include_path = library.include_paths
73        .first()
74        .ok_or_else(|| anyhow!("No include path found"))?;
75
76    let mkl_include_path = include_path
77        .join("mkl.h");
78
79    Builder::default()
80        .clang_arg(format!("-I{}", &include_path.to_str().ok_or_else(|| anyhow!("Invalid include path"))?))
81        .clang_arg("-fretain-comments-from-system-headers")
82        .clang_arg("-fparse-all-comments")
83        // We don't care at all what warnings simics has if they aren't errors :)
84        .clang_arg("-Wno-everything")
85        .default_visibility(FieldVisibilityKind::Public)
86        .default_alias_style(AliasVariation::TypeAlias)
87        .default_enum_style(EnumVariation::Rust {
88            non_exhaustive: false,
89        })
90        .default_macro_constant_type(MacroTypeVariation::Unsigned)
91        .default_non_copy_union_style(NonCopyUnionStyle::BindgenWrapper)
92        .derive_default(true)
93        .derive_hash(true)
94        .derive_partialord(true)
95        .derive_ord(true)
96        .derive_eq(true)
97        .derive_partialeq(true)
98        .generate_comments(true)
99        // Uses 128-bit unstable
100        .blocklist_function("strtold")
101        .blocklist_function("qecvt")
102        .blocklist_function("qfcvt")
103        .blocklist_function("qgcvt")
104        .blocklist_function("qecvt_r")
105        .blocklist_function("qfcvt_r")
106        .header(mkl_include_path.to_str().ok_or_else(|| anyhow!("Invalid include path"))?)
107        .generate()
108        .map_err(|e| anyhow!("Failed to generate bindings: {}", e))?
109        .write_to_file(PathBuf::from(var(OUT_DIR_ENV)?).join("bindings.rs"))?;
110
111    // Link to gomp if a gomp feature is enabled
112    if cfg!(feature = "dynamic-ilp64-gomp") || cfg!(feature = "dynamic-lp64-gomp") || cfg!(feature = "static-ilp64-gomp") || cfg!(feature = "static-lp64-gomp") {
113        println!("cargo:rustc-link-lib=gomp");
114    }
115
116    // Link to iomp if a iomp feature is enabled
117    if cfg!(feature = "static-ilp64-iomp") || cfg!(feature = "static-lp64-iomp") {
118        println!("cargo:rustc-link-lib=iomp5");
119    }
120
121    println!("cargo:rustc-env=LD_LIBRARY_PATH={}", ld_library_paths.join(":"));
122
123    Ok(())
124}