flowey_lib_hvlite/
build_openvmm_hcl.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Build `openvmm_hcl` binaries (NOT IGVM FILES!)
5
6use crate::init_openvmm_magicpath_openhcl_sysroot::OpenvmmSysrootArch;
7use crate::run_cargo_build::common::CommonArch;
8use crate::run_cargo_build::common::CommonTriple;
9use flowey::node::prelude::*;
10use flowey_lib_common::run_cargo_build::CargoFeatureSet;
11use std::collections::BTreeMap;
12use std::collections::BTreeSet;
13
14#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
15pub enum OpenvmmHclFeature {
16    Gdb,
17    Tpm,
18    LocalOnlyCustom(String),
19}
20
21#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
22pub enum OpenvmmHclBuildProfile {
23    Debug,
24    Release,
25    OpenvmmHclShip,
26}
27
28#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
29pub enum MaxTraceLevel {
30    Trace,
31    Debug,
32    Info,
33    Warn,
34    Error,
35    Off,
36}
37
38impl MaxTraceLevel {
39    pub fn features(&self) -> Vec<String> {
40        let name = match self {
41            MaxTraceLevel::Trace => return Vec::new(),
42            MaxTraceLevel::Debug => "debug",
43            MaxTraceLevel::Info => "info",
44            MaxTraceLevel::Warn => "warn",
45            MaxTraceLevel::Error => "error",
46            MaxTraceLevel::Off => "off",
47        };
48        // Add both release and non-release variants of the feature
49        // regardless of the profile to work around `tracing` bugs.
50        vec![
51            format!("tracing/max_level_{}", name),
52            format!("tracing/release_max_level_{}", name),
53        ]
54    }
55}
56
57#[derive(Serialize, Deserialize)]
58pub struct OpenvmmHclOutput {
59    pub bin: PathBuf,
60    pub dbg: Option<PathBuf>,
61}
62
63#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
64pub struct OpenvmmHclBuildParams {
65    pub target: CommonTriple,
66    pub profile: OpenvmmHclBuildProfile,
67    pub features: BTreeSet<OpenvmmHclFeature>,
68    pub no_split_dbg_info: bool,
69    pub max_trace_level: MaxTraceLevel,
70}
71
72flowey_request! {
73    pub struct Request {
74        pub build_params: OpenvmmHclBuildParams,
75        pub openvmm_hcl_output: WriteVar<OpenvmmHclOutput>,
76    }
77}
78
79new_flow_node!(struct Node);
80
81impl FlowNode for Node {
82    type Request = Request;
83
84    fn imports(ctx: &mut ImportCtx<'_>) {
85        ctx.import::<crate::run_cargo_build::Node>();
86        ctx.import::<crate::init_openvmm_magicpath_openhcl_sysroot::Node>();
87        ctx.import::<flowey_lib_common::install_dist_pkg::Node>();
88    }
89
90    fn emit(requests: Vec<Self::Request>, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
91        // de-dupe incoming requests
92        let requests = requests
93            .into_iter()
94            .fold(BTreeMap::<_, Vec<_>>::new(), |mut m, r| {
95                let Request {
96                    build_params,
97                    openvmm_hcl_output,
98                } = r;
99                m.entry(build_params).or_default().push(openvmm_hcl_output);
100                m
101            });
102
103        // -- end of req processing -- //
104
105        for (
106            OpenvmmHclBuildParams {
107                target,
108                profile,
109                features,
110                no_split_dbg_info,
111                max_trace_level,
112            },
113            outvars,
114        ) in requests
115        {
116            let mut pre_build_deps = Vec::new();
117
118            let target = target.as_triple();
119
120            let arch = CommonArch::from_triple(&target).ok_or_else(|| {
121                anyhow::anyhow!("cannot build openvmm_hcl on {}", target.architecture)
122            })?;
123
124            let openhcl_deps_path =
125                ctx.reqv(|v| crate::init_openvmm_magicpath_openhcl_sysroot::Request {
126                    arch: match arch {
127                        CommonArch::X86_64 => OpenvmmSysrootArch::X64,
128                        CommonArch::Aarch64 => OpenvmmSysrootArch::Aarch64,
129                    },
130                    path: v,
131                });
132
133            // required due to ambient dependencies in openvmm_hcl's source code
134            pre_build_deps.push(openhcl_deps_path.clone().into_side_effect());
135
136            // TODO: install build tools for other platforms
137            if matches!(
138                ctx.platform(),
139                FlowPlatform::Linux(FlowPlatformLinuxDistro::Ubuntu)
140            ) {
141                pre_build_deps.push(ctx.reqv(|v| {
142                    flowey_lib_common::install_dist_pkg::Request::Install {
143                        package_names: vec!["build-essential".into()],
144                        done: v,
145                    }
146                }));
147            }
148
149            let mut features = features
150                .into_iter()
151                .map(|f| match f {
152                    OpenvmmHclFeature::Gdb => "gdb".into(),
153                    OpenvmmHclFeature::Tpm => "tpm".into(),
154                    OpenvmmHclFeature::LocalOnlyCustom(s) => s,
155                })
156                .collect::<Vec<String>>();
157
158            features.extend(max_trace_level.features());
159
160            let output = ctx.reqv(|v| crate::run_cargo_build::Request {
161                crate_name: "openvmm_hcl".into(),
162                out_name: "openvmm_hcl".into(),
163                crate_type: flowey_lib_common::run_cargo_build::CargoCrateType::Bin,
164                profile: match profile {
165                    OpenvmmHclBuildProfile::Debug => crate::run_cargo_build::BuildProfile::Debug,
166                    OpenvmmHclBuildProfile::Release => {
167                        crate::run_cargo_build::BuildProfile::Release
168                    }
169                    OpenvmmHclBuildProfile::OpenvmmHclShip => {
170                        crate::run_cargo_build::BuildProfile::UnderhillShip
171                    }
172                },
173                features: CargoFeatureSet::Specific(features),
174                target,
175                no_split_dbg_info,
176                extra_env: None,
177                pre_build_deps,
178                output: v,
179            });
180
181            ctx.emit_minor_rust_step("report built openvmm_hcl", |ctx| {
182                let outvars = outvars.claim(ctx);
183                let output = output.claim(ctx);
184                move |rt| {
185                    let output = match rt.read(output) {
186                        crate::run_cargo_build::CargoBuildOutput::ElfBin { bin, dbg } => {
187                            OpenvmmHclOutput { bin, dbg }
188                        }
189                        _ => unreachable!(),
190                    };
191
192                    for var in outvars {
193                        rt.write(var, &output);
194                    }
195                }
196            });
197        }
198
199        Ok(())
200    }
201}