risc0_build/
config.rs

1// Copyright 2025 RISC Zero, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::{env, path::PathBuf};
16
17use cargo_metadata::Package;
18use derive_builder::Builder;
19use risc0_zkos_v1compat::V1COMPAT_ELF;
20use serde::{Deserialize, Serialize};
21
22use crate::DEFAULT_DOCKER_TAG;
23
24/// Options for configuring a docker build environment.
25#[derive(Clone, Debug, Default, Serialize, Deserialize, Builder)]
26#[builder(default)]
27#[non_exhaustive]
28pub struct DockerOptions {
29    /// Specify the root directory for docker builds.
30    ///
31    /// The current working directory is used if this option is unspecified.
32    #[builder(setter(into, strip_option))]
33    pub root_dir: Option<PathBuf>,
34
35    /// Additional environment variables for the build container.
36    pub env: Vec<(String, String)>,
37
38    /// Docker container tag to use
39    #[builder(setter(into, strip_option))]
40    pub docker_container_tag: Option<String>,
41}
42
43impl DockerOptions {
44    /// Get the configured root dir, or current working directory if None.
45    pub fn root_dir(&self) -> PathBuf {
46        self.root_dir
47            .clone()
48            .unwrap_or_else(|| env::current_dir().unwrap())
49    }
50
51    /// Get the configured custom environment variables.
52    pub fn env(&self) -> Vec<(&str, &str)> {
53        self.env
54            .iter()
55            .map(|(key, val)| (key.as_str(), val.as_str()))
56            .collect()
57    }
58
59    /// Get the docker container tag, or default container tag if none
60    ///
61    /// This value may be set by using the `RISC0_DOCKER_CONTAINER_TAG` environment variable.
62    pub fn docker_container_tag(&self) -> String {
63        if let Ok(tag) = env::var("RISC0_DOCKER_CONTAINER_TAG") {
64            return tag;
65        }
66
67        self.docker_container_tag
68            .clone()
69            .unwrap_or(DEFAULT_DOCKER_TAG.to_string())
70    }
71}
72
73/// Options defining how to embed a guest package in
74/// [`crate::embed_methods_with_options`].
75///
76/// ```
77/// use risc0_build::{DockerOptionsBuilder, GuestOptionsBuilder};
78///
79/// let docker_options = DockerOptionsBuilder::default()
80///     .root_dir("../../")
81///     .env(vec![("ENV_VAR".to_string(), "value".to_string())])
82///     .build()
83///     .unwrap();
84///
85/// let guest_options = GuestOptionsBuilder::default()
86///     .features(vec!["my-features".to_string()])
87///     .use_docker(docker_options)
88///     .build()
89///     .unwrap();
90/// ```
91#[derive(Default, Clone, Debug, Builder)]
92#[builder(default)]
93#[non_exhaustive]
94pub struct GuestOptions {
95    /// Features for cargo to build the guest with.
96    pub features: Vec<String>,
97
98    /// Use a docker environment for building.
99    #[builder(setter(strip_option))]
100    pub use_docker: Option<DockerOptions>,
101
102    /// Override the default kernel ELF to be used for execution.
103    #[builder(setter(strip_option))]
104    pub kernel: Option<Vec<u8>>,
105}
106
107impl GuestOptions {
108    /// Get the kernel ELF to be used for execution.
109    pub fn kernel(&self) -> Vec<u8> {
110        self.kernel.clone().unwrap_or_else(|| V1COMPAT_ELF.to_vec())
111    }
112}
113
114/// Metadata defining options to build a guest
115#[derive(Serialize, Deserialize, Clone, Default)]
116pub(crate) struct GuestMetadata {
117    /// Configuration flags to build the guest with.
118    #[serde(rename = "rustc-flags")]
119    pub(crate) rustc_flags: Option<Vec<String>>,
120
121    /// Indicates whether the guest program is a kernel.
122    #[serde(default)]
123    pub(crate) kernel: bool,
124}
125
126impl From<&Package> for GuestMetadata {
127    fn from(pkg: &Package) -> Self {
128        let Some(obj) = pkg.metadata.get("risc0") else {
129            return Default::default();
130        };
131        serde_json::from_value(obj.clone()).unwrap()
132    }
133}
134
135/// Extended options defining how to embed a guest package in
136/// [`crate::embed_methods_with_options`].
137#[derive(Default, Clone)]
138pub(crate) struct GuestInfo {
139    /// Options specified by build script or library usage.
140    pub(crate) options: GuestOptions,
141
142    /// Metadata specified in guest crate `Cargo.toml`.
143    pub(crate) metadata: GuestMetadata,
144}