fork of https://github.com/rustwasm/wasm-pack for the needs of NextGraph.org
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
174 lines
5.7 KiB
174 lines
5.7 KiB
//! Building a Rust crate into a `.wasm` binary.
|
|
|
|
use child;
|
|
use command::build::BuildProfile;
|
|
use emoji;
|
|
use failure::{Error, ResultExt};
|
|
use log::info;
|
|
use progressbar::Step;
|
|
use std::path::{Path, PathBuf};
|
|
use std::process::Command;
|
|
use std::str;
|
|
use PBAR;
|
|
|
|
/// Ensure that `rustc` is present and that it is >= 1.30.0
|
|
pub fn check_rustc_version(step: &Step) -> Result<String, Error> {
|
|
let msg = format!("{}Checking `rustc` version...", emoji::CRAB);
|
|
PBAR.step(step, &msg);
|
|
let local_minor_version = rustc_minor_version();
|
|
match local_minor_version {
|
|
Some(mv) => {
|
|
if mv < 30 {
|
|
bail!(
|
|
"Your version of Rust, '1.{}', is not supported. Please install Rust version 1.30.0 or higher.",
|
|
mv.to_string()
|
|
)
|
|
} else {
|
|
Ok(mv.to_string())
|
|
}
|
|
}
|
|
None => bail!("We can't figure out what your Rust version is- which means you might not have Rust installed. Please install Rust version 1.30.0 or higher."),
|
|
}
|
|
}
|
|
|
|
// from https://github.com/alexcrichton/proc-macro2/blob/79e40a113b51836f33214c6d00228934b41bd4ad/build.rs#L44-L61
|
|
fn rustc_minor_version() -> Option<u32> {
|
|
macro_rules! otry {
|
|
($e:expr) => {
|
|
match $e {
|
|
Some(e) => e,
|
|
None => return None,
|
|
}
|
|
};
|
|
}
|
|
let output = otry!(Command::new("rustc").arg("--version").output().ok());
|
|
let version = otry!(str::from_utf8(&output.stdout).ok());
|
|
let mut pieces = version.split('.');
|
|
if pieces.next() != Some("rustc 1") {
|
|
return None;
|
|
}
|
|
otry!(pieces.next()).parse().ok()
|
|
}
|
|
|
|
/// Get rustc's sysroot as a PathBuf
|
|
fn get_rustc_sysroot() -> Result<PathBuf, Error> {
|
|
let command = Command::new("rustc")
|
|
.args(&["--print", "sysroot"])
|
|
.output()?;
|
|
|
|
if command.status.success() {
|
|
Ok(String::from_utf8(command.stdout)?.trim().into())
|
|
} else {
|
|
Err(format_err!(
|
|
"Getting rustc's sysroot wasn't successful. Got {}",
|
|
command.status
|
|
))
|
|
}
|
|
}
|
|
|
|
/// Checks if the wasm32-unknown-unknown is present in rustc's sysroot.
|
|
fn is_wasm32_target_in_sysroot(sysroot: &PathBuf) -> bool {
|
|
let wasm32_target = "wasm32-unknown-unknown";
|
|
|
|
let rustlib_path = sysroot.join("lib/rustlib");
|
|
|
|
info!("Looking for {} in {:?}", wasm32_target, rustlib_path);
|
|
|
|
if rustlib_path.join(wasm32_target).exists() {
|
|
info!("Found {} in {:?}", wasm32_target, rustlib_path);
|
|
true
|
|
} else {
|
|
info!("Failed to find {} in {:?}", wasm32_target, rustlib_path);
|
|
false
|
|
}
|
|
}
|
|
|
|
fn check_wasm32_target() -> Result<bool, Error> {
|
|
let sysroot = get_rustc_sysroot()?;
|
|
|
|
// If wasm32-unknown-unknown already exists we're ok.
|
|
if is_wasm32_target_in_sysroot(&sysroot) {
|
|
Ok(true)
|
|
// If it doesn't exist, then we need to check if we're using rustup.
|
|
} else {
|
|
// If sysroot contains .rustup, then we can assume we're using rustup
|
|
// and use rustup to add the wasm32-unknown-unknown target.
|
|
if sysroot.to_string_lossy().contains(".rustup") {
|
|
rustup_add_wasm_target().map(|()| true)
|
|
} else {
|
|
Ok(false)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Add wasm32-unknown-unknown using `rustup`.
|
|
fn rustup_add_wasm_target() -> Result<(), Error> {
|
|
let mut cmd = Command::new("rustup");
|
|
cmd.arg("target").arg("add").arg("wasm32-unknown-unknown");
|
|
child::run(cmd, "rustup").context("Adding the wasm32-unknown-unknown target with rustup")?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Ensure that `rustup` has the `wasm32-unknown-unknown` target installed for
|
|
/// current toolchain
|
|
pub fn check_for_wasm32_target(step: &Step) -> Result<(), Error> {
|
|
let msg = format!("{}Checking for the Wasm target...", emoji::TARGET);
|
|
PBAR.step(step, &msg);
|
|
|
|
// Check if wasm32 target is present, otherwise bail.
|
|
match check_wasm32_target() {
|
|
Ok(true) => Ok(()),
|
|
Ok(false) => bail!("wasm32-unknown-unknown target not found!"),
|
|
Err(err) => Err(err),
|
|
}
|
|
}
|
|
|
|
/// Run `cargo build` targetting `wasm32-unknown-unknown`.
|
|
pub fn cargo_build_wasm(
|
|
path: &Path,
|
|
profile: BuildProfile,
|
|
step: &Step,
|
|
extra_options: &Vec<String>,
|
|
) -> Result<(), Error> {
|
|
let msg = format!("{}Compiling to Wasm...", emoji::CYCLONE);
|
|
PBAR.step(step, &msg);
|
|
let mut cmd = Command::new("cargo");
|
|
cmd.current_dir(path).arg("build").arg("--lib");
|
|
match profile {
|
|
BuildProfile::Profiling => {
|
|
// Once there are DWARF debug info consumers, force enable debug
|
|
// info, because builds that use the release cargo profile disables
|
|
// debug info.
|
|
//
|
|
// cmd.env("RUSTFLAGS", "-g");
|
|
cmd.arg("--release");
|
|
}
|
|
BuildProfile::Release => {
|
|
cmd.arg("--release");
|
|
}
|
|
BuildProfile::Dev => {
|
|
// Plain cargo builds use the dev cargo profile, which includes
|
|
// debug info by default.
|
|
}
|
|
}
|
|
cmd.arg("--target").arg("wasm32-unknown-unknown");
|
|
cmd.args(extra_options);
|
|
child::run(cmd, "cargo build").context("Compiling your crate to WebAssembly failed")?;
|
|
Ok(())
|
|
}
|
|
|
|
/// Run `cargo build --tests` targetting `wasm32-unknown-unknown`.
|
|
///
|
|
/// This generates the `Cargo.lock` file that we use in order to know which version of
|
|
/// wasm-bindgen-cli to use when running tests.
|
|
pub fn cargo_build_wasm_tests(path: &Path, debug: bool) -> Result<(), Error> {
|
|
let mut cmd = Command::new("cargo");
|
|
cmd.current_dir(path).arg("build").arg("--tests");
|
|
if !debug {
|
|
cmd.arg("--release");
|
|
}
|
|
cmd.arg("--target").arg("wasm32-unknown-unknown");
|
|
child::run(cmd, "cargo build").context("Compilation of your program failed")?;
|
|
Ok(())
|
|
}
|
|
|