Skip to content
Open
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
22cb532
feat: pass $TARGET triple to crate at compile time
lima-limon-inc Nov 3, 2025
e0b66c1
feat: initial TargetTriple implementation
lima-limon-inc Nov 4, 2025
f2cbb16
feat: add Display impl for TargetTriple
lima-limon-inc Nov 4, 2025
3cf9674
feat: implement artifact serialization
lima-limon-inc Nov 4, 2025
8e095e5
feat: add Artifacts to Component
lima-limon-inc Nov 4, 2025
85d1d75
feat: create lib and bin directories before executing the install script
lima-limon-inc Nov 4, 2025
610e10c
feat: download artifacts
lima-limon-inc Nov 5, 2025
734b715
feat: final touches when installing artifacts
lima-limon-inc Nov 5, 2025
53a8aab
feat: add file// support for artifacts
lima-limon-inc Nov 5, 2025
889216c
refactor: move install_artifact to cargo script
lima-limon-inc Nov 5, 2025
3cd188e
feat: obtain curl version from Cargo.toml instead of hardcoding it
lima-limon-inc Nov 6, 2025
9c9212f
refactor: make installation pipeline more linear
lima-limon-inc Nov 6, 2025
0a4ba74
feat: save downloaded file in .tmp, then rename it when finished
lima-limon-inc Nov 6, 2025
a3da0d7
feat: fail in debug builds, continue in release mode
lima-limon-inc Nov 6, 2025
305f5e6
feat: remove test file:// artifact from VM
lima-limon-inc Nov 6, 2025
7727632
feat: add artifact support in libraries
lima-limon-inc Nov 6, 2025
08f3053
feat: add std.masp as an example
lima-limon-inc Nov 6, 2025
a309539
feat: add miden VM Triplet
lima-limon-inc Nov 6, 2025
c18366e
feat: update manifest with new Triplet
lima-limon-inc Nov 6, 2025
6b7c1e8
feat: add miden to the list of wellknown targets
lima-limon-inc Nov 6, 2025
c82f722
chore: reword comments
lima-limon-inc Nov 6, 2025
d8395a7
Merge branch 'main' into fabrizioorsi/i121-artifact-support
lima-limon-inc Nov 10, 2025
d0d2f32
Merge branch 'main' into fabrizioorsi/i121-artifact-support
lima-limon-inc Nov 13, 2025
0b42d98
Merge branch 'main' into fabrizioorsi/i121-artifact-support
lima-limon-inc Nov 13, 2025
eb5d145
Merge branch 'main' into fabrizioorsi/i121-artifact-support
lima-limon-inc Nov 14, 2025
ab2b6de
WIP
lima-limon-inc Nov 14, 2025
7fec7b8
refactor: remove Artifact HashMap in favor of lists
lima-limon-inc Nov 14, 2025
e7a32f0
refactor: take MidenVM artifacts into account
lima-limon-inc Nov 14, 2025
f32fcdc
refactor: remove target from artifact, obtain it from the link itself
lima-limon-inc Nov 25, 2025
31aa2a2
refactor: contains now returns the Option<String> instead of bool
lima-limon-inc Nov 25, 2025
3d138da
refactor: rename Artifact::contains -> Artifact::get_uri_for
lima-limon-inc Nov 25, 2025
54d3b42
nit: make lint
lima-limon-inc Nov 25, 2025
a2d9adb
nit: remove pub indicator from Artifact
lima-limon-inc Nov 25, 2025
40842f4
docs: expand Artifact documentation
lima-limon-inc Nov 25, 2025
d4acf30
nit: remove example artifact uris
lima-limon-inc Nov 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
255 changes: 198 additions & 57 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ upon = { version = "0.9.0", default-features = false, features = [
] }
colored = "3.0.0"

[build-dependencies]
cargo_toml = "0.22.3"

[dev-dependencies]
tempdir = "0.3.7"

Expand Down
28 changes: 28 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,34 @@
use std::process::Command;

use cargo_toml::Manifest;

