-
-
Notifications
You must be signed in to change notification settings - Fork 97
/
build.rs
124 lines (105 loc) · 3.6 KB
/
build.rs
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
119
120
121
122
123
124
use std::{
collections::HashMap,
env::{self, VarError},
};
use git2::{DescribeOptions, Repository};
use serde::Deserialize;
fn main() {
features_env();
target_envs();
git_envs();
}
/// Builds the `CARGO_FEATURES` environment variable.
///
/// This function turns enabled cargo features into a simple string
/// `+feature1 +feature2 +featureN`, which then exposes it via the
/// `CARGO_FEATURES` environment variable.
///
/// It first reads and parses the Cargo.toml in order to extract all
/// available features (omitting "default"). It then checks for
/// enabled features via `CARGO_FEATURE_<name>` to finally collect
/// them into a string.
fn features_env() {
#[derive(Deserialize)]
struct Config {
features: HashMap<String, Vec<String>>,
}
impl Config {
fn enabled_features(self) -> impl Iterator<Item = String> {
self.features
.into_keys()
.filter(|feature| feature != "default")
.filter(|feature| {
let feature = feature.replace('-', "_").to_uppercase();
env::var(format!("CARGO_FEATURE_{feature}")).is_ok()
})
}
}
let config: Config =
toml::from_str(include_str!("./Cargo.toml")).expect("should parse Cargo.toml");
let mut features = String::new();
for feature in config.enabled_features() {
if !features.is_empty() {
features.push(' ');
}
features.push_str(&format!("+{feature}"));
}
println!("cargo::rustc-env=CARGO_FEATURES={features}");
}
/// Builds environment variables related to the target platform.
///
/// This function basically forwards existing cargo environments
/// related to the target platform.
fn target_envs() {
forward_env("CARGO_CFG_TARGET_OS");
forward_env("CARGO_CFG_TARGET_ENV");
forward_env("CARGO_CFG_TARGET_ARCH");
}
/// Builds environment variables related to git.
///
/// This function basically tries to forward existing git environment
/// variables. In case of failure, it tries to build them using
/// [`git2`].
fn git_envs() {
// skip the process if the current directory is not a git
// repository (for example, from a nix build root jail)
let Ok(git) = Repository::open(".") else {
return;
};
if try_forward_env("GIT_DESCRIBE").is_err() {
let mut opts = DescribeOptions::new();
opts.describe_all();
opts.show_commit_oid_as_fallback(true);
let description = git
.describe(&opts)
.expect("should describe git object")
.format(None)
.expect("should format git object description");
println!("cargo::rustc-env=GIT_DESCRIBE={description}");
};
if try_forward_env("GIT_REV").is_err() {
let head = git.head().expect("should get git HEAD");
let commit = head.peel_to_commit().expect("should get git HEAD commit");
let rev = commit.id().to_string();
println!("cargo::rustc-env=GIT_REV={rev}");
};
}
/// Tries to forward the given environment variable.
///
/// For a more strict version, see [`forward_env`].
fn try_forward_env(key: &str) -> Result<String, VarError> {
let env = env::var(key);
if let Ok(val) = &env {
println!("cargo::rustc-env={key}={val}");
}
env
}
/// Forwards the given environment variable.
///
/// This function panics in case the forward fails (when the
/// environment variable does not exist for example).
///
/// For a less strict version, see [`try_forward_env`].
fn forward_env(key: &str) {
try_forward_env(key).expect(&format!("should get env {key}"));
}