Newer
Older
// Copyright 2018-2021 Parity Technologies (UK) Ltd.
// This file is part of cargo-contract.
// cargo-contract 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.
//
// cargo-contract 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 cargo-contract. If not, see <http://www.gnu.org/licenses/>.
Andrew Jones
committed
use crate::{
maybe_println, util, validate_wasm,
workspace::{Manifest, ManifestPath, Profile, Workspace},
BuildArtifacts, BuildMode, BuildResult, OptimizationPasses, OptimizationResult, UnstableFlags,
UnstableOptions, Verbosity, VerbosityFlags,
Andrew Jones
committed
};
use anyhow::{Context, Result};
use parity_wasm::elements::{External, Internal, MemoryType, Module, Section};
use std::{
convert::TryFrom,
ffi::OsStr,
fs::metadata,
path::{Path, PathBuf},
process::Command,
str,
};
/// This is the maximum number of pages available for a contract to allocate.
const MAX_MEMORY_PAGES: u32 = 16;
/// Executes build of the smart-contract which produces a wasm binary that is ready for deploying.
///
/// It does so by invoking `cargo build` and then post processing the final binary.
#[derive(Debug, StructOpt)]
#[structopt(name = "build")]
pub struct BuildCommand {
/// Path to the Cargo.toml of the contract to build
#[structopt(long, parse(from_os_str))]
manifest_path: Option<PathBuf>,
/// By default the contract is compiled with debug functionality
/// included. This enables the contract to output debug messages,
/// but increases the contract size and the amount of gas used.
///
/// A production contract should always be build in `release` mode!
/// Then no debug functionality is compiled into the contract.
#[structopt(long = "--release")]
build_release: bool,
/// Which build artifacts to generate.
///
/// - `all`: Generate the Wasm, the metadata and a bundled `<name>.contract` file.
///
/// - `code-only`: Only the Wasm is created, generation of metadata and a bundled
/// `<name>.contract` file is skipped.
#[structopt(
long = "generate",
default_value = "all",
value_name = "all | code-only",
verbatim_doc_comment
)]
build_artifact: BuildArtifacts,
#[structopt(flatten)]
verbosity: VerbosityFlags,
#[structopt(flatten)]
unstable_options: UnstableOptions,
/// Number of optimization passes, passed as an argument to wasm-opt.
///
/// - `0`: execute no optimization passes
///
/// - `1`: execute 1 optimization pass (quick & useful opts, useful for iteration builds)
///
/// - `2`, execute 2 optimization passes (most opts, generally gets most perf)
///
/// - `3`, execute 3 optimization passes (spends potentially a lot of time optimizing)
///
/// - `4`, execute 4 optimization passes (also flatten the IR, which can take a lot more time and memory
/// but is useful on more nested / complex / less-optimized input)
///
/// - `s`, execute default optimization passes, focusing on code size
///
/// - `z`, execute default optimization passes, super-focusing on code size
///
/// - The default value is `z`
///
/// - It is possible to define the number of optimization passes in the
/// `[package.metadata.contract]` of your `Cargo.toml` as e.g. `optimization-passes = "3"`.
/// The CLI argument always takes precedence over the profile value.
optimization_passes: Option<OptimizationPasses>,
/// Do not remove symbols (Wasm name section) when optimizing.
///
/// This is useful if one wants to analyze or debug the optimized binary.
#[structopt(long)]
keep_debug_symbols: bool,
}
impl BuildCommand {
pub fn exec(&self) -> Result<BuildResult> {
let manifest_path = ManifestPath::try_from(self.manifest_path.as_ref())?;
let unstable_flags: UnstableFlags =
TryFrom::<&UnstableOptions>::try_from(&self.unstable_options)?;
let verbosity = TryFrom::<&VerbosityFlags>::try_from(&self.verbosity)?;
// The CLI flag `optimization-passes` overwrites optimization passes which are
// potentially defined in the `Cargo.toml` profile.
let optimization_passes = match self.optimization_passes {
Some(opt_passes) => opt_passes,
None => {
let mut manifest = Manifest::new(manifest_path.clone())?;
match manifest.get_profile_optimization_passes() {
// if no setting is found, neither on the cli nor in the profile,
// then we use the default
None => OptimizationPasses::default(),
Some(opt_passes) => opt_passes,
}
}
};
let build_mode = match self.build_release {
true => BuildMode::Release,
false => BuildMode::Debug,
};
execute(
&manifest_path,
verbosity,
self.build_artifact,
unstable_flags,
)
}
}
#[derive(Debug, StructOpt)]
#[structopt(name = "check")]
pub struct CheckCommand {
/// Path to the Cargo.toml of the contract to build
#[structopt(long, parse(from_os_str))]
manifest_path: Option<PathBuf>,
#[structopt(flatten)]
verbosity: VerbosityFlags,
#[structopt(flatten)]
unstable_options: UnstableOptions,
}
impl CheckCommand {
pub fn exec(&self) -> Result<BuildResult> {
let manifest_path = ManifestPath::try_from(self.manifest_path.as_ref())?;
let unstable_flags: UnstableFlags =
TryFrom::<&UnstableOptions>::try_from(&self.unstable_options)?;
let verbosity: Verbosity = TryFrom::<&VerbosityFlags>::try_from(&self.verbosity)?;
execute(
&manifest_path,
verbosity,
BuildArtifacts::CheckOnly,
unstable_flags,
OptimizationPasses::Zero,
/// Executes the supplied cargo command on the project in the specified directory, defaults to the
/// current directory.
/// Uses the unstable cargo feature [`build-std`](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std)
/// to build the standard library with [`panic_immediate_abort`](https://github.com/johnthagen/min-sized-rust#remove-panic-string-formatting-with-panic_immediate_abort)
/// which reduces the size of the Wasm binary by not including panic strings and formatting code.
///
/// # Cargo.toml optimizations
///
/// The original Cargo.toml will be amended to remove the `rlib` crate type in order to minimize
/// the final Wasm binary size.
///
/// Preferred default `[profile.release]` settings will be added if they are missing, existing
/// user-defined settings will be preserved.
///
/// To disable this and use the original `Cargo.toml` as is then pass the `-Z original_manifest` flag.
crate_metadata: &CrateMetadata,
) -> Result<()> {
Andrew Jones
committed
util::assert_channel()?;
// set linker args via RUSTFLAGS.
Loading full blame...