fn main() {
let toml_contents = std::fs::read("Cargo.toml").expect("Failed to find Cargo.toml");
let manifest =
Manifest::from_slice(&toml_contents).expect("Failed to parse Cargo.toml as Manifest");
let curl_version = {
let curl = manifest
.dependencies
.get("curl")
.expect("Couldn't find curl in parsed manifest");
match curl {
cargo_toml::Dependency::Simple(ver) => ver,
cargo_toml::Dependency::Detailed(detail) => &detail.version.as_ref().unwrap().clone(),
// This case should not happen since we are reading the root Cargo.toml
cargo_toml::Dependency::Inherited(_) => {
panic!("Couldn't determine curl version since it appears as inherited.")
},
}
};
// Pass the $CURL_VERSION to the crate at compile time.
println!("cargo:rustc-env=CURL_VERSION={}", curl_version);

// Pass the $TARGET to the crate at compile time.
println!(
"cargo:rustc-env=TARGET={}",
std::env::var("TARGET").expect("Failed to obtain $TARGET triple constant.")
);

// Generated by cargo at runtime when the build script is run:
// https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts
let build_script = std::env::var("OUT_DIR").unwrap();
Expand Down
16 changes: 14 additions & 2 deletions manifest/channel-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,13 @@
"package": "miden-stdlib",
"version": "0.17.2",
"installed_library": "std.masp",
"library_struct": "miden_stdlib::StdLibrary"
"library_struct": "miden_stdlib::StdLibrary",
"artifacts": [
{
"target": "zkvm-miden-unknown",
"uri": "https://github.com/lima-limon-inc/fabriz.io/releases/download/0.0/std.masp"
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These URLS are not intended to be merged and are only here to test this PR. They should be removed before merging.

}
]
},
{
"name": "base",
Expand Down Expand Up @@ -152,7 +158,13 @@
"send": ["executable", "send"],
"simulate": ["executable", "exec"]
},
"initialization": ["init"]
"initialization": ["init"],
"artifacts": [
{
"target": "aarch64-apple-darwin",
"uri": "https://github.com/lima-limon-inc/fabriz.io/releases/download/0.0/fabrizio"
}
]
},
{
"name": "midenc",
Expand Down
157 changes: 157 additions & 0 deletions src/artifact.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
use std::{fmt::Display, str::FromStr};

use serde::{Deserialize, Serialize};
use thiserror::Error;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Artifacts {
artifacts: Vec<Artifact>,
}

impl Artifacts {
/// Get a URI to download an artifact that's valid for [target].
pub fn get_uri_for(&self, target: &TargetTriple) -> Option<String> {
self.artifacts
.iter()
.find(|artifact| artifact.target == *target)
.map(|arti| arti.uri.clone())
}
}

/// Represents a mapping from a given [target] to the [url] which contains it.
#[derive(Serialize, Deserialize, Debug, Clone)]
struct Artifact {
target: TargetTriple,

uri: String,
}

/// Struct that represents a target architecture by the rust compiler.
/// There is no universal standadarized way to represent them, however,
/// according to the
/// [LLVM documentation](https://llvm.org/doxygen/Triple_8h_source.html),
/// most triples have one of the following two shapes:
/// - "ARCHITECTURE-VENDOR-OPERATING_SYSTEM"
/// - "ARCHITECTURE-VENDOR-OPERATING_SYSTEM-ENVIRONMENT"
///
/// This template does match with two major wellknown targets:
/// aarch64-apple-darwin and x86_64-unknown-linux-gnu.
///
/// There is one *notable* special case which is the Miden VM. MASP Libraries
/// are OS/environent-agnostic, since they target the Miden VM itself. So, they
/// use the following triplet: zkvm-miden-unknown
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct TargetTriple {
architecture: String,
vendor: String,
operating_system: String,
environment: Option<String>,
}

impl serde::ser::Serialize for TargetTriple {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
serializer.serialize_str(&self.to_string())
}
}

impl<'de> serde::de::Deserialize<'de> for TargetTriple {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
s.parse::<Self>().map_err(serde::de::Error::custom)
}
}

#[derive(Error, Debug)]
pub enum TargetTripleError {
#[error("Failed to deserialize TargetTriplet because: {0}")]
UnrecognizedTargetTriple(String),
}

impl FromStr for TargetTriple {
type Err = TargetTripleError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut parts = s.split("-");
let architecture = parts
.next()
.ok_or(TargetTripleError::UnrecognizedTargetTriple(
"Missing 'architecture' field".into(),
))?
.into();
let vendor = parts
.next()
.ok_or(TargetTripleError::UnrecognizedTargetTriple("Missing 'vendor' field".into()))?
.into();
let operating_system = parts
.next()
.ok_or(TargetTripleError::UnrecognizedTargetTriple(
"Missing 'operating_system' field".into(),
))?
.into();
let environment = parts.next().map(String::from);
Ok(TargetTriple {
architecture,
vendor,
operating_system,
environment,
})
}
}

impl Display for TargetTriple {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let repr = format!(
"{}-{}-{}{}",
self.architecture,
self.vendor,
self.operating_system,
self.environment.as_ref().map(|env| format!("-{}", env)).unwrap_or_default()
);
write!(f, "{repr}")
}
}

impl TargetTriple {
pub fn miden_vm() -> TargetTriple {
TargetTriple {
architecture: String::from("zkvm"),
vendor: String::from("miden"),
operating_system: String::from("unknown"),
environment: None,
}
}
}

