Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/build.rs
1691 views
1
// Build script.
2
//
3
// This program is run by Cargo when building cranelift-codegen. It is used to generate Rust code from
4
// the language definitions in the cranelift-codegen/meta directory.
5
//
6
// Environment:
7
//
8
// OUT_DIR
9
// Directory where generated files should be placed.
10
//
11
// TARGET
12
// Target triple provided by Cargo.
13
//
14
// The build script expects to be run from the directory where this build.rs file lives. The
15
// current directory is used to find the sources.
16
17
use cranelift_codegen_meta as meta;
18
use cranelift_isle::error::Errors;
19
use meta::isle::IsleCompilation;
20
21
use std::env;
22
use std::io::Read;
23
use std::process;
24
use std::time::Instant;
25
26
fn main() {
27
let start_time = Instant::now();
28
29
let out_dir = env::var("OUT_DIR").expect("The OUT_DIR environment variable must be set");
30
let out_dir = std::path::Path::new(&out_dir);
31
let target_triple = env::var("TARGET").expect("The TARGET environment variable must be set");
32
33
let all_arch = env::var("CARGO_FEATURE_ALL_ARCH").is_ok();
34
let all_native_arch = env::var("CARGO_FEATURE_ALL_NATIVE_ARCH").is_ok();
35
36
let mut isas = meta::isa::Isa::all()
37
.iter()
38
.cloned()
39
.filter(|isa| {
40
let env_key = match isa {
41
meta::isa::Isa::Pulley32 | meta::isa::Isa::Pulley64 => {
42
"CARGO_FEATURE_PULLEY".to_string()
43
}
44
_ => format!("CARGO_FEATURE_{}", isa.to_string().to_uppercase()),
45
};
46
all_arch || env::var(env_key).is_ok()
47
})
48
.collect::<Vec<_>>();
49
50
// Don't require host isa if under 'all-arch' feature.
51
let host_isa = env::var("CARGO_FEATURE_HOST_ARCH").is_ok() && !all_native_arch;
52
53
if isas.is_empty() || host_isa {
54
// Try to match native target.
55
let target_name = target_triple.split('-').next().unwrap();
56
if let Ok(isa) = meta::isa_from_arch(&target_name) {
57
println!("cargo:rustc-cfg=feature=\"{isa}\"");
58
isas.push(isa);
59
}
60
}
61
62
let cur_dir = env::current_dir().expect("Can't access current working directory");
63
let crate_dir = cur_dir.as_path();
64
65
println!("cargo:rerun-if-changed=build.rs");
66
println!("cargo:rerun-if-env-changed=ISLE_SOURCE_DIR");
67
68
let isle_dir = if let Ok(path) = std::env::var("ISLE_SOURCE_DIR") {
69
// This will canonicalize any relative path in terms of the
70
// crate root, and will take any absolute path as overriding the
71
// `crate_dir`.
72
crate_dir.join(&path)
73
} else {
74
out_dir.into()
75
};
76
77
std::fs::create_dir_all(&isle_dir).expect("Could not create ISLE source directory");
78
79
if let Err(err) = meta::generate(&isas, &out_dir, &isle_dir) {
80
eprintln!("Error: {err}");
81
process::exit(1);
82
}
83
84
if &std::env::var("SKIP_ISLE").unwrap_or("0".to_string()) != "1" {
85
if let Err(err) = build_isle(crate_dir, &isle_dir) {
86
eprintln!("Error: {err}");
87
process::exit(1);
88
}
89
}
90
91
if env::var("CRANELIFT_VERBOSE").is_ok() {
92
for isa in &isas {
93
println!("cargo:warning=Includes support for {} ISA", isa.to_string());
94
}
95
println!(
96
"cargo:warning=Build step took {:?}.",
97
Instant::now() - start_time
98
);
99
println!("cargo:warning=Generated files are in {}", out_dir.display());
100
}
101
102
let pkg_version = env::var("CARGO_PKG_VERSION").unwrap();
103
let mut cmd = std::process::Command::new("git");
104
cmd.arg("rev-parse")
105
.arg("HEAD")
106
.stdout(std::process::Stdio::piped())
107
.current_dir(env::var("CARGO_MANIFEST_DIR").unwrap());
108
let version = if let Ok(mut child) = cmd.spawn() {
109
let mut git_rev = String::new();
110
child
111
.stdout
112
.as_mut()
113
.unwrap()
114
.read_to_string(&mut git_rev)
115
.unwrap();
116
let status = child.wait().unwrap();
117
if status.success() {
118
let git_rev = git_rev.trim().chars().take(9).collect::<String>();
119
format!("{pkg_version}-{git_rev}")
120
} else {
121
// not a git repo
122
pkg_version
123
}
124
} else {
125
// git not available
126
pkg_version
127
};
128
std::fs::write(
129
std::path::Path::new(&out_dir).join("version.rs"),
130
format!(
131
"/// Version number of this crate. \n\
132
pub const VERSION: &str = \"{version}\";"
133
),
134
)
135
.unwrap();
136
}
137
138
/// Strip the current directory from the file paths, because `islec`
139
/// includes them in the generated source, and this helps us maintain
140
/// deterministic builds that don't include those local file paths.
141
fn make_isle_source_path_relative(
142
cur_dir: &std::path::Path,
143
filename: &std::path::Path,
144
) -> std::path::PathBuf {
145
if let Ok(suffix) = filename.strip_prefix(&cur_dir) {
146
suffix.to_path_buf()
147
} else {
148
filename.to_path_buf()
149
}
150
}
151
152
fn build_isle(
153
crate_dir: &std::path::Path,
154
isle_dir: &std::path::Path,
155
) -> Result<(), Box<dyn std::error::Error + 'static>> {
156
let cur_dir = std::env::current_dir()?;
157
let isle_compilations = meta::isle::get_isle_compilations(
158
&make_isle_source_path_relative(&cur_dir, &crate_dir),
159
&make_isle_source_path_relative(&cur_dir, &isle_dir),
160
);
161
162
let mut had_error = false;
163
for compilation in &isle_compilations.items {
164
for file in &compilation.inputs {
165
println!("cargo:rerun-if-changed={}", file.display());
166
}
167
168
if let Err(e) = run_compilation(compilation) {
169
had_error = true;
170
eprintln!("Error building ISLE files:");
171
eprintln!("{e:?}");
172
#[cfg(not(feature = "isle-errors"))]
173
{
174
eprintln!("To see a more detailed error report, run: ");
175
eprintln!();
176
eprintln!(" $ cargo check -p cranelift-codegen --features isle-errors");
177
eprintln!();
178
}
179
}
180
}
181
182
if had_error {
183
std::process::exit(1);
184
}
185
186
println!("cargo:rustc-env=ISLE_DIR={}", isle_dir.to_str().unwrap());
187
188
Ok(())
189
}
190
191
/// Build ISLE DSL source text into generated Rust code.
192
///
193
/// NB: This must happen *after* the `cranelift-codegen-meta` functions, since
194
/// it consumes files generated by them.
195
fn run_compilation(compilation: &IsleCompilation) -> Result<(), Errors> {
196
use cranelift_isle as isle;
197
198
eprintln!("Rebuilding {}", compilation.output.display());
199
200
let code = {
201
let file_paths = compilation
202
.inputs
203
.iter()
204
.chain(compilation.untracked_inputs.iter());
205
206
let mut options = isle::codegen::CodegenOptions::default();
207
// Because we include!() the generated ISLE source, we cannot
208
// put the global pragmas (`#![allow(...)]`) in the ISLE
209
// source itself; we have to put them in the source that
210
// include!()s it. (See
211
// https://github.com/rust-lang/rust/issues/47995.)
212
options.exclude_global_allow_pragmas = true;
213
214
if let Ok(out_dir) = std::env::var("OUT_DIR") {
215
options.prefixes.push(isle::codegen::Prefix {
216
prefix: out_dir,
217
name: "<OUT_DIR>".to_string(),
218
})
219
};
220
221
isle::compile::from_files(file_paths, &options)?
222
};
223
224
eprintln!(
225
"Writing ISLE-generated Rust code to {}",
226
compilation.output.display()
227
);
228
std::fs::write(&compilation.output, code)
229
.map_err(|e| Errors::from_io(e, "failed writing output"))?;
230
231
Ok(())
232
}
233
234