From e29d9c355c25ccc4f3923a20d1ef0c17ea9c5cf9 Mon Sep 17 00:00:00 2001 From: clearloop Date: Sat, 27 Apr 2024 01:39:45 +0800 Subject: [PATCH] feat(gbuild): introduce cargo-gbuild (#3835) --- .cargo/config.toml | 2 + Cargo.lock | 26 + Cargo.toml | 1 + Makefile | 8 + utils/cargo-gbuild/Cargo.toml | 22 + utils/cargo-gbuild/src/artifact.rs | 66 +++ utils/cargo-gbuild/src/bin/cargo-gbuild.rs | 66 +++ utils/cargo-gbuild/src/cli.rs | 135 +++++ utils/cargo-gbuild/src/lib.rs | 26 + utils/cargo-gbuild/test-program/Cargo.lock | 643 +++++++++++++++++++++ utils/cargo-gbuild/test-program/Cargo.toml | 17 + utils/cargo-gbuild/test-program/src/lib.rs | 39 ++ utils/cargo-gbuild/tests/smoke.rs | 54 ++ utils/wasm-builder/src/cargo_command.rs | 12 +- utils/wasm-builder/src/lib.rs | 6 +- 15 files changed, 1119 insertions(+), 4 deletions(-) create mode 100644 .cargo/config.toml create mode 100644 utils/cargo-gbuild/Cargo.toml create mode 100644 utils/cargo-gbuild/src/artifact.rs create mode 100644 utils/cargo-gbuild/src/bin/cargo-gbuild.rs create mode 100644 utils/cargo-gbuild/src/cli.rs create mode 100644 utils/cargo-gbuild/src/lib.rs create mode 100644 utils/cargo-gbuild/test-program/Cargo.lock create mode 100644 utils/cargo-gbuild/test-program/Cargo.toml create mode 100644 utils/cargo-gbuild/test-program/src/lib.rs create mode 100644 utils/cargo-gbuild/tests/smoke.rs diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 00000000000..e526b31a280 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[alias] +gbuild = "run -p cargo-gbuild --" diff --git a/Cargo.lock b/Cargo.lock index e5f74f1696e..810d27c0cd4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1240,6 +1240,22 @@ dependencies = [ "serde", ] +[[package]] +name = "cargo-gbuild" +version = "1.3.0" +dependencies = [ + "anyhow", + "cargo_toml", + "clap 4.5.4", + "colored", + "gear-wasm-builder", + "gtest", + "serde", + "toml 0.8.12", + "tracing", + "tracing-subscriber 0.3.18", +] + [[package]] name = "cargo-platform" version = "0.1.3" @@ -1277,6 +1293,16 @@ dependencies = [ "thiserror", ] +[[package]] +name = "cargo_toml" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a98356df42a2eb1bd8f1793ae4ee4de48e384dd974ce5eac8eee802edb7492be" +dependencies = [ + "serde", + "toml 0.8.12", +] + [[package]] name = "cc" version = "1.0.83" diff --git a/Cargo.toml b/Cargo.toml index b2af524a9b1..dbc8b3da79d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -105,6 +105,7 @@ base64 = "0.21.7" byteorder = { version = "1.5.0", default-features = false } blake2-rfc = { version = "0.2.18", default-features = false } bs58 = { version = "0.5.1", default-features = false } +cargo_toml = "0.19.2" cargo_metadata = "0.18.1" clap = "4.5.4" codec = { package = "parity-scale-codec", version = "3.6.4", default-features = false } diff --git a/Makefile b/Makefile index d447c661311..7f4d1b1c389 100644 --- a/Makefile +++ b/Makefile @@ -217,6 +217,14 @@ test-gcli: node test-gcli-release: node-release @ ./scripts/gear.sh test gcli --release +.PHONY: test-gbuild +test-gbuild: node + @ ./scripts/gear.sh test gbuild + +.PHONY: test-gbuild-release +test-gbuild-release: node-release + @ ./scripts/gear.sh test gbuild --release + .PHONY: test-pallet test-pallet: @ ./scripts/gear.sh test pallet diff --git a/utils/cargo-gbuild/Cargo.toml b/utils/cargo-gbuild/Cargo.toml new file mode 100644 index 00000000000..c6cbf59fea7 --- /dev/null +++ b/utils/cargo-gbuild/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "cargo-gbuild" +version.workspace = true +authors.workspace = true +edition.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true + +[dependencies] +anyhow.workspace = true +cargo_toml.workspace = true +clap = { workspace = true, features = ["derive"] } +colored.workspace = true +serde = { workspace = true, features = ["derive"] } +toml.workspace = true +tracing.workspace = true +tracing-subscriber = { workspace = true, features = ["env-filter"] } +gear-wasm-builder.workspace = true + +[dev-dependencies] +gtest.workspace = true diff --git a/utils/cargo-gbuild/src/artifact.rs b/utils/cargo-gbuild/src/artifact.rs new file mode 100644 index 00000000000..d68dfe0ae33 --- /dev/null +++ b/utils/cargo-gbuild/src/artifact.rs @@ -0,0 +1,66 @@ +// This file is part of Gear. +// +// Copyright (C) 2024 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 . + +use anyhow::{anyhow, Result}; +use gear_wasm_builder::optimize::{self, OptType, Optimizer}; +use std::{fs, path::PathBuf}; + +/// Gbuild artifact registry +/// +/// This instance simply holds the paths of the built binaries +/// for re-using stuffs. +/// +/// TODO: support workspace format, abstract instance for different programs (#3852) +pub struct Artifact { + /// The directory path of the artifact. + pub root: PathBuf, + /// Program name of this artifact. + pub name: String, + /// The path to the built program. + pub program: PathBuf, +} + +impl Artifact { + /// Create a new artifact registry. + pub fn new(root: PathBuf, name: String) -> Result { + fs::create_dir_all(&root) + .map_err(|e| anyhow!("Failed to create the artifact directory, {e}"))?; + + Ok(Self { + program: root.join(format!("{name}.wasm")), + name, + root, + }) + } + + /// Build artifacts with optimization. + pub fn process(&self, src: PathBuf) -> Result<()> { + optimize::optimize_wasm( + src.join(format!("{}.wasm", self.name)), + self.program.clone(), + "4", + true, + )?; + let mut optimizer = Optimizer::new(self.program.clone())?; + optimizer + .insert_stack_end_export() + .map_err(|e| anyhow!(e))?; + optimizer.strip_custom_sections(); + fs::write(self.program.clone(), optimizer.optimize(OptType::Opt)?).map_err(Into::into) + } +} diff --git a/utils/cargo-gbuild/src/bin/cargo-gbuild.rs b/utils/cargo-gbuild/src/bin/cargo-gbuild.rs new file mode 100644 index 00000000000..f8d6ece6b9a --- /dev/null +++ b/utils/cargo-gbuild/src/bin/cargo-gbuild.rs @@ -0,0 +1,66 @@ +// This file is part of Gear. +// +// Copyright (C) 2024 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 . + +use std::env; + +use anyhow::Result; +use cargo_gbuild::GBuild; +use clap::Parser; +use tracing_subscriber::filter::EnvFilter; + +const CUSTOM_COMMAND_NAME: &str = "gbuild"; + +/// Command `gbuild` as cargo extension. +#[derive(Parser)] +#[clap(author, version)] +#[command(name = "cargo-gbuild")] +struct App { + /// The verbosity level + #[clap(short, long, action = clap::ArgAction::Count)] + pub verbose: u8, + + /// The gbuild command. + #[clap(flatten)] + pub command: GBuild, +} + +fn main() -> Result<()> { + let args = env::args().enumerate().filter_map(|(idx, arg)| { + if idx == 1 && arg == CUSTOM_COMMAND_NAME { + return None; + } + + Some(arg) + }); + + let app = App::parse_from(args); + + // Replace the binary name to library name. + let name = env!("CARGO_PKG_NAME").replace('-', "_"); + let env = EnvFilter::try_from_default_env().unwrap_or(EnvFilter::new(match app.verbose { + 0 => format!("{name}=info"), + 1 => format!("{name}=debug"), + 2 => "debug".into(), + _ => "trace".into(), + })); + + tracing_subscriber::fmt().with_env_filter(env).init(); + let artifact = app.command.run()?; + tracing::info!("The artifact has been generated at {:?}", artifact.root); + Ok(()) +} diff --git a/utils/cargo-gbuild/src/cli.rs b/utils/cargo-gbuild/src/cli.rs new file mode 100644 index 00000000000..dac8a1d1db8 --- /dev/null +++ b/utils/cargo-gbuild/src/cli.rs @@ -0,0 +1,135 @@ +// This file is part of Gear. +// +// Copyright (C) 2024 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 . + +//! TODO: Introduce a standard for the project structure of gear programs (#3866) + +use crate::Artifact; +use anyhow::{anyhow, Result}; +use cargo_toml::Manifest; +use clap::Parser; +use colored::Colorize; +use gear_wasm_builder::CargoCommand; +use std::{ + env, fs, + path::{Path, PathBuf}, +}; + +const ARTIFACT_DIR: &str = "gbuild"; +const DEV_PROFILE: &str = "dev"; +const DEBUG_ARTIFACT: &str = "debug"; +const RELEASE_PROFILE: &str = "release"; + +/// Command `gbuild` as cargo extension. +#[derive(Parser)] +pub struct GBuild { + /// The path to the program manifest + #[clap(short, long, default_value = "Cargo.toml")] + pub manifest_path: PathBuf, + + /// Space or comma separated list of features to activate + #[clap(short = 'F', long)] + pub features: Vec, + + /// If enables the release profile. + #[clap(short, long)] + pub release: bool, + + /// Directory for all generated artifacts + /// + /// If not set, the default value will be the target folder + /// of the cargo project. + #[clap(short, long)] + pub target_dir: Option, + + /// Build artifacts with the specified profile + #[clap(long)] + pub profile: Option, +} + +impl GBuild { + /// Run the gbuild command + /// + /// TODO: Support `gtest::Program::current` (#3851) + pub fn run(self) -> Result { + // 1. Get the cargo target directory + // + // TODO: Detect if the package is part of a workspace. (#3852) + // TODO: Support target dir defined in `.cargo/config.toml` (#3852) + let absolute_root = fs::canonicalize(self.manifest_path.clone())?; + let cargo_target_dir = env::var("CARGO_TARGET_DIR").map(PathBuf::from).unwrap_or( + absolute_root + .parent() + .ok_or_else(|| anyhow!("Failed to parse the root directory."))? + .join("target"), + ); + + // 2. Run the cargo command, process optimizations and collect artifacts. + let cargo_artifact_dir = self.cargo(&cargo_target_dir)?; + let gbuild_artifact_dir = self + .target_dir + .unwrap_or(cargo_target_dir.clone()) + .join(ARTIFACT_DIR); + + let artifact = Artifact::new( + gbuild_artifact_dir, + Manifest::from_path(self.manifest_path.clone())? + .package() + .name + .replace('-', "_"), + )?; + artifact.process(cargo_artifact_dir)?; + Ok(artifact) + } + + /// Process the cargo command. + /// + /// TODO: Support workspace build. (#3852) + fn cargo(&self, target_dir: &Path) -> Result { + let mut kargo = CargoCommand::default(); + let mut artifact = DEBUG_ARTIFACT; + + if let Some(profile) = &self.profile { + if self.release { + eprintln!( + "{}: conflicting usage of --profile={} and --release +The `--release` flag is the same as `--profile=release`. +Remove one flag or the other to continue.", + "error".red().bold(), + profile + ); + std::process::exit(1); + } + + kargo.set_profile(profile.clone()); + if profile != DEV_PROFILE { + artifact = profile; + } + } else if self.release { + kargo.set_profile(RELEASE_PROFILE.into()); + artifact = RELEASE_PROFILE; + } + + kargo.set_manifest_path(self.manifest_path.clone()); + kargo.set_target_dir(target_dir.to_path_buf()); + kargo.set_features(&self.features); + kargo.run()?; + + // Returns the root of the built artifact + Ok(target_dir.join(format!("wasm32-unknown-unknown/{}", artifact))) + } +} diff --git a/utils/cargo-gbuild/src/lib.rs b/utils/cargo-gbuild/src/lib.rs new file mode 100644 index 00000000000..35f13e6edfe --- /dev/null +++ b/utils/cargo-gbuild/src/lib.rs @@ -0,0 +1,26 @@ +// This file is part of Gear. +// +// Copyright (C) 2024 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 . + +//! Cargo extension for building gear programs. + +#![deny(missing_docs)] + +mod artifact; +mod cli; + +pub use self::{artifact::Artifact, cli::GBuild}; diff --git a/utils/cargo-gbuild/test-program/Cargo.lock b/utils/cargo-gbuild/test-program/Cargo.lock new file mode 100644 index 00000000000..9be7ea3d388 --- /dev/null +++ b/utils/cargo-gbuild/test-program/Cargo.lock @@ -0,0 +1,643 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "const_format" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "enum-iterator" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fd242f399be1da0a5354aa462d57b4ab2b4ee0683cc552f7c007d2d12d36e94" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03cdc46ec28bd728e67540c528013c6a10eb69a02eb31078a1bda695438cbfb8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.58", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-core", + "futures-sink", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "galloc" +version = "1.3.0" +dependencies = [ + "gear-dlmalloc", +] + +[[package]] +name = "gbuild-test-program" +version = "0.1.0" +dependencies = [ + "gstd", +] + +[[package]] +name = "gcore" +version = "1.3.0" +dependencies = [ + "gear-core-errors", + "gear-stack-buffer", + "gsys", + "parity-scale-codec", +] + +[[package]] +name = "gear-core-errors" +version = "1.3.0" +dependencies = [ + "derive_more", + "enum-iterator", + "scale-info", +] + +[[package]] +name = "gear-dlmalloc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b88fcd5524e7ab9f156c17b14e754d6ba122ef9b00586d632d2ae3dbc7bfadb" +dependencies = [ + "libc", + "libc-print", + "page_size", + "static_assertions", + "str-buf", +] + +[[package]] +name = "gear-stack-buffer" +version = "1.3.0" + +[[package]] +name = "gstd" +version = "1.3.0" +dependencies = [ + "arrayvec", + "bs58", + "const_format", + "futures", + "galloc", + "gcore", + "gear-core-errors", + "gstd-codegen", + "hashbrown", + "hex", + "parity-scale-codec", + "primitive-types", + "scale-info", +] + +[[package]] +name = "gstd-codegen" +version = "1.3.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.58", +] + +[[package]] +name = "gsys" +version = "1.3.0" + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "libc-print" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17f111e2175c779daaf5e89fe3a3b0776b0adec218bc1159c56e4d3f58032f5" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "page_size" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +dependencies = [ + "arrayvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" +dependencies = [ + "proc-macro-crate 2.0.2", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "scale-info", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +dependencies = [ + "toml_datetime", + "toml_edit 0.20.2", +] + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "scale-info" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "788745a868b0e751750388f4e6546eb921ef714a4317fa6954f7cde114eb2eb7" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dc2f4e8bc344b9fc3d5f74f72c2e55bfc38d28dc2ebc69c194a3df424e4d9ac" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "semver" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "str-buf" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceb97b7225c713c2fd4db0153cb6b3cab244eb37900c3f634ed4d43310d8c34" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.58", +] diff --git a/utils/cargo-gbuild/test-program/Cargo.toml b/utils/cargo-gbuild/test-program/Cargo.toml new file mode 100644 index 00000000000..7b9a49ca07f --- /dev/null +++ b/utils/cargo-gbuild/test-program/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "gbuild-test-program" +version = "0.1.0" +edition = "2021" + +[dependencies] +gstd = { path = "../../../gstd" } + +[features] +debug = ["gstd/debug"] +default = [] +std = [] + +[lib] +crate-type = ["cdylib"] + +[workspace] diff --git a/utils/cargo-gbuild/test-program/src/lib.rs b/utils/cargo-gbuild/test-program/src/lib.rs new file mode 100644 index 00000000000..78c48a800e2 --- /dev/null +++ b/utils/cargo-gbuild/test-program/src/lib.rs @@ -0,0 +1,39 @@ +// This file is part of Gear. + +// Copyright (C) 2024 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 . + +#![no_std] + +use gstd::msg; + +#[no_mangle] +extern "C" fn init() { + let payload = msg::load_bytes().expect("Failed to load payload"); + gstd::debug!("Received payload: {payload:?}"); + if payload == b"PING" { + msg::reply_bytes("INIT_PONG", 0).expect("Failed to send reply"); + } +} + +#[no_mangle] +extern "C" fn handle() { + let payload = msg::load_bytes().expect("Failed to load payload"); + + if payload == b"PING" { + msg::reply_bytes("HANDLE_PONG", 0).expect("Failed to send reply"); + } +} diff --git a/utils/cargo-gbuild/tests/smoke.rs b/utils/cargo-gbuild/tests/smoke.rs new file mode 100644 index 00000000000..2092a3f32c2 --- /dev/null +++ b/utils/cargo-gbuild/tests/smoke.rs @@ -0,0 +1,54 @@ +// This file is part of Gear. +// +// Copyright (C) 2024 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 . + +use anyhow::Result; +use cargo_gbuild::GBuild; +use gtest::{Program, System}; +use std::path::PathBuf; + +#[test] +fn test_compile_program_v2() -> Result<()> { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-program/Cargo.toml"); + let artifact = GBuild { + manifest_path: root.to_string_lossy().to_string().into(), + features: vec!["debug".into()], + profile: None, + target_dir: None, + release: false, + } + .run()?; + + // Initialize system environment + let system = System::new(); + system.init_logger(); + + // Get program from artifact + let user = 0; + let program = Program::from_file(&system, artifact.program); + + // Init program + let res = program.send_bytes(user, b"PING"); + assert!(!res.main_failed()); + assert!(res.contains(&(user, b"INIT_PONG"))); + + // Handle program + let res = program.send_bytes(user, b"PING"); + assert!(!res.main_failed()); + assert!(res.contains(&(user, b"HANDLE_PONG"))); + Ok(()) +} diff --git a/utils/wasm-builder/src/cargo_command.rs b/utils/wasm-builder/src/cargo_command.rs index 2115955e900..19deac6bbb7 100644 --- a/utils/wasm-builder/src/cargo_command.rs +++ b/utils/wasm-builder/src/cargo_command.rs @@ -37,8 +37,8 @@ pub struct CargoCommand { } impl CargoCommand { - /// Create a new `CargoCommand`. - pub fn new() -> Self { + /// Initialize new cargo command. + pub fn new() -> CargoCommand { CargoCommand { path: "rustup".to_string(), manifest_path: "Cargo.toml".into(), @@ -52,7 +52,15 @@ impl CargoCommand { paths_to_remap: vec![], } } +} +impl Default for CargoCommand { + fn default() -> Self { + Self::new() + } +} + +impl CargoCommand { /// Set path to the `Cargo.toml` file. pub fn set_manifest_path(&mut self, path: PathBuf) { self.manifest_path = path; diff --git a/utils/wasm-builder/src/lib.rs b/utils/wasm-builder/src/lib.rs index 051a5444cc8..db39d9c4e7d 100644 --- a/utils/wasm-builder/src/lib.rs +++ b/utils/wasm-builder/src/lib.rs @@ -20,13 +20,15 @@ #![doc(html_logo_url = "https://docs.gear.rs/logo.svg")] #![doc(html_favicon_url = "https://gear-tech.io/favicons/favicon.ico")] -use crate::{cargo_command::CargoCommand, wasm_project::WasmProject}; +pub use cargo_command::CargoCommand; +pub use wasm_project::{PreProcessor, PreProcessorResult, PreProcessorTarget}; + +use crate::wasm_project::WasmProject; use anyhow::{Context, Result}; use gmeta::{Metadata, MetadataRepr}; use regex::Regex; use std::{env, path::PathBuf, process}; use wasm_project::ProjectType; -pub use wasm_project::{PreProcessor, PreProcessorResult, PreProcessorTarget}; mod builder_error; mod cargo_command;