Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
30 changes: 30 additions & 0 deletions midenc-compile/src/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,18 @@ fn cargo_build(
source_manager: Arc<dyn SourceManager + Send + Sync>,
) -> CompilerResult<Arc<miden_mast_package::Package>> {
let package_name = package.name().to_string();
// The directory of the dependency being compiled, captured before `manifest_path` is consumed
// below. The compiled package is materialized under this directory's `target` (see the end of
// this function).
let dependency_dir = manifest_path
.parent()
.ok_or_else(|| {
Report::msg(format!(
"dependency manifest path '{}' has no parent directory",
manifest_path.display()
))
})?
.to_path_buf();
let mut nested_options = Box::new(midenc_session::Options {
manifest_path: Some(manifest_path.clone()),
target: Some(target.name.to_string()),
Expand Down Expand Up @@ -244,6 +256,24 @@ fn cargo_build(

registry.publish_package(package.clone())?;

// Materialize the compiled dependency package on disk, in addition to publishing it to the
// in-memory registry. A dependent crate that imports this dependency (e.g. via
// `#[account(..)]`) resolves the dependency's `.masp` from disk while expanding its own Rust
// macros. The profile sub-directory mirrors the one searched by that macro: `release` for
// release builds and `debug` otherwise.
let profile = if cargo_opts.release {
"release"
} else {
"debug"
};
let masp_out_dir = dependency_dir.join("target").join("miden").join(profile);
package.write_masp_file(&masp_out_dir).map_err(|err| {
Report::msg(format!(
"failed to materialize dependency package '{package_name}' to '{}': {err}",
masp_out_dir.display()
))
})?;

Ok(package)
}

Expand Down
4 changes: 2 additions & 2 deletions midenc-compile/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ use midenc_session::{
pub struct Compiler {
/// Write all intermediate compiler artifacts to `<dir>`
///
/// Defaults to a directory named `target/midenc` in the current working directory
/// Defaults to a directory named `target/miden` in the current working directory
#[cfg_attr(
feature = "std",
arg(
long,
value_name = "DIR",
env = "MIDENC_TARGET_DIR",
default_value = "target/midenc",
default_value = "target/miden",
help_heading = "Output"
)
)]
Expand Down
2 changes: 1 addition & 1 deletion tools/cargo-miden/src/commands/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ impl BuildCommand {
let compiler_opts =
Compiler::try_parse_from(cwd.clone(), &self.args).unwrap_or_else(|err| err.exit());

let metadata_out_dir = compiler_opts.target_dir.join("miden").join(&compiler_opts.profile);
let metadata_out_dir = compiler_opts.target_dir.join(&compiler_opts.profile);
if !metadata_out_dir.exists() {
std::fs::create_dir_all(&metadata_out_dir)?;
}
Expand Down
1 change: 1 addition & 0 deletions tools/cargo-miden/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod build;
mod p2id_cargo_miden_build;
mod utils;
mod workspace;
71 changes: 71 additions & 0 deletions tools/cargo-miden/tests/p2id_cargo_miden_build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use std::{env, fs};

use cargo_miden::run;

use crate::utils::{current_dir_lock, workspace_root};

/// Building a project materializes its compiled Miden dependencies on disk.
///
/// The `p2id-note` example depends on the `basic-wallet` example as a Miden dependency. When
/// `cargo miden build` compiles `p2id-note`, it compiles `basic-wallet` as a dependency. The
/// resulting dependency package must be materialized to `basic-wallet/target/miden/release` rather
/// than only living in the in-memory package registry.
#[test]
fn p2id_build_materializes_basic_wallet_dependency() {
let _cwd_lock = current_dir_lock();
let _ = midenc_log::Builder::from_env("MIDENC_TRACE")
.is_test(true)
.format_timestamp(None)
.try_init();

// `Makefile.toml` sets `CARGO_TARGET_DIR` to the workspace target directory. Unset it so each
// example project uses its own `target/` directory, where dependency packages are expected to
// be materialized.
let restore_target_dir = env::var_os("CARGO_TARGET_DIR");
unsafe {
env::remove_var("CARGO_TARGET_DIR");
}

let examples = workspace_root().join("examples");
let basic_wallet_dir = examples.join("basic-wallet");
let p2id_note_dir = examples.join("p2id-note");

// The materialized dependency package we expect `cargo miden build` to produce on disk.
let dep_release_dir = basic_wallet_dir.join("target").join("miden").join("release");
let dep_package = dep_release_dir.join("basic-wallet.masp");

// Make sure the basic-wallet dependency package is not already materialized on disk, so that we
// can attribute its presence after the build to the p2id-note build alone.
if dep_release_dir.exists() {
fs::remove_dir_all(&dep_release_dir).unwrap();
}
assert!(
!dep_package.exists(),
"basic-wallet dependency package should not be materialized before the build"
);

// Build the p2id-note project, which pulls in basic-wallet as a Miden dependency.
let restore_dir = env::current_dir().unwrap();
env::set_current_dir(&p2id_note_dir).unwrap();
let result = run(["cargo", "miden", "build", "--release"].into_iter().map(|s| s.to_string()));
env::set_current_dir(&restore_dir).unwrap();

// Restore `CARGO_TARGET_DIR` before asserting, so a build failure doesn't leak the unset state.
match restore_target_dir {
Some(val) => unsafe { env::set_var("CARGO_TARGET_DIR", val) },
None => unsafe { env::remove_var("CARGO_TARGET_DIR") },
}

let output = result
.expect("cargo miden build for p2id-note failed")
.expect("expected BuildCommandOutput")
.unwrap_build_output();
assert_eq!(output.len(), 1, "expected a single p2id-note package artifact, got {output:?}");

// The build must have materialized the basic-wallet dependency package on disk.
assert!(
dep_package.exists(),
"expected basic-wallet dependency package to be materialized at {}",
dep_package.display()
);
}
Loading