From 6c234310f08c7e6b4e79c362b98ec02cbf35c8a5 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Wed, 17 Jul 2024 02:21:36 +0800 Subject: [PATCH 1/6] feat: allow passing extra cli args to solc --- crates/artifacts/solc/src/lib.rs | 29 ++-- crates/compilers/src/compile/project.rs | 14 +- crates/compilers/src/compilers/mod.rs | 46 +++--- crates/compilers/src/compilers/multi.rs | 63 ++++---- .../compilers/src/compilers/solc/compiler.rs | 4 + crates/compilers/src/compilers/solc/mod.rs | 138 +++++++++++------- crates/compilers/src/compilers/vyper/input.rs | 13 +- .../compilers/src/compilers/vyper/settings.rs | 7 + crates/compilers/src/lib.rs | 7 +- crates/compilers/src/project_util/mod.rs | 3 +- crates/compilers/tests/project.rs | 31 ++-- 11 files changed, 196 insertions(+), 159 deletions(-) diff --git a/crates/artifacts/solc/src/lib.rs b/crates/artifacts/solc/src/lib.rs index 530a0fab..4acaa903 100644 --- a/crates/artifacts/solc/src/lib.rs +++ b/crates/artifacts/solc/src/lib.rs @@ -133,12 +133,12 @@ impl SolcInput { /// This will remove/adjust values in the [`SolcInput`] that are not compatible with this /// version pub fn sanitize(&mut self, version: &Version) { - self.settings.sanitize(version) + self.settings.sanitize(version, self.language); } /// Consumes the type and returns a [SolcInput::sanitized] version pub fn sanitized(mut self, version: &Version) -> Self { - self.settings.sanitize(version); + self.settings.sanitize(version, self.language); self } @@ -178,18 +178,6 @@ impl SolcInput { pub fn is_yul(&self) -> bool { self.language == SolcLanguage::Yul } - - pub fn with_remappings(mut self, remappings: Vec) -> Self { - if self.language == SolcLanguage::Yul { - if !remappings.is_empty() { - warn!("omitting remappings supplied for the yul sources"); - } - } else { - self.settings.remappings = remappings; - } - - self - } } /// A `CompilerInput` representation used for verify @@ -292,13 +280,13 @@ impl Settings { } /// Consumes the type and returns a [Settings::sanitize] version - pub fn sanitized(mut self, version: &Version) -> Self { - self.sanitize(version); + pub fn sanitized(mut self, version: &Version, language: SolcLanguage) -> Self { + self.sanitize(version, language); self } /// This will remove/adjust values in the settings that are not compatible with this version. - pub fn sanitize(&mut self, version: &Version) { + pub fn sanitize(&mut self, version: &Version, language: SolcLanguage) { const V0_6_0: Version = Version::new(0, 6, 0); if *version < V0_6_0 { if let Some(meta) = &mut self.metadata { @@ -364,6 +352,13 @@ impl Settings { if let Some(ref mut evm_version) = self.evm_version { self.evm_version = evm_version.normalize_version_solc(version); } + + if language == SolcLanguage::Yul { + if !self.remappings.is_empty() { + warn!("omitting remappings supplied for the yul sources"); + } + self.remappings = Vec::new(); + } } /// Inserts a set of `ContractOutputSelection` diff --git a/crates/compilers/src/compile/project.rs b/crates/compilers/src/compile/project.rs index 569828eb..8672f2ed 100644 --- a/crates/compilers/src/compile/project.rs +++ b/crates/compilers/src/compile/project.rs @@ -109,7 +109,7 @@ use crate::{ output::{AggregatedCompilerOutput, Builds}, report, resolver::GraphEdges, - ArtifactOutput, Graph, Project, ProjectCompileOutput, Sources, + ArtifactOutput, CompilerSettings, Graph, Project, ProjectCompileOutput, Sources, }; use foundry_compilers_core::error::Result; use rayon::prelude::*; @@ -447,11 +447,13 @@ impl CompilerSources { trace!("calling {} with {} sources {:?}", version, sources.len(), sources.keys()); - let mut input = C::Input::build(sources, opt_settings, language, version.clone()) - .with_base_path(project.paths.root.clone()) - .with_allow_paths(project.paths.allowed_paths.clone()) - .with_include_paths(include_paths.clone()) - .with_remappings(project.paths.remappings.clone()); + let settings = opt_settings + .with_base_path(&project.paths.root) + .with_allow_paths(&project.paths.allowed_paths) + .with_include_paths(&include_paths) + .with_remappings(&project.paths.remappings); + + let mut input = C::Input::build(sources, settings, language, version.clone()); input.strip_prefix(project.paths.root.as_path()); diff --git a/crates/compilers/src/compilers/mod.rs b/crates/compilers/src/compilers/mod.rs index 641f3950..aa4b7230 100644 --- a/crates/compilers/src/compilers/mod.rs +++ b/crates/compilers/src/compilers/mod.rs @@ -74,6 +74,29 @@ pub trait CompilerSettings: /// Ensures that all settings fields are equal except for `output_selection` which is required /// to be a subset of `cached.output_selection`. fn can_use_cached(&self, other: &Self) -> bool; + + /// Method which might be invoked to add remappings to the input. + fn with_remappings(self, _remappings: &[Remapping]) -> Self { + self + } + + /// Builder method to set the base path for the compiler. Primarily used by solc implementation + /// to se --base-path. + fn with_base_path(self, _base_path: &Path) -> Self { + self + } + + /// Builder method to set the allowed paths for the compiler. Primarily used by solc + /// implementation to set --allow-paths. + fn with_allow_paths(self, _allowed_paths: &BTreeSet) -> Self { + self + } + + /// Builder method to set the include paths for the compiler. Primarily used by solc + /// implementation to set --include-paths. + fn with_include_paths(self, _include_paths: &BTreeSet) -> Self { + self + } } /// Input of a compiler, including sources and settings used for their compilation. @@ -101,29 +124,6 @@ pub trait CompilerInput: Serialize + Send + Sync + Sized + Debug { /// Returns compiler name used by reporters to display output during compilation. fn compiler_name(&self) -> Cow<'static, str>; - /// Method which might be invoked to add remappings to the input. - fn with_remappings(self, _remappings: Vec) -> Self { - self - } - - /// Builder method to set the base path for the compiler. Primarily used by solc implementation - /// to se --base-path. - fn with_base_path(self, _base_path: PathBuf) -> Self { - self - } - - /// Builder method to set the allowed paths for the compiler. Primarily used by solc - /// implementation to set --allow-paths. - fn with_allow_paths(self, _allowed_paths: BTreeSet) -> Self { - self - } - - /// Builder method to set the include paths for the compiler. Primarily used by solc - /// implementation to set --include-paths. - fn with_include_paths(self, _include_paths: BTreeSet) -> Self { - self - } - /// Strips given prefix from all paths. fn strip_prefix(&mut self, base: &Path); } diff --git a/crates/compilers/src/compilers/multi.rs b/crates/compilers/src/compilers/multi.rs index bd09a3a4..3ddc76af 100644 --- a/crates/compilers/src/compilers/multi.rs +++ b/crates/compilers/src/compilers/multi.rs @@ -10,13 +10,14 @@ use super::{ use crate::{ artifacts::vyper::{VyperCompilationError, VyperSettings}, resolver::parse::SolData, + solc::SolcSettings, }; use foundry_compilers_artifacts::{ error::SourceLocation, output_selection::OutputSelection, remappings::Remapping, sources::{Source, Sources}, - Error, Settings as SolcSettings, Severity, SolcLanguage, + Error, Severity, SolcLanguage, }; use foundry_compilers_core::error::{Result, SolcError}; use semver::Version; @@ -137,8 +138,36 @@ impl CompilerSettings for MultiCompilerSettings { } fn update_output_selection(&mut self, f: impl FnOnce(&mut OutputSelection) + Copy) { - f(&mut self.solc.output_selection); - f(&mut self.vyper.output_selection); + self.solc.update_output_selection(f); + self.vyper.update_output_selection(f); + } + + fn with_allow_paths(self, allowed_paths: &BTreeSet) -> Self { + Self { + solc: self.solc.with_allow_paths(allowed_paths), + vyper: self.vyper.with_allow_paths(allowed_paths), + } + } + + fn with_base_path(self, base_path: &Path) -> Self { + Self { + solc: self.solc.with_base_path(base_path), + vyper: self.vyper.with_base_path(base_path), + } + } + + fn with_include_paths(self, include_paths: &BTreeSet) -> Self { + Self { + solc: self.solc.with_include_paths(include_paths), + vyper: self.vyper.with_include_paths(include_paths), + } + } + + fn with_remappings(self, remappings: &[Remapping]) -> Self { + Self { + solc: self.solc.with_remappings(remappings), + vyper: self.vyper.with_remappings(remappings), + } } } @@ -210,34 +239,6 @@ impl CompilerInput for MultiCompilerInput { } } - fn with_allow_paths(self, allowed_paths: BTreeSet) -> Self { - match self { - Self::Solc(input) => Self::Solc(input.with_allow_paths(allowed_paths)), - Self::Vyper(input) => Self::Vyper(input.with_allow_paths(allowed_paths)), - } - } - - fn with_base_path(self, base_path: PathBuf) -> Self { - match self { - Self::Solc(input) => Self::Solc(input.with_base_path(base_path)), - Self::Vyper(input) => Self::Vyper(input.with_base_path(base_path)), - } - } - - fn with_include_paths(self, include_paths: BTreeSet) -> Self { - match self { - Self::Solc(input) => Self::Solc(input.with_include_paths(include_paths)), - Self::Vyper(input) => Self::Vyper(input.with_include_paths(include_paths)), - } - } - - fn with_remappings(self, remappings: Vec) -> Self { - match self { - Self::Solc(input) => Self::Solc(input.with_remappings(remappings)), - Self::Vyper(input) => Self::Vyper(input.with_remappings(remappings)), - } - } - fn sources(&self) -> impl Iterator { let ret: Box> = match self { Self::Solc(input) => Box::new(input.sources()), diff --git a/crates/compilers/src/compilers/solc/compiler.rs b/crates/compilers/src/compilers/solc/compiler.rs index 1071962c..b95b8e4f 100644 --- a/crates/compilers/src/compilers/solc/compiler.rs +++ b/crates/compilers/src/compilers/solc/compiler.rs @@ -80,6 +80,8 @@ pub struct Solc { pub allow_paths: BTreeSet, /// Value for --include-paths arg. pub include_paths: BTreeSet, + /// Additional arbitrary arguments. + pub extra_args: Vec, } impl Solc { @@ -100,6 +102,7 @@ impl Solc { base_path: None, allow_paths: Default::default(), include_paths: Default::default(), + extra_args: Default::default(), } } @@ -475,6 +478,7 @@ impl Solc { cmd.current_dir(base_path); } + cmd.args(&self.extra_args); cmd.arg("--standard-json"); cmd diff --git a/crates/compilers/src/compilers/solc/mod.rs b/crates/compilers/src/compilers/solc/mod.rs index 940056f2..8f43d4ec 100644 --- a/crates/compilers/src/compilers/solc/mod.rs +++ b/crates/compilers/src/compilers/solc/mod.rs @@ -9,7 +9,7 @@ use foundry_compilers_artifacts::{ output_selection::OutputSelection, remappings::Remapping, sources::{Source, Sources}, - Error, Settings as SolcSettings, Severity, SolcInput, + Error, Settings, Severity, SolcInput, }; use foundry_compilers_core::error::Result; use itertools::Itertools; @@ -18,6 +18,7 @@ use serde::{Deserialize, Serialize}; use std::{ borrow::Cow, collections::BTreeSet, + ops::{Deref, DerefMut}, path::{Path, PathBuf}, }; mod compiler; @@ -51,9 +52,9 @@ impl Compiler for SolcCompiler { #[cfg(feature = "svm-solc")] Self::AutoDetect => Solc::find_or_install(&input.version)?, }; - solc.base_path.clone_from(&input.base_path); - solc.allow_paths.clone_from(&input.allow_paths); - solc.include_paths.clone_from(&input.include_paths); + solc.base_path.clone_from(&input.cli_settings.base_path); + solc.allow_paths.clone_from(&input.cli_settings.allow_paths); + solc.include_paths.clone_from(&input.cli_settings.include_paths); let solc_output = solc.compile(&input.input)?; @@ -106,9 +107,8 @@ pub struct SolcVersionedInput { pub version: Version, #[serde(flatten)] pub input: SolcInput, - pub allow_paths: BTreeSet, - pub base_path: Option, - pub include_paths: BTreeSet, + #[serde(flatten)] + cli_settings: CLISettings, } impl CompilerInput for SolcVersionedInput { @@ -125,15 +125,10 @@ impl CompilerInput for SolcVersionedInput { language: Self::Language, version: Version, ) -> Self { + let SolcSettings { settings, cli_settings } = settings; let input = SolcInput::new(language, sources, settings).sanitized(&version); - Self { - version, - input, - base_path: None, - include_paths: Default::default(), - allow_paths: Default::default(), - } + Self { version, input, cli_settings } } fn language(&self) -> Self::Language { @@ -148,12 +143,6 @@ impl CompilerInput for SolcVersionedInput { self.input.sources.iter().map(|(path, source)| (path.as_path(), source)) } - fn with_remappings(mut self, remappings: Vec) -> Self { - self.input = self.input.with_remappings(remappings); - - self - } - fn compiler_name(&self) -> Cow<'static, str> { "Solc".into() } @@ -161,52 +150,99 @@ impl CompilerInput for SolcVersionedInput { fn strip_prefix(&mut self, base: &Path) { self.input.strip_prefix(base); } +} - fn with_allow_paths(mut self, allowed_paths: BTreeSet) -> Self { - self.allow_paths = allowed_paths; - self - } +#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct CLISettings { + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub extra_args: Vec, + #[serde(default, skip_serializing_if = "BTreeSet::is_empty")] + pub allow_paths: BTreeSet, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub base_path: Option, + #[serde(default, skip_serializing_if = "BTreeSet::is_empty")] + pub include_paths: BTreeSet, +} - fn with_base_path(mut self, base_path: PathBuf) -> Self { - self.base_path = Some(base_path); - self +#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)] +pub struct SolcSettings { + /// JSON settings expected by Solc + #[serde(flatten)] + pub settings: Settings, + /// Additional CLI args configuration + #[serde(flatten)] + pub cli_settings: CLISettings, +} + +impl Deref for SolcSettings { + type Target = Settings; + + fn deref(&self) -> &Self::Target { + &self.settings } +} - fn with_include_paths(mut self, include_paths: BTreeSet) -> Self { - self.include_paths = include_paths; - self +impl DerefMut for SolcSettings { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.settings } } impl CompilerSettings for SolcSettings { fn update_output_selection(&mut self, f: impl FnOnce(&mut OutputSelection) + Copy) { - f(&mut self.output_selection) + f(&mut self.settings.output_selection) } fn can_use_cached(&self, other: &Self) -> bool { let Self { - stop_after, - remappings, - optimizer, - model_checker, - metadata, - output_selection, - evm_version, - via_ir, - debug, - libraries, + settings: + Settings { + stop_after, + remappings, + optimizer, + model_checker, + metadata, + output_selection, + evm_version, + via_ir, + debug, + libraries, + }, + .. } = self; - *stop_after == other.stop_after - && *remappings == other.remappings - && *optimizer == other.optimizer - && *model_checker == other.model_checker - && *metadata == other.metadata - && *evm_version == other.evm_version - && *via_ir == other.via_ir - && *debug == other.debug - && *libraries == other.libraries - && output_selection.is_subset_of(&other.output_selection) + *stop_after == other.settings.stop_after + && *remappings == other.settings.remappings + && *optimizer == other.settings.optimizer + && *model_checker == other.settings.model_checker + && *metadata == other.settings.metadata + && *evm_version == other.settings.evm_version + && *via_ir == other.settings.via_ir + && *debug == other.settings.debug + && *libraries == other.settings.libraries + && output_selection.is_subset_of(&other.settings.output_selection) + } + + fn with_remappings(mut self, remappings: &[Remapping]) -> Self { + self.settings.remappings = remappings.to_vec(); + + self + } + + fn with_allow_paths(mut self, allowed_paths: &BTreeSet) -> Self { + self.cli_settings.allow_paths = allowed_paths.clone(); + self + } + + fn with_base_path(mut self, base_path: &Path) -> Self { + self.cli_settings.base_path = Some(base_path.to_path_buf()); + self + } + + fn with_include_paths(mut self, include_paths: &BTreeSet) -> Self { + self.cli_settings.include_paths = include_paths.clone(); + self } } diff --git a/crates/compilers/src/compilers/vyper/input.rs b/crates/compilers/src/compilers/vyper/input.rs index 49e779d9..928c8f97 100644 --- a/crates/compilers/src/compilers/vyper/input.rs +++ b/crates/compilers/src/compilers/vyper/input.rs @@ -6,11 +6,7 @@ use crate::{ use foundry_compilers_artifacts::sources::{Source, Sources}; use semver::Version; use serde::Serialize; -use std::{ - borrow::Cow, - collections::BTreeSet, - path::{Path, PathBuf}, -}; +use std::{borrow::Cow, path::Path}; pub const VYPER_SEARCH_PATHS: Version = Version::new(0, 4, 0); @@ -58,11 +54,4 @@ impl CompilerInput for VyperVersionedInput { .chain(self.input.interfaces.iter()) .map(|(path, source)| (path.as_path(), source)) } - - fn with_include_paths(mut self, include_paths: BTreeSet) -> Self { - if self.version >= VYPER_SEARCH_PATHS { - self.input.settings.search_paths = Some(include_paths); - } - self - } } diff --git a/crates/compilers/src/compilers/vyper/settings.rs b/crates/compilers/src/compilers/vyper/settings.rs index 96f54129..233ab194 100644 --- a/crates/compilers/src/compilers/vyper/settings.rs +++ b/crates/compilers/src/compilers/vyper/settings.rs @@ -1,3 +1,5 @@ +use std::{collections::BTreeSet, path::PathBuf}; + pub use crate::artifacts::vyper::VyperSettings; use crate::compilers::CompilerSettings; use foundry_compilers_artifacts::output_selection::OutputSelection; @@ -16,4 +18,9 @@ impl CompilerSettings for VyperSettings { && output_selection.is_subset_of(&other.output_selection) && search_paths == &other.search_paths } + + fn with_include_paths(mut self, include_paths: &BTreeSet) -> Self { + self.search_paths = Some(include_paths.clone()); + self + } } diff --git a/crates/compilers/src/lib.rs b/crates/compilers/src/lib.rs index 034f2a65..6689821e 100644 --- a/crates/compilers/src/lib.rs +++ b/crates/compilers/src/lib.rs @@ -52,13 +52,14 @@ use derivative::Derivative; use foundry_compilers_artifacts::solc::{ output_selection::OutputSelection, sources::{Source, SourceCompilationKind, Sources}, - Contract, Settings, Severity, SourceFile, StandardJsonCompilerInput, + Contract, Severity, SourceFile, StandardJsonCompilerInput, }; use foundry_compilers_core::error::{Result, SolcError, SolcIoError}; use output::sources::{VersionedSourceFile, VersionedSourceFiles}; use project::ProjectCompiler; use semver::Version; use solang_parser::pt::SourceUnitPart; +use solc::SolcSettings; use std::{ collections::{BTreeMap, HashMap, HashSet}, fs, @@ -148,7 +149,7 @@ impl Project { impl Project where - C::Settings: Into, + C::Settings: Into, { /// Returns standard-json-input to compile the target contract pub fn standard_json_input(&self, target: &Path) -> Result { @@ -186,7 +187,7 @@ where .map(|r| r.into_relative(self.root()).to_relative_remapping()) .collect::>(); - let input = StandardJsonCompilerInput::new(sources, settings); + let input = StandardJsonCompilerInput::new(sources, settings.settings); Ok(input) } diff --git a/crates/compilers/src/project_util/mod.rs b/crates/compilers/src/project_util/mod.rs index c13632ff..36fa73d8 100644 --- a/crates/compilers/src/project_util/mod.rs +++ b/crates/compilers/src/project_util/mod.rs @@ -7,6 +7,7 @@ use crate::{ Compiler, }, config::ProjectPathsConfigBuilder, + solc::SolcSettings, Artifact, ArtifactOutput, Artifacts, ConfigurableArtifacts, HardhatArtifacts, PathStyle, Project, ProjectBuilder, ProjectCompileOutput, ProjectPathsConfig, }; @@ -47,7 +48,7 @@ impl TempProject { /// Overwrites the settings to pass to `solc` pub fn with_solc_settings(mut self, settings: impl Into) -> Self { - self.inner.settings.solc = settings.into(); + self.inner.settings.solc = SolcSettings { settings: settings.into(), ..Default::default() }; self } diff --git a/crates/compilers/tests/project.rs b/crates/compilers/tests/project.rs index c8b25ff7..2ab50590 100644 --- a/crates/compilers/tests/project.rs +++ b/crates/compilers/tests/project.rs @@ -15,6 +15,7 @@ use foundry_compilers::{ flatten::Flattener, info::ContractInfo, project_util::*, + solc::SolcSettings, take_solc_installer_lock, Artifact, ConfigurableArtifacts, ExtraOutputValues, Graph, Project, ProjectBuilder, ProjectCompileOutput, ProjectPathsConfig, TestFileFilter, }; @@ -134,7 +135,7 @@ fn can_compile_dapp_sample() { assert!(compiled.find_first("Dapp").is_some()); assert!(compiled.is_unchanged()); - let cache = CompilerCache::::read(project.cache_path()).unwrap(); + let cache = CompilerCache::::read(project.cache_path()).unwrap(); // delete artifacts std::fs::remove_dir_all(&project.paths().artifacts).unwrap(); @@ -142,7 +143,7 @@ fn can_compile_dapp_sample() { assert!(compiled.find_first("Dapp").is_some()); assert!(!compiled.is_unchanged()); - let updated_cache = CompilerCache::::read(project.cache_path()).unwrap(); + let updated_cache = CompilerCache::::read(project.cache_path()).unwrap(); assert_eq!(cache, updated_cache); } @@ -163,7 +164,7 @@ fn can_compile_yul_sample() { assert!(compiled.find_first("SimpleStore").is_some()); assert!(compiled.is_unchanged()); - let cache = CompilerCache::::read(project.cache_path()).unwrap(); + let cache = CompilerCache::::read(project.cache_path()).unwrap(); // delete artifacts std::fs::remove_dir_all(&project.paths().artifacts).unwrap(); @@ -172,7 +173,7 @@ fn can_compile_yul_sample() { assert!(compiled.find_first("SimpleStore").is_some()); assert!(!compiled.is_unchanged()); - let updated_cache = CompilerCache::::read(project.cache_path()).unwrap(); + let updated_cache = CompilerCache::::read(project.cache_path()).unwrap(); assert_eq!(cache, updated_cache); } @@ -250,7 +251,7 @@ fn can_compile_dapp_detect_changes_in_libs() { assert!(compiled.find_first("Foo").is_some()); assert!(compiled.is_unchanged()); - let cache = CompilerCache::::read(&project.paths().cache).unwrap(); + let cache = CompilerCache::::read(&project.paths().cache).unwrap(); assert_eq!(cache.files.len(), 2); // overwrite lib @@ -324,7 +325,7 @@ fn can_compile_dapp_detect_changes_in_sources() { assert!(compiled.find_first("DssSpellTest").is_some()); assert!(compiled.find_first("DssSpellTestBase").is_some()); - let cache = CompilerCache::::read(&project.paths().cache).unwrap(); + let cache = CompilerCache::::read(&project.paths().cache).unwrap(); assert_eq!(cache.files.len(), 2); let artifacts = compiled.into_artifacts().collect::>(); @@ -2774,7 +2775,7 @@ fn can_compile_model_checker_sample() { let paths = ProjectPathsConfig::builder().sources(root); let mut project = TempProject::::new(paths).unwrap(); - project.project_mut().settings.solc.model_checker = Some(ModelCheckerSettings { + project.project_mut().settings.solc.settings.model_checker = Some(ModelCheckerSettings { engine: Some(CHC), timeout: Some(10000), ..Default::default() @@ -2970,7 +2971,7 @@ fn can_purge_obsolete_artifacts() { fn can_parse_notice() { let mut project = TempProject::::dapptools().unwrap(); project.project_mut().artifacts.additional_values.userdoc = true; - project.project_mut().settings.solc = project.project_mut().artifacts.solc_settings(); + project.project_mut().settings.solc.settings = project.project_mut().artifacts.solc_settings(); let contract = r" pragma solidity $VERSION; @@ -3050,7 +3051,7 @@ fn can_parse_doc() { let mut project = TempProject::::dapptools().unwrap(); project.project_mut().artifacts.additional_values.userdoc = true; project.project_mut().artifacts.additional_values.devdoc = true; - project.project_mut().settings.solc = project.project_mut().artifacts.solc_settings(); + project.project_mut().settings.solc.settings = project.project_mut().artifacts.solc_settings(); let contract = r" // SPDX-License-Identifier: GPL-3.0-only @@ -3272,7 +3273,7 @@ contract D { } let compiled = project.compile().unwrap(); compiled.assert_success(); - let cache = CompilerCache::::read(project.cache_path()).unwrap(); + let cache = CompilerCache::::read(project.cache_path()).unwrap(); let entries = vec![ PathBuf::from("src/A.sol"), @@ -3282,7 +3283,7 @@ contract D { } ]; assert_eq!(entries, cache.files.keys().cloned().collect::>()); - let cache = CompilerCache::::read_joined(project.paths()).unwrap(); + let cache = CompilerCache::::read_joined(project.paths()).unwrap(); assert_eq!( entries.into_iter().map(|p| project.root().join(p)).collect::>(), @@ -3371,7 +3372,7 @@ fn can_handle_conflicting_files() { let artifacts = compiled.artifacts().count(); assert_eq!(artifacts, 2); - let cache = CompilerCache::::read(project.cache_path()).unwrap(); + let cache = CompilerCache::::read(project.cache_path()).unwrap(); let mut source_files = cache.files.keys().cloned().collect::>(); source_files.sort_unstable(); @@ -3440,7 +3441,7 @@ fn can_handle_conflicting_files_recompile() { let artifacts = compiled.artifacts().count(); assert_eq!(artifacts, 2); - let cache = CompilerCache::::read(project.cache_path()).unwrap(); + let cache = CompilerCache::::read(project.cache_path()).unwrap(); let mut source_files = cache.files.keys().cloned().collect::>(); source_files.sort_unstable(); @@ -3537,7 +3538,7 @@ fn can_handle_conflicting_files_case_sensitive_recompile() { let artifacts = compiled.artifacts().count(); assert_eq!(artifacts, 2); - let cache = CompilerCache::::read(project.cache_path()).unwrap(); + let cache = CompilerCache::::read(project.cache_path()).unwrap(); let mut source_files = cache.files.keys().cloned().collect::>(); source_files.sort_unstable(); @@ -3643,7 +3644,7 @@ fn can_detect_config_changes() { let compiled = project.compile().unwrap(); assert!(compiled.is_unchanged()); - project.project_mut().settings.solc.optimizer.enabled = Some(true); + project.project_mut().settings.solc.settings.optimizer.enabled = Some(true); let compiled = project.compile().unwrap(); compiled.assert_success(); From ea5fbb979059cb6b53ae05150091407b9136bbe9 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Wed, 17 Jul 2024 02:27:07 +0800 Subject: [PATCH 2/6] sanitize vyper --- crates/artifacts/vyper/Cargo.toml | 1 + crates/artifacts/vyper/src/input.rs | 13 +++++++++++++ crates/artifacts/vyper/src/settings.rs | 18 ++++++++++++++++++ crates/compilers/src/compilers/vyper/input.rs | 2 -- 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/crates/artifacts/vyper/Cargo.toml b/crates/artifacts/vyper/Cargo.toml index 73446f5e..bb019f40 100644 --- a/crates/artifacts/vyper/Cargo.toml +++ b/crates/artifacts/vyper/Cargo.toml @@ -21,6 +21,7 @@ foundry-compilers-core.workspace = true serde.workspace = true alloy-primitives.workspace = true alloy-json-abi.workspace = true +semver.workspace = true [target.'cfg(windows)'.dependencies] path-slash.workspace = true diff --git a/crates/artifacts/vyper/src/input.rs b/crates/artifacts/vyper/src/input.rs index 409f3694..7b99b79a 100644 --- a/crates/artifacts/vyper/src/input.rs +++ b/crates/artifacts/vyper/src/input.rs @@ -1,6 +1,7 @@ use super::VyperSettings; use foundry_compilers_artifacts_solc::sources::Sources; use foundry_compilers_core::utils::strip_prefix_owned; +use semver::Version; use serde::{Deserialize, Serialize}; use std::path::Path; @@ -47,4 +48,16 @@ impl VyperInput { self.settings.strip_prefix(base) } + + /// This will remove/adjust values in the [`VyperInput`] that are not compatible with this + /// version + pub fn sanitize(&mut self, version: &Version) { + self.settings.sanitize(version); + } + + /// Consumes the type and returns a [VyperInput::sanitized] version + pub fn sanitized(mut self, version: &Version) -> Self { + self.sanitize(version); + self + } } diff --git a/crates/artifacts/vyper/src/settings.rs b/crates/artifacts/vyper/src/settings.rs index 97d95e20..6d789f9d 100644 --- a/crates/artifacts/vyper/src/settings.rs +++ b/crates/artifacts/vyper/src/settings.rs @@ -1,12 +1,15 @@ use foundry_compilers_artifacts_solc::{ output_selection::OutputSelection, serde_helpers, EvmVersion, }; +use semver::Version; use serde::{Deserialize, Serialize}; use std::{ collections::BTreeSet, path::{Path, PathBuf}, }; +pub const VYPER_SEARCH_PATHS: Version = Version::new(0, 4, 0); + #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum VyperOptimizationMode { @@ -68,4 +71,19 @@ impl VyperSettings { }) }); } + + /// Sanitize the settings based on the compiler version. + pub fn sanitize(&mut self, version: &Version) { + if version < &VYPER_SEARCH_PATHS { + self.search_paths = None; + } + + self.sanitize_output_selection(); + } + + /// Sanitize the settings based on the compiler version. + pub fn sanitized(mut self, version: &Version) -> Self { + self.sanitize(version); + self + } } diff --git a/crates/compilers/src/compilers/vyper/input.rs b/crates/compilers/src/compilers/vyper/input.rs index 928c8f97..0401e6a1 100644 --- a/crates/compilers/src/compilers/vyper/input.rs +++ b/crates/compilers/src/compilers/vyper/input.rs @@ -8,8 +8,6 @@ use semver::Version; use serde::Serialize; use std::{borrow::Cow, path::Path}; -pub const VYPER_SEARCH_PATHS: Version = Version::new(0, 4, 0); - #[derive(Clone, Debug, Serialize)] pub struct VyperVersionedInput { #[serde(flatten)] From 186daa1c4d0e0035ab9cf7eb2e64de093f524853 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Wed, 17 Jul 2024 02:30:21 +0800 Subject: [PATCH 3/6] respect extra args --- crates/compilers/src/compilers/solc/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/compilers/src/compilers/solc/mod.rs b/crates/compilers/src/compilers/solc/mod.rs index 8f43d4ec..8a3db97e 100644 --- a/crates/compilers/src/compilers/solc/mod.rs +++ b/crates/compilers/src/compilers/solc/mod.rs @@ -55,6 +55,7 @@ impl Compiler for SolcCompiler { solc.base_path.clone_from(&input.cli_settings.base_path); solc.allow_paths.clone_from(&input.cli_settings.allow_paths); solc.include_paths.clone_from(&input.cli_settings.include_paths); + solc.extra_args.clone_from(&input.cli_settings.extra_args); let solc_output = solc.compile(&input.input)?; From 77895fdc0013febb4a236037b11e8c45c12685a1 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Wed, 17 Jul 2024 02:34:31 +0800 Subject: [PATCH 4/6] clippy --- crates/compilers/src/compilers/solc/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/compilers/src/compilers/solc/mod.rs b/crates/compilers/src/compilers/solc/mod.rs index 8a3db97e..194b5bf0 100644 --- a/crates/compilers/src/compilers/solc/mod.rs +++ b/crates/compilers/src/compilers/solc/mod.rs @@ -232,7 +232,7 @@ impl CompilerSettings for SolcSettings { } fn with_allow_paths(mut self, allowed_paths: &BTreeSet) -> Self { - self.cli_settings.allow_paths = allowed_paths.clone(); + self.cli_settings.allow_paths.clone_from(allowed_paths); self } @@ -242,7 +242,7 @@ impl CompilerSettings for SolcSettings { } fn with_include_paths(mut self, include_paths: &BTreeSet) -> Self { - self.cli_settings.include_paths = include_paths.clone(); + self.cli_settings.include_paths.clone_from(include_paths); self } } From dd1ae311ebf784269b3f0c47100d56bceeac30d3 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Wed, 17 Jul 2024 02:54:37 +0800 Subject: [PATCH 5/6] doctests --- crates/compilers/src/cache.rs | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/crates/compilers/src/cache.rs b/crates/compilers/src/cache.rs index f91ad1ad..f6aa5b1c 100644 --- a/crates/compilers/src/cache.rs +++ b/crates/compilers/src/cache.rs @@ -103,10 +103,10 @@ impl CompilerCache { /// # Examples #[cfg_attr(not(feature = "svm-solc"), doc = "```ignore")] /// ```no_run - /// use foundry_compilers::{artifacts::Settings, cache::CompilerCache, Project}; + /// use foundry_compilers::{cache::CompilerCache, solc::SolcSettings, Project}; /// /// let project = Project::builder().build(Default::default())?; - /// let mut cache = CompilerCache::::read(project.cache_path())?; + /// let mut cache = CompilerCache::::read(project.cache_path())?; /// cache.join_artifacts_files(project.artifacts_path()); /// # Ok::<_, Box>(()) /// ``` @@ -129,10 +129,10 @@ impl CompilerCache { /// # Examples #[cfg_attr(not(feature = "svm-solc"), doc = "```ignore")] /// ```no_run - /// use foundry_compilers::{artifacts::Settings, cache::CompilerCache, Project}; + /// use foundry_compilers::{cache::CompilerCache, solc::SolcSettings, Project}; /// /// let project = Project::builder().build(Default::default())?; - /// let cache: CompilerCache = CompilerCache::read_joined(&project.paths)?; + /// let cache: CompilerCache = CompilerCache::read_joined(&project.paths)?; /// # Ok::<_, Box>(()) /// ``` pub fn read_joined(paths: &ProjectPathsConfig) -> Result { @@ -210,13 +210,11 @@ impl CompilerCache { #[cfg_attr(not(feature = "svm-solc"), doc = "```ignore")] /// ```no_run /// use foundry_compilers::{ - /// artifacts::{contract::CompactContract, Settings}, - /// cache::CompilerCache, - /// Project, + /// artifacts::contract::CompactContract, cache::CompilerCache, solc::SolcSettings, Project, /// }; /// /// let project = Project::builder().build(Default::default())?; - /// let cache: CompilerCache = + /// let cache: CompilerCache = /// CompilerCache::read(project.cache_path())?.with_stripped_file_prefixes(project.root()); /// let artifact: CompactContract = cache.read_artifact("src/Greeter.sol".as_ref(), "Greeter")?; /// # Ok::<_, Box>(()) @@ -237,10 +235,10 @@ impl CompilerCache { /// # Examples #[cfg_attr(not(feature = "svm-solc"), doc = "```ignore")] /// ```no_run - /// use foundry_compilers::{artifacts::Settings, cache::CompilerCache, Project}; + /// use foundry_compilers::{cache::CompilerCache, solc::SolcSettings, Project}; /// /// let project = Project::builder().build(Default::default())?; - /// let cache: CompilerCache = CompilerCache::read_joined(&project.paths)?; + /// let cache: CompilerCache = CompilerCache::read_joined(&project.paths)?; /// cache.find_artifact_path("/Users/git/myproject/src/Greeter.sol".as_ref(), "Greeter"); /// # Ok::<_, Box>(()) /// ``` @@ -256,13 +254,11 @@ impl CompilerCache { #[cfg_attr(not(feature = "svm-solc"), doc = "```ignore")] /// ```no_run /// use foundry_compilers::{ - /// artifacts::{contract::CompactContract, Settings}, - /// cache::CompilerCache, - /// Project, + /// artifacts::contract::CompactContract, cache::CompilerCache, solc::SolcSettings, Project, /// }; /// /// let project = Project::builder().build(Default::default())?; - /// let cache = CompilerCache::::read_joined(&project.paths)?; + /// let cache = CompilerCache::::read_joined(&project.paths)?; /// let artifact: CompactContract = /// cache.read_artifact("/Users/git/myproject/src/Greeter.sol".as_ref(), "Greeter")?; /// # Ok::<_, Box>(()) @@ -288,13 +284,12 @@ impl CompilerCache { #[cfg_attr(not(feature = "svm-solc"), doc = "```ignore")] /// ```no_run /// use foundry_compilers::{ - /// artifacts::{contract::CompactContractBytecode, Settings}, - /// cache::CompilerCache, + /// artifacts::contract::CompactContractBytecode, cache::CompilerCache, solc::SolcSettings, /// Project, /// }; /// /// let project = Project::builder().build(Default::default())?; - /// let cache: CompilerCache = CompilerCache::read_joined(&project.paths)?; + /// let cache: CompilerCache = CompilerCache::read_joined(&project.paths)?; /// let artifacts = cache.read_artifacts::()?; /// # Ok::<_, Box>(()) /// ``` From abc909a3a140391dc45a03953e13914370dfc191 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Wed, 17 Jul 2024 17:55:06 +0800 Subject: [PATCH 6/6] rename --- crates/compilers/src/compilers/solc/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/compilers/src/compilers/solc/mod.rs b/crates/compilers/src/compilers/solc/mod.rs index 194b5bf0..a6bcd95d 100644 --- a/crates/compilers/src/compilers/solc/mod.rs +++ b/crates/compilers/src/compilers/solc/mod.rs @@ -109,7 +109,7 @@ pub struct SolcVersionedInput { #[serde(flatten)] pub input: SolcInput, #[serde(flatten)] - cli_settings: CLISettings, + cli_settings: CliSettings, } impl CompilerInput for SolcVersionedInput { @@ -155,7 +155,7 @@ impl CompilerInput for SolcVersionedInput { #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)] #[serde(rename_all = "camelCase")] -pub struct CLISettings { +pub struct CliSettings { #[serde(default, skip_serializing_if = "Vec::is_empty")] pub extra_args: Vec, #[serde(default, skip_serializing_if = "BTreeSet::is_empty")] @@ -173,7 +173,7 @@ pub struct SolcSettings { pub settings: Settings, /// Additional CLI args configuration #[serde(flatten)] - pub cli_settings: CLISettings, + pub cli_settings: CliSettings, } impl Deref for SolcSettings {