summaryrefslogtreecommitdiff
path: root/zfs-core-sys/build.rs
blob: cdce9e9b6a4fd9d9ea836e9817b48bb503cec12c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use std::{ffi::OsStr, path::PathBuf, str::FromStr};

fn var(s: &str) -> Result<String, std::env::VarError> {
    println!("cargo:rerun-if-env-changed={}", s);
    std::env::var(s)
}

#[derive(Debug)]
enum Lookup {
    PkgConfig,
    Link,
}

#[derive(Debug)]
struct LookupParseErr;

impl FromStr for Lookup {
    type Err = LookupParseErr;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "pkg-config" => Ok(Lookup::PkgConfig),
            "link" => Ok(Lookup::Link),
            _ => Err(LookupParseErr),
        }
    }
}

fn env_var_append<V: AsRef<OsStr>>(key: &str, value: V) {
    let value = value.as_ref();
    let mut v = if let Some(v) = std::env::var_os(value) {
        v
    } else {
        std::env::set_var(key, value);
        return;
    };

    if v.is_empty() {
        std::env::set_var(key, value);
        return;
    }

    v.push(":");
    v.push(value);
    std::env::set_var(key, v);
}

fn main() {
    // openzfs on osx: fixed paths, under /usr/local/zfs (has pkg-config for libzfs_core)

    let target_os = var("CARGO_CFG_TARGET_OS").expect("Could not get env var CARGO_CFG_TARGET_OS");
    let mut build_env = build_env::BuildEnv::from_env().expect("Could not determine build_env");

    let lzc_libdir = build_env.var("LIBZFS_CORE_LIBDIR");
    let lzc_lookup = if lzc_libdir.as_ref().is_some() {
        // Implies users want `LIBZFS_CORE_LOOKUP_WITH=link`
        Lookup::Link
    } else {
        let lookup_with = build_env.var("LIBZFS_CORE_LOOKUP_WITH");
        let lookup_with: Option<Lookup> = lookup_with.map(|v| v.to_str().unwrap().parse().unwrap());

        lookup_with.unwrap_or_else(|| match target_os.as_str() {
            // users have reported that this is required for freebsd. I have not tested it.
            "freebsd" => Lookup::Link,

            // openzfs on osx has the `libzfs_core.pc` file, installed into
            // `/usr/local/zfs/lib/pkgconfig`. Users _must_ ensure this is part of their
            // `PKG_CONFIG_PATH`. Note that when cross compiling, this may cause some difficulty,
            // because the `pkg-config` crate doesn't allow distinguishing right now. We could
            // workaround this by hacking up std::env ourselves, or ideally the pkg-config crate would
            // use a build-env style lookup to pick the right `PKG_CONFIG_PATH` itself.
            //
            // Right now, if the link method is _not_ supplied, we tweak PKG_CONFIG_PATH so things
            // will automatically work in the common case (with openzfs on osx 2.01 at least)
            //
            // This will almost certainly behave poorly in the case of cross compilation, where
            // users should probably specify a `LIBZFS_CORE_LOOKUP_WITH` explicitly.
            "macos" => {
                let pc_path = PathBuf::from_str("/usr/local/zfs/lib/pkgconfig").unwrap();
                if pc_path.exists() {
                    env_var_append("PKG_CONFIG_PATH", pc_path);
                }
                Lookup::PkgConfig
            }
            //
            // zfs on linux: use pkg-config for libzfs_core (no pc for nvpair)
            // default to true otherwise.
            _ => Lookup::PkgConfig,
        })
    };

    match lzc_lookup {
        Lookup::PkgConfig => {
            pkg_config::probe_library("libzfs_core").unwrap();
        }
        Lookup::Link => {
            if let Some(v) = lzc_libdir {
                println!("cargo:rustc-link-search=native={}", v.to_str().unwrap());
            }
            println!("cargo:rustc-link-lib=zfs_core");
        }
    }

    // FIXME: we don't provide a way to specify the search path for nvpair. One can add search
    // paths with RUSTFLAGS or some cargo.toml build target hacking. Consider if we should either
    // rely on that mechanism entirely (even for libzfs_core), or add a LIB_DIR env var for
    // nvpair/zutil/etc
    //
    // there is currently no nvpair pkg-config, so unconditionally link
    if target_os == "macos" {
        // TODO: this is an openzfs on osx specific path. Provide a way to disable
        println!("cargo:rustc-link-search=native=/usr/local/zfs/lib");
    }
    println!("cargo:rustc-link-lib=nvpair");
    if target_os == "freebsd" {
        println!("cargo:rustc-link-lib=dylib:-as-needed=zutil");
    }
}