From 6ebd2d6665d1507e9440272d6cb60582e90eda1f Mon Sep 17 00:00:00 2001 From: maciektr Date: Thu, 1 Feb 2024 23:24:20 +0100 Subject: [PATCH] wip: procedural macro compilation commit-id:aebc6424 --- scarb/src/compiler/compilers/mod.rs | 2 + .../compiler/compilers/procedural_macro.rs | 48 ++++++++++++++++++ scarb/src/compiler/repository.rs | 5 +- scarb/src/ops/compile.rs | 17 +++++-- scarb/src/ops/resolve.rs | 50 +++++++++++++++++-- scarb/tests/build_cairo_plugin.rs | 1 + 6 files changed, 116 insertions(+), 7 deletions(-) create mode 100644 scarb/src/compiler/compilers/procedural_macro.rs diff --git a/scarb/src/compiler/compilers/mod.rs b/scarb/src/compiler/compilers/mod.rs index 4d810b570..6d40e822a 100644 --- a/scarb/src/compiler/compilers/mod.rs +++ b/scarb/src/compiler/compilers/mod.rs @@ -1,7 +1,9 @@ pub use lib::*; +pub use procedural_macro::*; pub use starknet_contract::*; pub use test::*; mod lib; +mod procedural_macro; mod starknet_contract; mod test; diff --git a/scarb/src/compiler/compilers/procedural_macro.rs b/scarb/src/compiler/compilers/procedural_macro.rs new file mode 100644 index 000000000..b560586fd --- /dev/null +++ b/scarb/src/compiler/compilers/procedural_macro.rs @@ -0,0 +1,48 @@ +use crate::compiler::{CompilationUnit, Compiler}; +use crate::core::{TargetKind, Workspace}; +use anyhow::{Context, Result}; +use cairo_lang_compiler::db::RootDatabase; +use std::path::Path; +use std::process::Command; +use tracing::trace_span; + +pub struct ProceduralMacroCompiler; + +impl Compiler for ProceduralMacroCompiler { + fn target_kind(&self) -> TargetKind { + TargetKind::CAIRO_PLUGIN.clone() + } + + fn compile( + &self, + unit: CompilationUnit, + _db: &mut RootDatabase, + _ws: &Workspace<'_>, + ) -> Result<()> { + let main_package = unit.components.first().unwrap().package.clone(); + let mut cmd = Self::build_command(main_package.root()); + { + let _ = trace_span!("compile_proc_macro").enter(); + let status = cmd + .status() + .with_context(|| format!("Failed to execute {:?}", cmd))?; + if !status.success() { + return Err(anyhow::anyhow!( + "Failed to compile procedural macro plugin: {:?}", + cmd + )); + } + } + Ok(()) + } +} + +impl ProceduralMacroCompiler { + fn build_command(cwd: impl AsRef) -> Command { + let mut cmd = Command::new("cargo"); + cmd.current_dir(cwd); + cmd.arg("build"); + cmd.arg("--release"); + cmd + } +} diff --git a/scarb/src/compiler/repository.rs b/scarb/src/compiler/repository.rs index 823f8e091..ea8103e9b 100644 --- a/scarb/src/compiler/repository.rs +++ b/scarb/src/compiler/repository.rs @@ -7,7 +7,9 @@ use cairo_lang_compiler::db::RootDatabase; use itertools::Itertools; use smol_str::SmolStr; -use crate::compiler::compilers::{LibCompiler, StarknetContractCompiler, TestCompiler}; +use crate::compiler::compilers::{ + LibCompiler, ProceduralMacroCompiler, StarknetContractCompiler, TestCompiler, +}; use crate::compiler::{CompilationUnit, Compiler}; use crate::core::Workspace; @@ -27,6 +29,7 @@ impl CompilerRepository { repo.add(Box::new(LibCompiler)).unwrap(); repo.add(Box::new(StarknetContractCompiler)).unwrap(); repo.add(Box::new(TestCompiler)).unwrap(); + repo.add(Box::new(ProceduralMacroCompiler)).unwrap(); repo } diff --git a/scarb/src/ops/compile.rs b/scarb/src/ops/compile.rs index 93015fe80..db67ba28d 100644 --- a/scarb/src/ops/compile.rs +++ b/scarb/src/ops/compile.rs @@ -2,6 +2,7 @@ use anyhow::{anyhow, Result}; use cairo_lang_compiler::db::RootDatabase; use cairo_lang_compiler::diagnostics::DiagnosticsError; use indoc::formatdoc; +use itertools::Itertools; use scarb_ui::components::Status; use scarb_ui::HumanDuration; @@ -59,11 +60,21 @@ where let compilation_units = ops::generate_compilation_units(&resolve, ws)? .into_iter() - .filter(|cu| !opts.exclude_targets.contains(&cu.target().kind)) .filter(|cu| { - opts.include_targets.is_empty() || opts.include_targets.contains(&cu.target().kind) + let is_excluded = opts.exclude_targets.contains(&cu.target().kind); + let is_included = + opts.include_targets.is_empty() || opts.include_targets.contains(&cu.target().kind); + let is_selected = packages.contains(&cu.main_package_id); + let is_cairo_plugin = cu.components.first().unwrap().target.is_cairo_plugin(); + is_cairo_plugin || (is_selected && is_included && !is_excluded) + }) + .sorted_by_key(|cu| { + if cu.components.first().unwrap().target.is_cairo_plugin() { + 0 + } else { + 1 + } }) - .filter(|cu| packages.contains(&cu.main_package_id)) .collect::>(); for unit in compilation_units { diff --git a/scarb/src/ops/resolve.rs b/scarb/src/ops/resolve.rs index fedfaab95..ed5c44f41 100644 --- a/scarb/src/ops/resolve.rs +++ b/scarb/src/ops/resolve.rs @@ -155,12 +155,26 @@ pub fn generate_compilation_units( let mut units = Vec::with_capacity(ws.members().size_hint().0); for member in ws.members() { units.extend(if member.is_cairo_plugin() { - generate_cairo_plugin_compilation_units()? + generate_cairo_plugin_compilation_units(&member, resolve, ws)? } else { generate_cairo_compilation_units(&member, resolve, ws)? }); } + let cairo_plugins = units + .iter() + .flat_map(|unit| unit.cairo_plugins.clone()) + .filter(|plugin| !plugin.builtin) + .map(|plugin| plugin.package.clone()) + .unique_by(|plugin| plugin.id) + .collect_vec(); + + for plugin in cairo_plugins { + units.extend(generate_cairo_plugin_compilation_units( + &plugin, resolve, ws, + )?); + } + assert!( units.iter().map(CompilationUnit::id).all_unique(), "All generated compilation units must have unique IDs." @@ -402,6 +416,36 @@ fn check_cairo_version_compatibility(packages: &[Package], ws: &Workspace<'_>) - Ok(()) } -fn generate_cairo_plugin_compilation_units() -> Result> { - bail!("compiling Cairo plugin packages is not possible yet") +fn generate_cairo_plugin_compilation_units( + member: &Package, + resolve: &WorkspaceResolve, + ws: &Workspace<'_>, +) -> Result> { + let core = resolve + .packages + .iter() + .find(|(pid, _)| pid.name == PackageName::CORE) + .map(|(_, p)| p.clone()) + .unwrap() + .clone(); + Ok(vec![CompilationUnit { + main_package_id: member.id, + components: vec![ + CompilationUnitComponent { + package: member.clone(), + target: member + .fetch_target(&TargetKind::CAIRO_PLUGIN) + .cloned() + .unwrap(), + }, + CompilationUnitComponent { + package: core.clone(), + target: core.fetch_target(&TargetKind::LIB).cloned().unwrap(), + }, + ], + cairo_plugins: Vec::new(), + profile: ws.current_profile()?, + compiler_config: member.manifest.compiler_config.clone(), + cfg_set: Default::default(), + }]) } diff --git a/scarb/tests/build_cairo_plugin.rs b/scarb/tests/build_cairo_plugin.rs index f8308dd91..382b4cadf 100644 --- a/scarb/tests/build_cairo_plugin.rs +++ b/scarb/tests/build_cairo_plugin.rs @@ -5,6 +5,7 @@ use scarb_test_support::command::Scarb; use scarb_test_support::project_builder::ProjectBuilder; #[test] +#[ignore = "TODO(maciektr): Remove when proc-macros are implemented."] fn compile_cairo_plugin() { let t = TempDir::new().unwrap(); ProjectBuilder::start()