-
Notifications
You must be signed in to change notification settings - Fork 89
Expand file tree
/
Copy pathbuild.rs
More file actions
232 lines (201 loc) · 8.32 KB
/
build.rs
File metadata and controls
232 lines (201 loc) · 8.32 KB
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
use fil_actor_bundler::Bundler;
use fil_actors_runtime::runtime::builtins::Type;
use num_traits::cast::FromPrimitive;
use std::error::Error;
use std::io::{BufRead, BufReader};
use std::path::Path;
use std::process::{Command, Stdio};
use std::thread;
/// Cargo package for an actor.
type Package = str;
/// Technical identifier for the actor in legacy CodeCIDs and else.
type ID = str;
const ACTORS: &[(&Package, &ID)] = &[
("system", "system"),
("init", "init"),
("cron", "cron"),
("account", "account"),
("power", "storagepower"),
("miner", "storageminer"),
("market", "storagemarket"),
("paych", "paymentchannel"),
("multisig", "multisig"),
("reward", "reward"),
("verifreg", "verifiedregistry"),
("datacap", "datacap"),
("placeholder", "placeholder"),
("evm", "evm"),
("eam", "eam"),
("ethaccount", "ethaccount"),
];
const NETWORK_ENV: &str = "BUILD_FIL_NETWORK";
/// Returns the configured network name, checking both the environment and feature flags.
fn network_name() -> String {
let env_network = std::env::var_os(NETWORK_ENV);
let feat_network = if cfg!(feature = "mainnet") {
Some("mainnet")
} else if cfg!(feature = "caterpillarnet") {
Some("caterpillarnet")
} else if cfg!(feature = "butterflynet") {
Some("butterflynet")
} else if cfg!(feature = "calibrationnet") {
Some("calibrationnet")
} else if cfg!(feature = "devnet") {
Some("devnet")
} else if cfg!(feature = "testing") {
Some("testing")
} else if cfg!(feature = "testing-fake-proofs") {
Some("testing-fake-proofs")
} else {
None
};
// Make sure they match if they're both set. Otherwise, pick the one
// that's set, or fallback on "mainnet".
match (feat_network, &env_network) {
(Some(from_feature), Some(from_env)) => {
assert_eq!(from_feature, from_env, "different target network configured via the features than via the {} environment variable", NETWORK_ENV);
from_feature
}
(Some(net), None) => net,
(None, Some(net)) => net.to_str().expect("network name not utf8"),
(None, None) => "mainnet",
}.to_owned()
}
// To support EIP 2537 we compile blst library directly into evm actor
// This requires a C => wasm32-unknown-unknown clang
// Note that emcc while support by blst is not an option for us as it cannot
// target wasm32-unknown-unknown
fn check_c_compiler_does_wasm() {
// If CC is not set, default to "clang", else use the value from the environment.
let cc = match std::env::var_os("CC") {
Some(val) => val,
None => "clang".into(),
};
// First check cc actually runs / is in path
let version_check = std::process::Command::new(&cc).arg("--version").output();
if version_check.is_err() || !version_check.as_ref().unwrap().status.success() {
eprintln!(
"error: could not run C compiler '{}'.\n\
Please ensure clang is installed and in your PATH, or set CC to a working clang binary.",
cc.to_string_lossy()
);
std::process::exit(1);
}
// Then check that the compiler supports wasm32 target
let targets_check = std::process::Command::new(&cc).arg("--print-targets").output();
let has_wasm32 = match targets_check {
Ok(output) if output.status.success() => {
let targets = String::from_utf8_lossy(&output.stdout);
targets.lines().any(|line| line.trim().contains("wasm32"))
}
_ => false,
};
if !has_wasm32 {
eprintln!(
"error: C compiler '{}' does not support wasm32-unknown-unknown target.\n\
Install LLVM/Clang with wasm32 support \n",
cc.to_string_lossy()
);
std::process::exit(1);
}
}
fn main() -> Result<(), Box<dyn Error>> {
// Cargo executable location.
let cargo = std::env::var_os("CARGO").expect("no CARGO env var");
println!("cargo:warning=cargo: {:?}", &cargo);
check_c_compiler_does_wasm();
let out_dir = std::env::var_os("OUT_DIR")
.as_ref()
.map(Path::new)
.map(|p| p.join("bundle"))
.expect("no OUT_DIR env var");
println!("cargo:warning=out_dir: {:?}", &out_dir);
// Compute the package names.
let packages =
ACTORS.iter().map(|(pkg, _)| String::from("fil_actor_") + pkg).collect::<Vec<String>>();
let manifest_path =
Path::new(&std::env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR unset"))
.join("Cargo.toml");
println!("cargo:warning=manifest_path={:?}", &manifest_path);
// Determine the network name.
let network_name = network_name();
println!("cargo:warning=network name: {}", network_name);
// Make sure we re-build if the network name changes.
println!("cargo:rerun-if-env-changed={}", NETWORK_ENV);
// Rerun if the source, dependencies, build options, build script _or_ actors have changed. We
// need to check if the actors have changed because otherwise, when building in a workspace, we
// won't re-run the build script and therefore won't re-compile them.
//
// This _isn't_ an issue when building as a dependency fetched from crates.io (because the crate
// is immutable).
for file in ["actors", "Cargo.toml", "Cargo.lock", "src", "build.rs"] {
println!("cargo:rerun-if-changed={}", file);
}
// Cargo build command for all actors at once.
let mut cmd = Command::new(&cargo);
cmd.arg("build")
.args(packages.iter().map(|pkg| "-p=".to_owned() + pkg))
.arg("--target=wasm32-unknown-unknown")
.arg("--profile=wasm")
.arg("--locked")
.arg("--features=fil-actor")
.arg("--manifest-path=".to_owned() + manifest_path.to_str().unwrap())
.env(NETWORK_ENV, network_name)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
// We are supposed to only generate artifacts under OUT_DIR,
// so set OUT_DIR as the target directory for this build.
.env("CARGO_TARGET_DIR", &out_dir)
// As we are being called inside a build-script, this env variable is set. However, we set
// our own `RUSTFLAGS` and thus, we need to remove this. Otherwise cargo favors this
// env variable.
.env_remove("CARGO_ENCODED_RUSTFLAGS");
// Print out the command line we're about to run.
println!("cargo:warning=cmd={:?}", &cmd);
// Launch the command.
let mut child = cmd.spawn().expect("failed to launch cargo build");
// Pipe the output as cargo warnings. Unfortunately this is the only way to
// get cargo build to print the output.
let stdout = child.stdout.take().expect("no stdout");
let stderr = child.stderr.take().expect("no stderr");
let j1 = thread::spawn(move || {
for line in BufReader::new(stderr).lines() {
println!("cargo:warning={:?}", line.unwrap());
}
});
let j2 = thread::spawn(move || {
for line in BufReader::new(stdout).lines() {
println!("cargo:warning={:?}", line.unwrap());
}
});
j1.join().unwrap();
j2.join().unwrap();
let result = child.wait().expect("failed to wait for build to finish");
if !result.success() {
return Err("actor build failed".into());
}
let dst = Path::new(&out_dir).join("bundle.car");
let mut bundler = Bundler::new(&dst);
for (&(pkg, name), id) in ACTORS.iter().zip(1u32..) {
assert_eq!(
name,
Type::from_u32(id).expect("type not defined").name(),
"actor types don't match actors included in the bundle"
);
let bytecode_path = Path::new(&out_dir)
.join("wasm32-unknown-unknown/wasm")
.join(format!("fil_actor_{}.wasm", pkg));
// This actor version doesn't force synthetic CIDs; it uses genuine
// content-addressed CIDs.
let forced_cid = None;
let cid = bundler
.add_from_file(id, name.to_owned(), forced_cid, &bytecode_path)
.unwrap_or_else(|err| {
panic!("failed to add file {:?} to bundle for actor {}: {}", bytecode_path, id, err)
});
println!("cargo:warning=added {} ({}) to bundle with CID {}", name, id, cid);
}
bundler.finish().expect("failed to finish bundle");
println!("cargo:warning=bundle={}", dst.display());
Ok(())
}