Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[fix] build_guest_package didn't target any specific package, there was no way to build examples with it #1114

Merged
merged 2 commits into from
Dec 18, 2024
Merged
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
2 changes: 1 addition & 1 deletion benchmarks/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ pub fn build_bench_program(program_name: &str) -> Result<Elf> {
let target_dir = tempdir()?;
// Build guest with default features
let guest_opts = GuestOptions::default().with_target_dir(target_dir.path());
if let Err(Some(code)) = build_guest_package(&pkg, &guest_opts, None) {
if let Err(Some(code)) = build_guest_package(&pkg, &guest_opts, None, &None) {
std::process::exit(code);
}
// Assumes the package has a single target binary
Expand Down
22 changes: 6 additions & 16 deletions book/src/writing-apps/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,34 +37,24 @@ The following flags are available for the `cargo openvm build` command:
cargo openvm build --features my_feature
```

- `--bin`
- `--bin <NAME>`

**Description**: Restricts the build to binary targets. If your project has multiple target types (binaries, libraries, examples, etc.), using `--bin` ensures only binary targets are considered.
**Description**: Restricts the build to the binary target with the given name, similar to `cargo build --bin <NAME>`. If your project has multiple target types (binaries, libraries, examples, etc.), using `--bin <NAME>` narrows down the build to the binary target with the given name.

**Usage Example**:

```bash
cargo openvm build --bin
cargo openvm build --bin my_bin
```

- `--example`
- `--example <NAME>`

**Description**: Restricts the build to example targets. Projects often include code samples or demos under the examples directory, and this flag focuses on compiling those.
**Description**: Restricts the build to the example target with the given name, similar to `cargo build --example <NAME>`. Projects often include code samples or demos under the examples directory, and this flag focuses on compiling a specific example.

**Usage Example**:

```bash
cargo openvm build --example
```

- `--name <NAME>`

**Description**: Filters targets by name. Only targets whose names contain the given substring will be built.

**Usage Example**: To build only targets that have `client` in their name:

```bash
cargo openvm build --name client
cargo openvm build --example my_example
```

- `--no-transpile`
Expand Down
42 changes: 19 additions & 23 deletions crates/cli/src/commands/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,6 @@ pub struct BuildArgs {
#[clap(flatten, help = "Filter the target to build")]
pub bin_type_filter: BinTypeFilter,

#[arg(long, help = "Target name substring filter")]
pub name: Option<String>,

#[arg(
long,
default_value = "false",
Expand Down Expand Up @@ -73,31 +70,30 @@ pub struct BuildArgs {
#[derive(Clone, clap::Args)]
#[group(required = false, multiple = false)]
pub struct BinTypeFilter {
#[arg(
long,
help = "Specifies that the target should be a binary kind when set"
)]
pub bin: bool,
#[arg(long, help = "Specifies that the bin target to build")]
pub bin: Option<String>,

#[arg(
long,
help = "Specifies that the target should be an example kind when set"
)]
pub example: bool,
#[arg(long, help = "Specifies that the example target to build")]
pub example: Option<String>,
}

// Returns the path to the ELF file if it is unique.
pub(crate) fn build(build_args: &BuildArgs) -> Result<Option<PathBuf>> {
println!("[openvm] Building the package...");
let target_filter = TargetFilter {
name_substr: build_args.name.clone(),
kind: if build_args.bin_type_filter.bin {
Some("bin".to_string())
} else if build_args.bin_type_filter.example {
Some("example".to_string())
} else {
None
},
let target_filter = if let Some(bin) = &build_args.bin_type_filter.bin {
Some(TargetFilter {
name: bin.clone(),
kind: "bin".to_string(),
})
} else {
build_args
.bin_type_filter
.example
.as_ref()
.map(|example| TargetFilter {
name: example.clone(),
kind: "example".to_string(),
})
};
let guest_options = GuestOptions {
features: build_args.features.clone(),
Expand All @@ -106,7 +102,7 @@ pub(crate) fn build(build_args: &BuildArgs) -> Result<Option<PathBuf>> {

let pkg = get_package(&build_args.manifest_dir);
// We support builds of libraries with 0 or >1 executables.
let elf_path = match build_guest_package(&pkg, &guest_options, None) {
let elf_path = match build_guest_package(&pkg, &guest_options, None, &target_filter) {
Ok(target_dir) => {
find_unique_executable(&build_args.manifest_dir, &target_dir, &target_filter)
}
Expand Down
4 changes: 2 additions & 2 deletions crates/sdk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@ impl Sdk {
&self,
guest_opts: GuestOptions,
pkg_dir: P,
target_filter: &TargetFilter,
target_filter: &Option<TargetFilter>,
) -> Result<Elf> {
let pkg = get_package(pkg_dir.as_ref());
let target_dir = match build_guest_package(&pkg, &guest_opts, None) {
let target_dir = match build_guest_package(&pkg, &guest_opts, None, target_filter) {
Ok(target_dir) => target_dir,
Err(Some(code)) => {
return Err(eyre::eyre!("Failed to build guest: code = {}", code));
Expand Down
66 changes: 35 additions & 31 deletions crates/toolchain/build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,20 @@ pub fn get_target_dir(manifest_path: impl AsRef<Path>) -> PathBuf {
}

/// Returns the target executable directory given `target_dir` and `profile`.
pub fn get_dir_with_profile(target_dir: impl AsRef<Path>, profile: &str) -> PathBuf {
target_dir
pub fn get_dir_with_profile(
target_dir: impl AsRef<Path>,
profile: &str,
examples: bool,
) -> PathBuf {
let res = target_dir
.as_ref()
.join("riscv32im-risc0-zkvm-elf")
.join(profile)
.join(profile);
if examples {
res.join("examples")
} else {
res
}
}

/// When called from a build.rs, returns the current package being built.
Expand Down Expand Up @@ -241,6 +250,7 @@ pub fn build_guest_package(
pkg: &Package,
guest_opts: &GuestOptions,
runtime_lib: Option<&str>,
target_filter: &Option<TargetFilter>,
) -> Result<PathBuf, Option<i32>> {
if is_skip_build() {
return Err(None);
Expand Down Expand Up @@ -279,6 +289,13 @@ pub fn build_guest_package(
target_dir.to_str().unwrap(),
]);

if let Some(target_filter) = target_filter {
cmd.args([
format!("--{}", target_filter.kind).as_str(),
target_filter.name.as_str(),
]);
}

let profile = if let Some(profile) = &guest_opts.profile {
profile
} else if is_debug() {
Expand Down Expand Up @@ -320,54 +337,41 @@ pub fn build_guest_package(
if !res.success() {
Err(res.code())
} else {
Ok(get_dir_with_profile(&target_dir, profile))
Ok(get_dir_with_profile(
&target_dir,
profile,
target_filter
.as_ref()
.map(|t| t.kind == "example")
.unwrap_or(false),
))
}
}

/// A filter for selecting a target from a package.
#[derive(Default)]
pub struct TargetFilter {
/// A substring of the target name to match.
pub name_substr: Option<String>,
/// The target name to match.
pub name: String,
/// The kind of target to match.
pub kind: Option<String>,
}

impl TargetFilter {
/// Set substring of target name to match.
pub fn with_name_substr(mut self, name_substr: String) -> Self {
self.name_substr = Some(name_substr);
self
}

/// Set kind of target to match.
pub fn with_kind(mut self, kind: String) -> Self {
self.kind = Some(kind);
self
}
pub kind: String,
}

/// Finds the unique executable target in the given package and target directory,
/// using the given target filter.
pub fn find_unique_executable<P: AsRef<Path>, Q: AsRef<Path>>(
pkg_dir: P,
target_dir: Q,
target_filter: &TargetFilter,
target_filter: &Option<TargetFilter>,
) -> eyre::Result<PathBuf> {
let pkg = get_package(pkg_dir.as_ref());
let elf_paths = pkg
.targets
.into_iter()
.filter(move |target| {
if let Some(name_substr) = &target_filter.name_substr {
if !target.name.contains(name_substr) {
return false;
}
}
if let Some(kind) = &target_filter.kind {
if !target.kind.iter().any(|k| k == kind) {
return false;
}
if let Some(target_filter) = target_filter {
return target.kind.iter().any(|k| k == &target_filter.kind)
&& target.name == target_filter.name;
}
true
})
Expand Down
13 changes: 10 additions & 3 deletions crates/toolchain/tests/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::{
};

use eyre::Result;
use openvm_build::{build_guest_package, get_package, is_debug, GuestOptions};
use openvm_build::{build_guest_package, get_package, is_debug, GuestOptions, TargetFilter};
use openvm_transpiler::{elf::Elf, openvm_platform::memory::MEM_SIZE};
use tempfile::tempdir;

Expand Down Expand Up @@ -41,10 +41,17 @@ pub fn build_example_program_at_path_with_features<S: AsRef<str>>(
let target_dir = tempdir()?;
// Build guest with default features
let guest_opts = GuestOptions::default()
.with_options(["--example", example_name])
.with_features(features)
.with_target_dir(target_dir.path());
if let Err(Some(code)) = build_guest_package(&pkg, &guest_opts, None) {
if let Err(Some(code)) = build_guest_package(
&pkg,
&guest_opts,
None,
&Some(TargetFilter {
name: example_name.to_string(),
kind: "example".to_string(),
}),
) {
std::process::exit(code);
jonathanpwang marked this conversation as resolved.
Show resolved Hide resolved
}
// Assumes the package has a single target binary
Expand Down