Skip to content

Commit

Permalink
feat: allow passing extra cli args to solc + some cleanup (#171)
Browse files Browse the repository at this point in the history
This refactors `Compiler` a bit moving some of the configuration methods
from `CompilerInput` to `CompilerSettings`, preferring sanitization of
settings during input construction instead of in `with_*` methods of
version-aware input.

Instead of using JSON solc settings, I've added separate `SolcSettings`
type divided into JSON and CLI settings
  • Loading branch information
klkvr authored Jul 17, 2024
1 parent b04423c commit db66310
Show file tree
Hide file tree
Showing 15 changed files with 241 additions and 178 deletions.
29 changes: 12 additions & 17 deletions crates/artifacts/solc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -178,18 +178,6 @@ impl SolcInput {
pub fn is_yul(&self) -> bool {
self.language == SolcLanguage::Yul
}

pub fn with_remappings(mut self, remappings: Vec<Remapping>) -> 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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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`
Expand Down
1 change: 1 addition & 0 deletions crates/artifacts/vyper/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions crates/artifacts/vyper/src/input.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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
}
}
18 changes: 18 additions & 0 deletions crates/artifacts/vyper/src/settings.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -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
}
}
29 changes: 12 additions & 17 deletions crates/compilers/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,10 @@ impl<S: CompilerSettings> CompilerCache<S> {
/// # 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::<Settings>::read(project.cache_path())?;
/// let mut cache = CompilerCache::<SolcSettings>::read(project.cache_path())?;
/// cache.join_artifacts_files(project.artifacts_path());
/// # Ok::<_, Box<dyn std::error::Error>>(())
/// ```
Expand All @@ -129,10 +129,10 @@ impl<S: CompilerSettings> CompilerCache<S> {
/// # 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<Settings> = CompilerCache::read_joined(&project.paths)?;
/// let cache: CompilerCache<SolcSettings> = CompilerCache::read_joined(&project.paths)?;
/// # Ok::<_, Box<dyn std::error::Error>>(())
/// ```
pub fn read_joined<L>(paths: &ProjectPathsConfig<L>) -> Result<Self> {
Expand Down Expand Up @@ -210,13 +210,11 @@ impl<S: CompilerSettings> CompilerCache<S> {
#[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<Settings> =
/// let cache: CompilerCache<SolcSettings> =
/// 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<dyn std::error::Error>>(())
Expand All @@ -237,10 +235,10 @@ impl<S: CompilerSettings> CompilerCache<S> {
/// # 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<Settings> = CompilerCache::read_joined(&project.paths)?;
/// let cache: CompilerCache<SolcSettings> = CompilerCache::read_joined(&project.paths)?;
/// cache.find_artifact_path("/Users/git/myproject/src/Greeter.sol".as_ref(), "Greeter");
/// # Ok::<_, Box<dyn std::error::Error>>(())
/// ```
Expand All @@ -256,13 +254,11 @@ impl<S: CompilerSettings> CompilerCache<S> {
#[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::<Settings>::read_joined(&project.paths)?;
/// let cache = CompilerCache::<SolcSettings>::read_joined(&project.paths)?;
/// let artifact: CompactContract =
/// cache.read_artifact("/Users/git/myproject/src/Greeter.sol".as_ref(), "Greeter")?;
/// # Ok::<_, Box<dyn std::error::Error>>(())
Expand All @@ -288,13 +284,12 @@ impl<S: CompilerSettings> CompilerCache<S> {
#[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<Settings> = CompilerCache::read_joined(&project.paths)?;
/// let cache: CompilerCache<SolcSettings> = CompilerCache::read_joined(&project.paths)?;
/// let artifacts = cache.read_artifacts::<CompactContractBytecode>()?;
/// # Ok::<_, Box<dyn std::error::Error>>(())
/// ```
Expand Down
14 changes: 8 additions & 6 deletions crates/compilers/src/compile/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand Down Expand Up @@ -447,11 +447,13 @@ impl<L: Language> CompilerSources<L> {

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());

Expand Down
46 changes: 23 additions & 23 deletions crates/compilers/src/compilers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<PathBuf>) -> 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<PathBuf>) -> Self {
self
}
}

/// Input of a compiler, including sources and settings used for their compilation.
Expand Down Expand Up @@ -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<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: 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<PathBuf>) -> 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<PathBuf>) -> Self {
self
}

/// Strips given prefix from all paths.
fn strip_prefix(&mut self, base: &Path);
}
Expand Down
63 changes: 32 additions & 31 deletions crates/compilers/src/compilers/multi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<PathBuf>) -> 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<PathBuf>) -> 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),
}
}
}

Expand Down Expand Up @@ -210,34 +239,6 @@ impl CompilerInput for MultiCompilerInput {
}
}

fn with_allow_paths(self, allowed_paths: BTreeSet<PathBuf>) -> 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<PathBuf>) -> 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<Remapping>) -> 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<Item = (&Path, &Source)> {
let ret: Box<dyn Iterator<Item = _>> = match self {
Self::Solc(input) => Box::new(input.sources()),
Expand Down
Loading

0 comments on commit db66310

Please sign in to comment.