Skip to content

Commit

Permalink
Procedural macro compilation
Browse files Browse the repository at this point in the history
Resolves #1129

commit-id:aebc6424
  • Loading branch information
maciektr committed Feb 20, 2024
1 parent cbdcc41 commit a897204
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 21 deletions.
4 changes: 4 additions & 0 deletions scarb/src/compiler/compilation_unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ impl CompilationUnit {
ws.target_dir().child(self.profile.as_str())
}

pub fn is_cairo_plugin(&self) -> bool {
self.target().is_cairo_plugin()
}

pub fn is_sole_for_package(&self) -> bool {
self.main_component()
.package
Expand Down
50 changes: 49 additions & 1 deletion scarb/src/compiler/plugin/proc_macro/compilation.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
use crate::compiler::plugin::proc_macro::PROC_MACRO_BUILD_PROFILE;
use crate::core::{Config, Package};
use crate::compiler::CompilationUnit;
use crate::core::{Config, Package, Workspace};
use crate::flock::Filesystem;
use anyhow::{ensure, Context, Result};
use camino::Utf8PathBuf;
use libloading::library_filename;
use std::process::{Command, Stdio};
use tracing::trace_span;

/// This trait is used to define the shared library path for a package.
pub trait SharedLibraryProvider {
Expand Down Expand Up @@ -33,3 +38,46 @@ impl SharedLibraryProvider for Package {
.into_child(lib_name)
}
}

pub fn compile_unit(unit: CompilationUnit, ws: &Workspace<'_>) -> Result<()> {
let main_package = unit.components.first().unwrap().package.clone();
let cmd = CargoCommand {
current_dir: main_package.root().to_path_buf(),
target_dir: main_package
.target_path(ws.config())
.path_unchecked()
.to_path_buf(),
};
let mut cmd: Command = cmd.into();
{
let _ = trace_span!("compile_proc_macro").enter();
let status = cmd
.status()
.with_context(|| format!("Failed to execute {:?}", cmd))?;
ensure!(
status.success(),
"failed to compile procedural macro plugin: {:?}",
cmd
);
}

Ok(())
}

struct CargoCommand {
current_dir: Utf8PathBuf,
target_dir: Utf8PathBuf,
}

impl From<CargoCommand> for Command {
fn from(args: CargoCommand) -> Self {
let mut cmd = Command::new("cargo");
cmd.stdout(Stdio::inherit());
cmd.stderr(Stdio::inherit());
cmd.current_dir(args.current_dir);
cmd.args(["build", "--release"]);
cmd.arg("--target-dir");
cmd.arg(args.target_dir);
cmd
}
}
1 change: 1 addition & 0 deletions scarb/src/compiler/plugin/proc_macro/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ pub mod compilation;
mod ffi;
mod host;

pub use compilation::compile_unit;
pub use ffi::*;
pub use host::*;
45 changes: 28 additions & 17 deletions scarb/src/ops/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ 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;

use crate::compiler::db::{build_scarb_root_database, has_starknet_plugin};
use crate::compiler::helpers::build_compiler_config;
use crate::compiler::plugin::proc_macro;
use crate::compiler::CompilationUnit;
use crate::core::{PackageId, PackageName, TargetKind, Utf8PathWorkspaceExt, Workspace};
use crate::ops;
Expand Down Expand Up @@ -59,11 +61,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::<Vec<_>>();

for unit in compilation_units {
Expand All @@ -89,22 +101,21 @@ fn compile_unit(unit: CompilationUnit, ws: &Workspace<'_>) -> Result<()> {
.ui()
.print(Status::new("Compiling", &unit.name()));

let mut db = build_scarb_root_database(&unit, ws)?;

check_starknet_dependency(&unit, ws, &db, &package_name);

ws.config()
.compilers()
.compile(unit, &mut db, ws)
.map_err(|err| {
if !suppress_error(&err) {
ws.config().ui().anyhow(&err);
}
let result = if unit.is_cairo_plugin() {
proc_macro::compile_unit(unit, ws)
} else {
let mut db = build_scarb_root_database(&unit, ws)?;
check_starknet_dependency(&unit, ws, &db, &package_name);
ws.config().compilers().compile(unit, &mut db, ws)
};

anyhow!("could not compile `{package_name}` due to previous error")
})?;
result.map_err(|err| {
if !suppress_error(&err) {
ws.config().ui().anyhow(&err);
}

Ok(())
anyhow!("could not compile `{package_name}` due to previous error")
})
}

fn check_unit(unit: CompilationUnit, ws: &Workspace<'_>) -> Result<()> {
Expand Down
36 changes: 33 additions & 3 deletions scarb/src/ops/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,12 +155,24 @@ 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, 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, ws)?);
}

assert!(
units.iter().map(CompilationUnit::id).all_unique(),
"All generated compilation units must have unique IDs."
Expand Down Expand Up @@ -425,6 +437,24 @@ fn check_cairo_version_compatibility(packages: &[Package], ws: &Workspace<'_>) -
Ok(())
}

fn generate_cairo_plugin_compilation_units() -> Result<Vec<CompilationUnit>> {
bail!("compiling Cairo plugin packages is not possible yet")
fn generate_cairo_plugin_compilation_units(
member: &Package,
ws: &Workspace<'_>,
) -> Result<Vec<CompilationUnit>> {
Ok(vec![CompilationUnit {
main_package_id: member.id,
components: vec![CompilationUnitComponent {
package: member.clone(),
cfg_set: None,
target: member
.fetch_target(&TargetKind::CAIRO_PLUGIN)
.cloned()
// Safe to unwrap, as member.is_cairo_plugin() has been ensured before.
.expect("main component of procedural macro must define `cairo-plugin` target"),
}],
cairo_plugins: Vec::new(),
profile: ws.current_profile()?,
compiler_config: member.manifest.compiler_config.clone(),
cfg_set: Default::default(),
}])
}
1 change: 1 addition & 0 deletions scarb/tests/build_cairo_plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down

0 comments on commit a897204

Please sign in to comment.