Skip to main content

flowey_lib_hvlite/
common.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Vocabulary types for the most-common build profiles, architectures,
5//! platforms, and target triples used in the OpenVMM/OpenHCL tree.
6//!
7//! Outside of a few binaries / libraries that are intimately tied to one
8//! particular architecture / platform, most things in the hvlite tree run on a
9//! common subset of supported target triples + build profiles.
10
11use flowey::node::prelude::*;
12use std::collections::BTreeMap;
13
14pub(crate) const OPENVMM_GITHUB_OWNER: &str = "microsoft";
15pub(crate) const OPENVMM_GITHUB_REPO: &str = "openvmm";
16pub(crate) const OPENVMM_DEPS_GITHUB_REPO: &str = "openvmm-deps";
17
18/// Environment for OpenHCL builds that must use prebuilt native libraries.
19pub(crate) fn openhcl_build_env() -> BTreeMap<String, String> {
20    BTreeMap::from([
21        ("CC_FORCE_DISABLE".into(), "1".into()),
22        (
23            "CMAKE".into(),
24            "cmake-is-forbidden-during-openvmm-hcl-build".into(),
25        ),
26    ])
27}
28
29pub(crate) fn openssl_dev_packages(platform: FlowPlatform) -> anyhow::Result<Vec<String>> {
30    Ok(match platform {
31        FlowPlatform::Linux(distro) => match distro {
32            FlowPlatformLinuxDistro::Ubuntu => vec!["libssl-dev".into()],
33            FlowPlatformLinuxDistro::Fedora | FlowPlatformLinuxDistro::AzureLinux => {
34                vec!["openssl-devel".into(), "perl".into()]
35            }
36            FlowPlatformLinuxDistro::Arch => vec!["openssl".into(), "perl".into()],
37            FlowPlatformLinuxDistro::Nix => Vec::new(),
38            FlowPlatformLinuxDistro::Unknown => anyhow::bail!("Unknown Linux distribution"),
39        },
40        _ => Vec::new(),
41    })
42}
43
44/// Vocabulary type for artifacts that only get built using the two most
45/// common cargo build profiles (i.e: `release` vs. `debug`).
46///
47/// More specialized artifacts should use the
48/// [`BuildProfile`](crate::run_cargo_build::BuildProfile) type, which
49/// enumerates _all_ build profiles defined in HvLite's `Cargo.toml` file.
50#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
51pub enum CommonProfile {
52    Release,
53    Debug,
54}
55
56impl CommonProfile {
57    pub fn from_release(release: bool) -> Self {
58        match release {
59            true => Self::Release,
60            false => Self::Debug,
61        }
62    }
63
64    pub fn to_release(self) -> bool {
65        match self {
66            Self::Release => true,
67            Self::Debug => false,
68        }
69    }
70}
71
72impl From<CommonProfile> for crate::run_cargo_build::BuildProfile {
73    fn from(value: CommonProfile) -> Self {
74        match value {
75            CommonProfile::Release => crate::run_cargo_build::BuildProfile::Release,
76            CommonProfile::Debug => crate::run_cargo_build::BuildProfile::Debug,
77        }
78    }
79}
80
81impl From<CommonProfile> for flowey_lib_common::run_cargo_build::CargoBuildProfile {
82    fn from(value: CommonProfile) -> Self {
83        match value {
84            CommonProfile::Release => Self::Release,
85            CommonProfile::Debug => Self::Debug,
86        }
87    }
88}
89
90/// Vocabulary type for artifacts that only get built for the most common
91/// actively-supported architectures in the hvlite tree.
92#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
93pub enum CommonArch {
94    X86_64,
95    Aarch64,
96}
97
98impl CommonArch {
99    /// Target the OpenHCL minimal runtime, leaving target translation to
100    /// [`crate::run_cargo_build`].
101    pub fn minimal_rt_triple(self) -> target_lexicon::Triple {
102        target_lexicon::Triple {
103            architecture: self.as_arch(),
104            operating_system: target_lexicon::OperatingSystem::None_,
105            environment: target_lexicon::Environment::Unknown,
106            vendor: target_lexicon::Vendor::Custom(target_lexicon::CustomVendor::Static(
107                "minimal_rt",
108            )),
109            binary_format: target_lexicon::BinaryFormat::Unknown,
110        }
111    }
112
113    /// Convert to a [`target_lexicon::Architecture`].
114    pub fn as_arch(&self) -> target_lexicon::Architecture {
115        match self {
116            CommonArch::X86_64 => target_lexicon::Architecture::X86_64,
117            CommonArch::Aarch64 => {
118                target_lexicon::Architecture::Aarch64(target_lexicon::Aarch64Architecture::Aarch64)
119            }
120        }
121    }
122
123    /// Convert from a [`target_lexicon::Triple`], failing if the triple's
124    /// architecture is not one of the common architectures.
125    pub fn from_triple(triple: &target_lexicon::Triple) -> anyhow::Result<Self> {
126        Self::from_architecture(triple.architecture)
127    }
128
129    /// Convert from a [`target_lexicon::Architecture`], failing if it is not
130    /// one of the common architectures.
131    pub fn from_architecture(arch: target_lexicon::Architecture) -> anyhow::Result<Self> {
132        Ok(match arch {
133            target_lexicon::Architecture::Aarch64(target_lexicon::Aarch64Architecture::Aarch64) => {
134                Self::Aarch64
135            }
136            target_lexicon::Architecture::X86_64 => Self::X86_64,
137            _ => anyhow::bail!("unsupported arch {arch}"),
138        })
139    }
140}
141
142impl TryFrom<FlowArch> for CommonArch {
143    type Error = anyhow::Error;
144
145    fn try_from(arch: FlowArch) -> anyhow::Result<Self> {
146        Ok(match arch {
147            FlowArch::X86_64 => Self::X86_64,
148            FlowArch::Aarch64 => Self::Aarch64,
149            arch => anyhow::bail!("unsupported arch {arch}"),
150        })
151    }
152}
153
154/// Vocabulary type for artifacts that only get built for the most common
155/// actively-supported platforms in the hvlite tree.
156#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
157pub enum CommonPlatform {
158    WindowsMsvc,
159    /// Windows via the GNU (mingw-w64) toolchain. Used to cross-compile
160    /// Windows *guest* payloads (e.g. pipette) from a non-WSL Linux host,
161    /// where the MSVC toolchain / Windows SDK is unavailable.
162    WindowsGnu,
163    LinuxGnu,
164    LinuxMusl,
165    MacOs,
166}
167
168impl TryFrom<FlowPlatform> for CommonPlatform {
169    type Error = anyhow::Error;
170
171    fn try_from(platform: FlowPlatform) -> anyhow::Result<Self> {
172        Ok(match platform {
173            FlowPlatform::Windows => Self::WindowsMsvc,
174            FlowPlatform::Linux(_) => Self::LinuxGnu,
175            FlowPlatform::MacOs => Self::MacOs,
176            platform => anyhow::bail!("unsupported platform {platform}"),
177        })
178    }
179}
180
181#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
182pub enum CommonTriple {
183    Common {
184        arch: CommonArch,
185        platform: CommonPlatform,
186    },
187    Custom(target_lexicon::Triple),
188}
189
190impl CommonTriple {
191    pub const X86_64_WINDOWS_MSVC: Self = Self::Common {
192        arch: CommonArch::X86_64,
193        platform: CommonPlatform::WindowsMsvc,
194    };
195    pub const X86_64_WINDOWS_GNU: Self = Self::Common {
196        arch: CommonArch::X86_64,
197        platform: CommonPlatform::WindowsGnu,
198    };
199    pub const X86_64_LINUX_GNU: Self = Self::Common {
200        arch: CommonArch::X86_64,
201        platform: CommonPlatform::LinuxGnu,
202    };
203    pub const X86_64_LINUX_MUSL: Self = Self::Common {
204        arch: CommonArch::X86_64,
205        platform: CommonPlatform::LinuxMusl,
206    };
207    pub const AARCH64_WINDOWS_MSVC: Self = Self::Common {
208        arch: CommonArch::Aarch64,
209        platform: CommonPlatform::WindowsMsvc,
210    };
211    pub const AARCH64_WINDOWS_GNU: Self = Self::Common {
212        arch: CommonArch::Aarch64,
213        platform: CommonPlatform::WindowsGnu,
214    };
215    pub const AARCH64_LINUX_GNU: Self = Self::Common {
216        arch: CommonArch::Aarch64,
217        platform: CommonPlatform::LinuxGnu,
218    };
219    pub const AARCH64_LINUX_MUSL: Self = Self::Common {
220        arch: CommonArch::Aarch64,
221        platform: CommonPlatform::LinuxMusl,
222    };
223}
224
225impl std::fmt::Debug for CommonTriple {
226    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
227        std::fmt::Debug::fmt(&self.as_triple(), f)
228    }
229}
230
231impl std::fmt::Display for CommonTriple {
232    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
233        std::fmt::Display::fmt(&self.as_triple(), f)
234    }
235}
236
237impl PartialOrd for CommonTriple {
238    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
239        Some(self.cmp(other))
240    }
241}
242
243impl Ord for CommonTriple {
244    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
245        self.as_triple()
246            .to_string()
247            .cmp(&other.as_triple().to_string())
248    }
249}
250
251impl CommonTriple {
252    pub fn as_triple(&self) -> target_lexicon::Triple {
253        match self {
254            CommonTriple::Common { arch, platform } => match platform {
255                CommonPlatform::WindowsMsvc => target_lexicon::Triple {
256                    architecture: arch.as_arch(),
257                    vendor: target_lexicon::Vendor::Pc,
258                    operating_system: target_lexicon::OperatingSystem::Windows,
259                    environment: target_lexicon::Environment::Msvc,
260                    binary_format: target_lexicon::BinaryFormat::Coff,
261                },
262                CommonPlatform::WindowsGnu => target_lexicon::Triple {
263                    architecture: arch.as_arch(),
264                    vendor: target_lexicon::Vendor::Pc,
265                    operating_system: target_lexicon::OperatingSystem::Windows,
266                    environment: target_lexicon::Environment::Gnu,
267                    binary_format: target_lexicon::BinaryFormat::Coff,
268                },
269                CommonPlatform::LinuxGnu => target_lexicon::Triple {
270                    architecture: arch.as_arch(),
271                    vendor: target_lexicon::Vendor::Unknown,
272                    operating_system: target_lexicon::OperatingSystem::Linux,
273                    environment: target_lexicon::Environment::Gnu,
274                    binary_format: target_lexicon::BinaryFormat::Elf,
275                },
276                CommonPlatform::LinuxMusl => target_lexicon::Triple {
277                    architecture: arch.as_arch(),
278                    vendor: target_lexicon::Vendor::Unknown,
279                    operating_system: target_lexicon::OperatingSystem::Linux,
280                    environment: target_lexicon::Environment::Musl,
281                    binary_format: target_lexicon::BinaryFormat::Elf,
282                },
283                CommonPlatform::MacOs => target_lexicon::Triple {
284                    architecture: arch.as_arch(),
285                    vendor: target_lexicon::Vendor::Apple,
286                    operating_system: target_lexicon::OperatingSystem::Darwin(None),
287                    environment: target_lexicon::Environment::Unknown,
288                    binary_format: target_lexicon::BinaryFormat::Macho,
289                },
290            },
291            CommonTriple::Custom(t) => t.clone(),
292        }
293    }
294
295    /// Get the common architecture of this triple, failing if the triple's
296    /// architecture is not one of the common architectures.
297    pub fn common_arch(&self) -> anyhow::Result<CommonArch> {
298        match self {
299            CommonTriple::Common { arch, .. } => Ok(*arch),
300            CommonTriple::Custom(target) => CommonArch::from_triple(target),
301        }
302    }
303}