Skip to content

Commit b59e5db

Browse files
authored
Merge pull request #1524 from RReverser/wasi
Support arbitrary targets
2 parents b1f9555 + 87a5e2c commit b59e5db

File tree

6 files changed

+111
-83
lines changed

6 files changed

+111
-83
lines changed

src/bindgen.rs

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use std::process::Command;
1212
/// Run the `wasm-bindgen` CLI to generate bindings for the current crate's
1313
/// `.wasm`.
1414
pub fn wasm_bindgen_build(
15+
wasm_path: &str,
1516
data: &CrateData,
1617
install_status: &install::Status,
1718
out_dir: &Path,
@@ -21,31 +22,9 @@ pub fn wasm_bindgen_build(
2122
reference_types: bool,
2223
target: Target,
2324
profile: BuildProfile,
24-
extra_options: &Vec<String>,
2525
) -> Result<()> {
26-
let profile_name = match profile.clone() {
27-
BuildProfile::Release | BuildProfile::Profiling => "release",
28-
BuildProfile::Dev => "debug",
29-
BuildProfile::Custom(profile_name) => &profile_name.clone(),
30-
};
31-
3226
let out_dir = out_dir.to_str().unwrap();
3327

34-
let target_directory = {
35-
let mut has_target_dir_iter = extra_options.iter();
36-
has_target_dir_iter
37-
.find(|&it| it == "--target-dir")
38-
.and_then(|_| has_target_dir_iter.next())
39-
.map(Path::new)
40-
.unwrap_or(data.target_directory())
41-
};
42-
43-
let wasm_path = target_directory
44-
.join("wasm32-unknown-unknown")
45-
.join(profile_name)
46-
.join(data.crate_name())
47-
.with_extension("wasm");
48-
4928
let dts_arg = if disable_dts {
5029
"--no-typescript"
5130
} else {

src/build/mod.rs

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ use crate::emoji;
66
use crate::manifest::Crate;
77
use crate::PBAR;
88
use anyhow::{anyhow, bail, Context, Result};
9+
use cargo_metadata::Message;
10+
use std::io::BufReader;
911
use std::path::Path;
10-
use std::process::Command;
12+
use std::process::{Command, Stdio};
1113
use std::str;
1214

1315
pub mod wasm_target;
@@ -72,12 +74,12 @@ fn wasm_pack_local_version() -> Option<String> {
7274
Some(output.to_string())
7375
}
7476

75-
/// Run `cargo build` targetting `wasm32-unknown-unknown`.
77+
/// Run `cargo build` for Wasm with config derived from the given `BuildProfile`.
7678
pub fn cargo_build_wasm(
7779
path: &Path,
7880
profile: BuildProfile,
7981
extra_options: &[String],
80-
) -> Result<()> {
82+
) -> Result<String> {
8183
let msg = format!("{}Compiling to Wasm...", emoji::CYCLONE);
8284
PBAR.info(&msg);
8385

@@ -109,7 +111,9 @@ pub fn cargo_build_wasm(
109111
}
110112
}
111113

112-
cmd.arg("--target").arg("wasm32-unknown-unknown");
114+
// If user has specified a custom --target in Cargo options, we shouldn't override it.
115+
// Otherwise, default to wasm32-unknown-unknown.
116+
cmd.env("CARGO_BUILD_TARGET", "wasm32-unknown-unknown");
113117

114118
// The `cargo` command is executed inside the directory at `path`, so relative paths set via extra options won't work.
115119
// To remedy the situation, all detected paths are converted to absolute paths.
@@ -132,8 +136,47 @@ pub fn cargo_build_wasm(
132136
.collect::<Result<Vec<_>>>()?;
133137
cmd.args(extra_options_with_absolute_paths);
134138

135-
child::run(cmd, "cargo build").context("Compiling your crate to WebAssembly failed")?;
136-
Ok(())
139+
cmd.arg("--message-format=json");
140+
141+
let mut cargo_process = cmd.stdout(Stdio::piped()).spawn()?;
142+
143+
let final_artifact =
144+
Message::parse_stream(BufReader::new(cargo_process.stdout.as_mut().unwrap()))
145+
.filter_map(|msg| {
146+
match msg {
147+
Ok(Message::CompilerArtifact(artifact)) => return Some(artifact),
148+
Ok(Message::CompilerMessage(msg)) => eprintln!("{msg}"),
149+
Ok(Message::TextLine(text)) => eprintln!("{text}"),
150+
Err(err) => log::error!("Couldn't parse cargo message: {err}"),
151+
_ => {} // ignore messages irrelevant to the user
152+
}
153+
None
154+
})
155+
.last();
156+
157+
if !cargo_process
158+
.wait()
159+
.context("Failed to wait for cargo build process")?
160+
.success()
161+
{
162+
bail!("`cargo build` failed, see the output above for details");
163+
}
164+
165+
let wasm_files: Vec<_> = final_artifact
166+
.context("Expected at least one compiler artifact in the output of `cargo build`")?
167+
.filenames
168+
.into_iter()
169+
.filter(|path| path.extension() == Some("wasm"))
170+
.collect();
171+
172+
match <[_; 1]>::try_from(wasm_files) {
173+
Ok([filename]) => Ok(filename.into_string()),
174+
Err(filenames) => {
175+
bail!(
176+
"Expected exactly one .wasm file in the compiler artifact, but found {filenames:?}"
177+
)
178+
}
179+
}
137180
}
138181

139182
/// Runs `cargo build --tests` targeting `wasm32-unknown-unknown`.
@@ -162,7 +205,7 @@ pub fn cargo_build_wasm_tests(path: &Path, debug: bool, extra_options: &[String]
162205
cmd.arg("--release");
163206
}
164207

165-
cmd.arg("--target").arg("wasm32-unknown-unknown");
208+
cmd.env("CARGO_BUILD_TARGET", "wasm32-unknown-unknown");
166209

167210
cmd.args(extra_options);
168211

src/build/wasm_target.rs

Lines changed: 29 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,27 @@ use std::fmt;
1010
use std::path::PathBuf;
1111
use std::process::Command;
1212

13-
struct Wasm32Check {
13+
struct Wasm32Check<'target> {
14+
target: &'target str,
1415
rustc_path: PathBuf,
1516
sysroot: PathBuf,
1617
found: bool,
1718
is_rustup: bool,
1819
}
1920

20-
impl fmt::Display for Wasm32Check {
21+
impl fmt::Display for Wasm32Check<'_> {
2122
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
22-
let target = "wasm32-unknown-unknown";
23-
2423
if !self.found {
2524
let rustup_string = if self.is_rustup {
2625
"It looks like Rustup is being used.".to_owned()
2726
} else {
28-
format!("It looks like Rustup is not being used. For non-Rustup setups, the {} target needs to be installed manually. See https://drager.github.io/wasm-pack/book/prerequisites/non-rustup-setups.html on how to do this.", target)
27+
format!("It looks like Rustup is not being used. For non-Rustup setups, the {} target needs to be installed manually. See https://drager.github.io/wasm-pack/book/prerequisites/non-rustup-setups.html on how to do this.", self.target)
2928
};
3029

3130
writeln!(
3231
f,
3332
"{} target not found in sysroot: {:?}",
34-
target, self.sysroot
33+
self.target, self.sysroot
3534
)
3635
.and_then(|_| {
3736
writeln!(
@@ -51,14 +50,14 @@ impl fmt::Display for Wasm32Check {
5150
}
5251
}
5352

54-
/// Ensure that `rustup` has the `wasm32-unknown-unknown` target installed for
53+
/// Ensure that `rustup` has the requested target installed for
5554
/// current toolchain
56-
pub fn check_for_wasm32_target() -> Result<()> {
55+
pub fn check_for_wasm_target(target: &str) -> Result<()> {
5756
let msg = format!("{}Checking for the Wasm target...", emoji::TARGET);
5857
PBAR.info(&msg);
5958

6059
// Check if wasm32 target is present, otherwise bail.
61-
match check_wasm32_target() {
60+
match check_target(target) {
6261
Ok(ref wasm32_check) if wasm32_check.found => Ok(()),
6362
Ok(wasm32_check) => bail!("{}", wasm32_check),
6463
Err(err) => Err(err),
@@ -81,43 +80,32 @@ fn get_rustc_sysroot() -> Result<PathBuf> {
8180
}
8281
}
8382

84-
/// Get wasm32-unknown-unknown target libdir
85-
fn get_rustc_wasm32_unknown_unknown_target_libdir() -> Result<PathBuf> {
83+
/// Get target libdir
84+
fn get_rustc_target_libdir(target: &str) -> Result<PathBuf> {
8685
let command = Command::new("rustc")
87-
.args(&[
88-
"--target",
89-
"wasm32-unknown-unknown",
90-
"--print",
91-
"target-libdir",
92-
])
86+
.args(&["--target", target, "--print", "target-libdir"])
9387
.output()?;
9488

9589
if command.status.success() {
9690
Ok(String::from_utf8(command.stdout)?.trim().into())
9791
} else {
9892
Err(anyhow!(
99-
"Getting rustc's wasm32-unknown-unknown target wasn't successful. Got {}",
93+
"Getting rustc's {target} target wasn't successful. Got {}",
10094
command.status
10195
))
10296
}
10397
}
10498

105-
fn does_wasm32_target_libdir_exist() -> bool {
106-
let result = get_rustc_wasm32_unknown_unknown_target_libdir();
99+
fn does_target_libdir_exist(target: &str) -> bool {
100+
let result = get_rustc_target_libdir(target);
107101

108102
match result {
109-
Ok(wasm32_target_libdir_path) => {
110-
if wasm32_target_libdir_path.exists() {
111-
info!(
112-
"Found wasm32-unknown-unknown in {:?}",
113-
wasm32_target_libdir_path
114-
);
103+
Ok(target_libdir_path) => {
104+
if target_libdir_path.exists() {
105+
info!("Found {target} in {:?}", target_libdir_path);
115106
true
116107
} else {
117-
info!(
118-
"Failed to find wasm32-unknown-unknown in {:?}",
119-
wasm32_target_libdir_path
120-
);
108+
info!("Failed to find {target} in {:?}", target_libdir_path);
121109
false
122110
}
123111
}
@@ -128,12 +116,13 @@ fn does_wasm32_target_libdir_exist() -> bool {
128116
}
129117
}
130118

131-
fn check_wasm32_target() -> Result<Wasm32Check> {
119+
fn check_target(target: &'_ str) -> Result<Wasm32Check<'_>> {
132120
let sysroot = get_rustc_sysroot()?;
133121
let rustc_path = which::which("rustc")?;
134122

135-
if does_wasm32_target_libdir_exist() {
123+
if does_target_libdir_exist(target) {
136124
Ok(Wasm32Check {
125+
target,
137126
rustc_path,
138127
sysroot,
139128
found: true,
@@ -142,16 +131,18 @@ fn check_wasm32_target() -> Result<Wasm32Check> {
142131
// If it doesn't exist, then we need to check if we're using rustup.
143132
} else {
144133
// If sysroot contains "rustup", then we can assume we're using rustup
145-
// and use rustup to add the wasm32-unknown-unknown target.
134+
// and use rustup to add the requested target.
146135
if sysroot.to_string_lossy().contains("rustup") {
147-
rustup_add_wasm_target().map(|()| Wasm32Check {
136+
rustup_add_wasm_target(target).map(|()| Wasm32Check {
137+
target,
148138
rustc_path,
149139
sysroot,
150140
found: true,
151141
is_rustup: true,
152142
})
153143
} else {
154144
Ok(Wasm32Check {
145+
target,
155146
rustc_path,
156147
sysroot,
157148
found: false,
@@ -161,11 +152,11 @@ fn check_wasm32_target() -> Result<Wasm32Check> {
161152
}
162153
}
163154

164-
/// Add wasm32-unknown-unknown using `rustup`.
165-
fn rustup_add_wasm_target() -> Result<()> {
155+
/// Add target using `rustup`.
156+
fn rustup_add_wasm_target(target: &str) -> Result<()> {
166157
let mut cmd = Command::new("rustup");
167-
cmd.arg("target").arg("add").arg("wasm32-unknown-unknown");
168-
child::run(cmd, "rustup").context("Adding the wasm32-unknown-unknown target with rustup")?;
158+
cmd.arg("target").arg("add").arg(target);
159+
child::run(cmd, "rustup").with_context(|| format!("Adding the {target} target with rustup"))?;
169160

170161
Ok(())
171162
}

src/child.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
//! This module helps us ensure that all child processes that we spawn get
44
//! properly logged and their output is logged as well.
55
6-
use crate::install::Tool;
76
use anyhow::{bail, Result};
87
use log::info;
98
use std::process::{Command, Stdio};
@@ -43,7 +42,10 @@ pub fn run(mut command: Command, command_name: &str) -> Result<()> {
4342
}
4443

4544
/// Run the given command and return its stdout.
46-
pub fn run_capture_stdout(mut command: Command, command_name: &Tool) -> Result<String> {
45+
pub fn run_capture_stdout(
46+
mut command: Command,
47+
command_name: impl std::fmt::Display,
48+
) -> Result<String> {
4749
info!("Running {:?}", command);
4850

4951
let output = command

0 commit comments

Comments
 (0)