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
// This file is part of Gear.

// Copyright (C) 2022 Gear Technologies Inc.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use anyhow::Result;
use std::{env, process};

use crate::cargo_command::CargoCommand;
use crate::wasm_project::WasmProject;

mod builder_error;
mod cargo_command;
mod crate_info;
mod stack_end;
mod wasm_project;

pub use stack_end::insert_stack_end_export;

/// WASM building tool.
pub struct WasmBuilder {
    wasm_project: WasmProject,
    cargo: CargoCommand,
}

impl WasmBuilder {
    /// Create a new `WasmBuilder`.
    pub fn new() -> Self {
        WasmBuilder {
            wasm_project: WasmProject::new(),
            cargo: CargoCommand::new(),
        }
    }

    /// Build the program and produce an output WASM binary.
    pub fn build(self) {
        if env::var(self.cargo.skip_build_env()).is_ok() {
            return;
        }
        if let Err(e) = self.build_project() {
            eprintln!("error: {}", e);
            e.chain()
                .skip(1)
                .for_each(|cause| eprintln!("|      {}", cause));
            process::exit(1);
        }
    }

    fn build_project(mut self) -> Result<()> {
        // TODO: Check nightly toolchain
        self.wasm_project.generate()?;
        self.cargo
            .set_manifest_path(self.wasm_project.manifest_path());
        self.cargo
            .set_profile(self.wasm_project.profile().to_string());
        self.cargo.run()?;
        self.wasm_project.postprocess()
    }
}

impl Default for WasmBuilder {
    fn default() -> Self {
        Self::new()
    }
}

/// Shorthand function to be used in `build.rs`.
pub fn build() {
    WasmBuilder::new().build();
}