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 21, 2024
1 parent 21e6d18 commit 252efc6
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 26 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
48 changes: 47 additions & 1 deletion scarb/src/compiler/plugin/proc_macro/compilation.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
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 crate::process::exec_piping;
use anyhow::Result;
use camino::Utf8PathBuf;
use libloading::library_filename;
use std::process::Command;
use tracing::trace_span;

/// This trait is used to define the shared library path for a package.
pub trait SharedLibraryProvider {
Expand Down Expand Up @@ -38,3 +43,44 @@ impl SharedLibraryProvider for Package {
.join(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 _ = trace_span!("compile_proc_macro").enter();
exec(&mut cmd.into(), ws.config())?;
}
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.current_dir(args.current_dir);
cmd.args(["build", "--release"]);
cmd.arg("--target-dir");
cmd.arg(args.target_dir);
cmd
}
}

fn exec(cmd: &mut Command, config: &Config) -> Result<()> {
exec_piping(
cmd,
config,
|line: &str| config.ui().print(line),
|line: &str| config.ui().print(line),
)
}
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(),
}])
}
29 changes: 24 additions & 5 deletions scarb/src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,28 @@ mod imp {
}
}

/// Runs the process, waiting for completion, and mapping non-success exit codes to an error.
#[tracing::instrument(level = "trace", skip_all)]
pub fn exec(cmd: &mut Command, config: &Config) -> Result<()> {
exec_piping(
cmd,
config,
|line: &str| {
debug!("{line}");
},
|line: &str| {
debug!("{line}");
},
)
}

/// Runs the process, waiting for completion, and mapping non-success exit codes to an error.
#[tracing::instrument(level = "trace", skip_all)]
pub fn exec_piping(
cmd: &mut Command,
config: &Config,
stdout_callback: impl Fn(&str) + Send,
stderr_callback: impl Fn(&str) + Send,
) -> Result<()> {
let cmd_str = shlex_join(cmd);

config.ui().verbose(Status::new("Running", &cmd_str));
Expand All @@ -112,7 +131,7 @@ pub fn exec(cmd: &mut Command, config: &Config) -> Result<()> {
let span = debug_span!("out");
move || {
let mut stdout = stdout;
pipe_to_logs(&span, &mut stdout);
pipe(&span, &mut stdout, stdout_callback);
}
});

Expand All @@ -121,7 +140,7 @@ pub fn exec(cmd: &mut Command, config: &Config) -> Result<()> {
let span = debug_span!("err");
move || {
let mut stderr = stderr;
pipe_to_logs(&span, &mut stderr);
pipe(&span, &mut stderr, stderr_callback);
}
});

Expand All @@ -135,12 +154,12 @@ pub fn exec(cmd: &mut Command, config: &Config) -> Result<()> {
}
});

fn pipe_to_logs(span: &Span, stream: &mut dyn Read) {
fn pipe(span: &Span, stream: &mut dyn Read, callback: impl Fn(&str)) {
let _enter = span.enter();
let stream = BufReader::with_capacity(128, stream);
for line in stream.lines() {
match line {
Ok(line) => debug!("{line}"),
Ok(line) => callback(line.as_str()),
Err(err) => warn!("{err:?}"),
}
}
Expand Down
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 252efc6

Please sign in to comment.