#[cfg(test)]
mod tests {
use std::str::FromStr;

use super::TargetTriple;

#[test]
/// Test that we can parse triples that we actually support.
fn parse_wellknown_targets() {
let mut failed_parsing = Vec::new();
let well_known_targets =
["aarch64-apple-darwin", "x86_64-unknown-linux-gnu", "zkvm-miden-unknown"];
for target in well_known_targets {
if let Err(err) = TargetTriple::from_str(target) {
failed_parsing.push((target, err));
}
}
if failed_parsing.is_empty() {
return;
}
let err_message = failed_parsing.iter().fold(
String::from("Failed to serialize the following well known targets:"),
|acc, (target, err)| format!("{acc}\n - {target}, because {}", err),
);
panic!("{}", err_message)
}
}
33 changes: 31 additions & 2 deletions src/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ use std::{
collections::{HashMap, HashSet},
fmt::{self, Display},
hash::{Hash, Hasher},
path::PathBuf,
path::{Path, PathBuf},
};

use anyhow::Context;
use serde::{Deserialize, Serialize};

use crate::{
Config, utils,
Config,
artifact::{Artifacts, TargetTriple},
utils,
version::{Authority, GitTarget},
};

Expand Down Expand Up @@ -269,6 +271,14 @@ impl InstalledFile {
InstalledFile::Library { library_struct, .. } => Some(library_struct),
}
}
pub fn get_path_from(&self, toolchain_dir: &Path) -> PathBuf {
match &self {
exe @ InstalledFile::Executable { .. } => {
toolchain_dir.join("bin").join(exe.to_string())
},
lib @ InstalledFile::Library { .. } => toolchain_dir.join("lib").join(lib.to_string()),
}
}
}

impl Display for InstalledFile {
Expand Down Expand Up @@ -399,6 +409,9 @@ pub struct Component {
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub initialization: Vec<String>,
/// Pre-built artifact.
#[serde(flatten)]
artifacts: Option<Artifacts>,
}

impl Component {
Expand All @@ -413,6 +426,7 @@ impl Component {
installed_file: None,
initialization: vec![],
aliases: HashMap::new(),
artifacts: None,
}
}

Expand Down Expand Up @@ -567,6 +581,11 @@ impl Component {
self.call_format.clone()
}
}

/// Returns the URI for a given [target] (if available).
pub fn get_uri_for(&self, target: &TargetTriple) -> Option<String> {
self.artifacts.as_ref().and_then(|artifacts| artifacts.get_uri_for(target))
}
}

/// User-facing channel reference. The main difference with this and [Channel]
Expand Down Expand Up @@ -661,6 +680,7 @@ mod tests {
installed_file: None,
initialization: vec![],
aliases: HashMap::new(),
artifacts: None,
},
Component {
name: std::borrow::Cow::Borrowed("std"),
Expand All @@ -675,6 +695,7 @@ mod tests {
installed_file: None,
initialization: vec![],
aliases: HashMap::new(),
artifacts: None,
},
Component {
name: std::borrow::Cow::Borrowed("removed-component"),
Expand All @@ -689,6 +710,7 @@ mod tests {
installed_file: None,
initialization: vec![],
aliases: HashMap::new(),
artifacts: None,
},
Component {
name: std::borrow::Cow::Borrowed("base"),
Expand All @@ -703,6 +725,7 @@ mod tests {
installed_file: None,
initialization: vec![],
aliases: HashMap::new(),
artifacts: None,
},
];

Expand All @@ -720,6 +743,7 @@ mod tests {
installed_file: None,
initialization: vec![],
aliases: HashMap::new(),
artifacts: None,
},
Component {
name: std::borrow::Cow::Borrowed("std"),
Expand All @@ -734,6 +758,7 @@ mod tests {
installed_file: None,
initialization: vec![],
aliases: HashMap::new(),
artifacts: None,
},
Component {
name: std::borrow::Cow::Borrowed("new-component"),
Expand All @@ -748,6 +773,7 @@ mod tests {
installed_file: None,
initialization: vec![],
aliases: HashMap::new(),
artifacts: None,
},
Component {
name: std::borrow::Cow::Borrowed("base"),
Expand All @@ -762,6 +788,7 @@ mod tests {
installed_file: None,
initialization: vec![],
aliases: HashMap::new(),
artifacts: None,
},
];

Expand Down Expand Up @@ -808,6 +835,7 @@ mod tests {
installed_file: None,
initialization: vec![],
aliases: HashMap::new(),
artifacts: None,
}];

let new_components = [Component {
Expand All @@ -823,6 +851,7 @@ mod tests {
installed_file: None,
initialization: vec![],
aliases: HashMap::new(),
artifacts: None,
}];

let old = Channel {
Expand Down
Loading
Loading