diff --git a/README.md b/README.md index fb49207..c5e3470 100644 --- a/README.md +++ b/README.md @@ -50,13 +50,13 @@ Run printers: caracal print path/file/to/analyze --printer printer_to_use --corelib path/to/corelib/src ``` ### Cairo project -If you have a cairo project with multiple files and contracts you may need to specify which contract with `--contract-path`. The local cairo compiler binary is used if available otherwise a bundled compiler is used. In the latter case you also need to specify the corelib as explained above for the standalone case. The path is the directory where `cairo_project.toml` resides. +If you have a cairo project with multiple files and contracts you may need to specify which contracts with `--contract-path`. The local cairo compiler binary is used if available otherwise a bundled compiler is used. In the latter case you also need to specify the corelib as explained above for the standalone case. The path is the directory where `cairo_project.toml` resides. Run detectors: ```bash caracal detect path/to/dir ``` ```bash -caracal detect path/to/dir --contract-path token::myerc20::... +caracal detect path/to/dir --contract-path token::myerc20::... token::myerc721::... ``` Run printers: ```bash diff --git a/src/cli/commands/detect/mod.rs b/src/cli/commands/detect/mod.rs index 2e2db1a..c85cae5 100644 --- a/src/cli/commands/detect/mod.rs +++ b/src/cli/commands/detect/mod.rs @@ -18,9 +18,9 @@ pub struct DetectArgs { #[arg(long)] corelib: Option, - /// Path to the contract to compile when using a cairo project with multiple contracts - #[arg(long)] - contract_path: Option, + /// Path to the contracts to compile when using a cairo project with multiple contracts + #[arg(long, num_args(0..))] + contract_path: Option>, /// Detectors to run #[arg(long, num_args(0..), conflicts_with_all(["exclude", "exclude_informational", "exclude_low", "exclude_medium", "exclude_high"]))] diff --git a/src/cli/commands/print/mod.rs b/src/cli/commands/print/mod.rs index fc0f22b..e517b09 100644 --- a/src/cli/commands/print/mod.rs +++ b/src/cli/commands/print/mod.rs @@ -14,9 +14,9 @@ pub struct PrintArgs { #[arg(long)] corelib: Option, - /// Path to the contract to compile when using a cairo project with multiple contracts - #[arg(long)] - contract_path: Option, + /// Path to the contracts to compile when using a cairo project with multiple contracts + #[arg(long, num_args(0..))] + contract_path: Option>, /// Which functions to run the printer (all, user-functions) #[arg(short, long, default_value_t = Filter::UserFunctions)] diff --git a/src/compilation/cairo_project.rs b/src/compilation/cairo_project.rs index a08632c..c8a3dcf 100644 --- a/src/compilation/cairo_project.rs +++ b/src/compilation/cairo_project.rs @@ -1,6 +1,7 @@ use anyhow::{anyhow, bail, Context, Result}; use std::env; use std::process; +use std::process::Output; use std::sync::Arc; use super::ProgramCompiled; @@ -97,41 +98,56 @@ pub fn compile(opts: CoreOpts) -> Result> { } fn local_compiler(opts: CoreOpts) -> Result> { - let output = if let Some(contract_path) = opts.contract_path { - process::Command::new("starknet-compile") - .arg(opts.target) - .arg("--contract-path") - .arg(contract_path) - .arg("--replace-ids") - .output()? + let mut compiler_calls: Vec = vec![]; + if let Some(contract_paths) = opts.contract_path { + contract_paths.iter().for_each(|c| { + compiler_calls.push( + process::Command::new("starknet-compile") + .arg(opts.target.clone()) + .arg("--contract-path") + .arg(c) + .arg("--replace-ids") + .output() + .unwrap(), + ) + }); } else { - process::Command::new("starknet-compile") - .arg(opts.target) - .arg("--replace-ids") - .output()? + compiler_calls.push( + process::Command::new("starknet-compile") + .arg(opts.target) + .arg("--replace-ids") + .output() + .unwrap(), + ); }; - if !output.status.success() { - bail!(anyhow!( - "starknet-compile failed to compile.\n Status {}\n {}", - output.status, - String::from_utf8(output.stderr)? - )); - } + let mut programs_compiled: Vec = vec![]; + + for compiler_call in compiler_calls { + if !compiler_call.status.success() { + bail!(anyhow!( + "starknet-compile failed to compile.\n Status {}\n {}", + compiler_call.status, + String::from_utf8(compiler_call.stderr)? + )); + } - let contract_class: ContractClass = - serde_json::from_str(&String::from_utf8(output.stdout)?).unwrap(); + let contract_class: ContractClass = + serde_json::from_str(&String::from_utf8(compiler_call.stdout)?).unwrap(); - // We don't have to check the existence because we ran the compiler with --replace-ids - let debug_info = contract_class.sierra_program_debug_info.unwrap(); + // We don't have to check the existence because we ran the compiler with --replace-ids + let debug_info = contract_class.sierra_program_debug_info.unwrap(); - let sierra = sierra_from_felt252s(&contract_class.sierra_program) - .unwrap() - .2; - let sierra = SierraProgramDebugReplacer { debug_info }.apply(&sierra); + let sierra = sierra_from_felt252s(&contract_class.sierra_program) + .unwrap() + .2; + let sierra = SierraProgramDebugReplacer { debug_info }.apply(&sierra); + + programs_compiled.push(ProgramCompiled { + sierra, + abi: contract_class.abi.unwrap(), + }); + } - Ok(vec![ProgramCompiled { - sierra, - abi: contract_class.abi.unwrap(), - }]) + Ok(programs_compiled) } diff --git a/src/core/core_unit.rs b/src/core/core_unit.rs index ed37518..1f73cce 100644 --- a/src/core/core_unit.rs +++ b/src/core/core_unit.rs @@ -10,7 +10,7 @@ use crate::core::compilation_unit::CompilationUnit; pub struct CoreOpts { pub target: PathBuf, pub corelib: Option, - pub contract_path: Option, + pub contract_path: Option>, } pub struct CoreUnit {