microsoft/openvmm
Publicmirrored fromhttps://github.com/microsoft/openvmmAvailable
flowey/flowey_lib_hvlite/src/build_and_test_vmgs_lib.rs
227lines · modecode
| 1 | // Copyright (c) Microsoft Corporation. |
| 2 | // Licensed under the MIT License. |
| 3 | |
| 4 | //! Builds and tests `vmgs_lib` library. |
| 5 | //! |
| 6 | //! Tests are windows only at the moment. |
| 7 | |
| 8 | use crate::run_cargo_build::CargoBuildOutput; |
| 9 | use crate::run_cargo_build::common::CommonProfile; |
| 10 | use crate::run_cargo_build::common::CommonTriple; |
| 11 | use flowey::node::prelude::*; |
| 12 | use flowey_lib_common::run_cargo_build::CargoCrateType; |
| 13 | |
| 14 | #[derive(Serialize, Deserialize)] |
| 15 | #[serde(untagged)] |
| 16 | pub enum VmgsLibOutput { |
| 17 | LinuxDynamicLib { |
| 18 | #[serde(rename = "libvmgs_lib.so")] |
| 19 | so: PathBuf, |
| 20 | }, |
| 21 | WindowsDynamicLib { |
| 22 | #[serde(rename = "vmgs_lib.dll")] |
| 23 | dll: PathBuf, |
| 24 | #[serde(rename = "vmgs_lib.dll.lib")] |
| 25 | dll_lib: PathBuf, |
| 26 | #[serde(rename = "vmgs_lib.pdb")] |
| 27 | pdb: PathBuf, |
| 28 | }, |
| 29 | } |
| 30 | |
| 31 | impl Artifact for VmgsLibOutput {} |
| 32 | |
| 33 | flowey_request! { |
| 34 | pub struct Request { |
| 35 | pub target: CommonTriple, |
| 36 | pub profile: CommonProfile, |
| 37 | pub vmgs_lib: WriteVar<VmgsLibOutput>, |
| 38 | } |
| 39 | } |
| 40 | |
| 41 | new_simple_flow_node!(struct Node); |
| 42 | |
| 43 | impl SimpleFlowNode for Node { |
| 44 | type Request = Request; |
| 45 | |
| 46 | fn imports(ctx: &mut ImportCtx<'_>) { |
| 47 | ctx.import::<crate::run_cargo_build::Node>(); |
| 48 | ctx.import::<crate::git_checkout_openvmm_repo::Node>(); |
| 49 | ctx.import::<flowey_lib_common::install_dist_pkg::Node>(); |
| 50 | } |
| 51 | |
| 52 | fn process_request(request: Self::Request, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> { |
| 53 | let Request { |
| 54 | target, |
| 55 | profile, |
| 56 | vmgs_lib, |
| 57 | } = request; |
| 58 | |
| 59 | let ssl_pkg = match ctx.platform() { |
| 60 | FlowPlatform::Linux( |
| 61 | FlowPlatformLinuxDistro::Fedora | FlowPlatformLinuxDistro::AzureLinux, |
| 62 | ) => "openssl-devel", |
| 63 | _ => "libssl-dev", |
| 64 | }; |
| 65 | let pre_build_deps = |
| 66 | [ |
| 67 | ctx.reqv(|v| flowey_lib_common::install_dist_pkg::Request::Install { |
| 68 | package_names: vec![ssl_pkg.into()], |
| 69 | done: v, |
| 70 | }), |
| 71 | ] |
| 72 | .to_vec(); |
| 73 | |
| 74 | let output = ctx.reqv(|v| crate::run_cargo_build::Request { |
| 75 | crate_name: "vmgs_lib".into(), |
| 76 | out_name: "vmgs_lib".into(), |
| 77 | crate_type: CargoCrateType::DynamicLib, |
| 78 | profile: profile.into(), |
| 79 | features: Default::default(), |
| 80 | target: target.as_triple(), |
| 81 | no_split_dbg_info: false, |
| 82 | extra_env: None, |
| 83 | pre_build_deps, |
| 84 | output: v, |
| 85 | }); |
| 86 | |
| 87 | let built_vmgs_lib = ctx.emit_minor_rust_stepv("check built vmgs_lib", |ctx| { |
| 88 | let output = output.claim(ctx); |
| 89 | move |rt| match rt.read(output) { |
| 90 | CargoBuildOutput::LinuxDynamicLib { so } => VmgsLibOutput::LinuxDynamicLib { so }, |
| 91 | CargoBuildOutput::WindowsDynamicLib { dll, dll_lib, pdb } => { |
| 92 | VmgsLibOutput::WindowsDynamicLib { dll, dll_lib, pdb } |
| 93 | } |
| 94 | _ => unreachable!(), |
| 95 | } |
| 96 | }); |
| 97 | |
| 98 | // given how simple the test is for vmgs_lib, it's fine to just |
| 99 | // do it "inline" with the compilation |
| 100 | // |
| 101 | // if we ever decide to do more involved testing for this lib, |
| 102 | // this should get split out into a separate step |
| 103 | |
| 104 | // TODO: figure out how to test vmgs_lib on other architectures. |
| 105 | // Currently x86 only |
| 106 | let did_test = if matches!( |
| 107 | &target.as_triple().architecture, |
| 108 | target_lexicon::Architecture::X86_64 |
| 109 | ) && matches!(ctx.arch(), FlowArch::X86_64) |
| 110 | { |
| 111 | let clang_installed = |
| 112 | ctx.reqv(|v| flowey_lib_common::install_dist_pkg::Request::Install { |
| 113 | package_names: vec!["clang".into()], |
| 114 | done: v, |
| 115 | }); |
| 116 | |
| 117 | let openvmm_repo_path = ctx.reqv(crate::git_checkout_openvmm_repo::req::GetRepoDir); |
| 118 | |
| 119 | if matches!(ctx.platform(), FlowPlatform::Linux(_)) { |
| 120 | ctx.emit_rust_step("test vmgs_lib", |ctx| { |
| 121 | clang_installed.claim(ctx); |
| 122 | |
| 123 | let built_vmgs_lib = built_vmgs_lib.clone().claim(ctx); |
| 124 | let openvmm_repo_path = openvmm_repo_path.claim(ctx); |
| 125 | |
| 126 | move |rt| { |
| 127 | let VmgsLibOutput::LinuxDynamicLib { so } = rt.read(built_vmgs_lib) else { |
| 128 | unreachable!() |
| 129 | }; |
| 130 | |
| 131 | let so_dir = so.parent().unwrap(); |
| 132 | |
| 133 | let openvmm_repo_path = rt.read(openvmm_repo_path); |
| 134 | |
| 135 | let vmgs_testlib_c = |
| 136 | openvmm_repo_path.join("vm/vmgs/vmgs_lib/examples/vmgs_testlib.c"); |
| 137 | |
| 138 | if which::which("clang").is_ok() { |
| 139 | flowey::shell_cmd!( |
| 140 | rt, |
| 141 | "clang {vmgs_testlib_c} {so} -rpath {so_dir} -o ./vmgs_lib_test" |
| 142 | ) |
| 143 | .run()?; |
| 144 | flowey::shell_cmd!(rt, "./vmgs_lib_test").run()?; |
| 145 | } else { |
| 146 | log::warn!("skipping vmgs_lib test (could not find clang)"); |
| 147 | } |
| 148 | |
| 149 | Ok(()) |
| 150 | } |
| 151 | }) |
| 152 | } else if matches!(ctx.platform(), FlowPlatform::Windows) { |
| 153 | // HACK: clang-on-bash-on-windows-on-ADO is... wild. This |
| 154 | // works, but it's undoubtedly suboptimal, and someone who |
| 155 | // actually _understands_ how clang is set up in this |
| 156 | // context could do a wildly better job here. |
| 157 | ctx.emit_rust_step("test vmgs_lib", |ctx| { |
| 158 | clang_installed.claim(ctx); |
| 159 | |
| 160 | let built_vmgs_lib = built_vmgs_lib.clone().claim(ctx); |
| 161 | let openvmm_repo_path = openvmm_repo_path.claim(ctx); |
| 162 | |
| 163 | move |rt| { |
| 164 | // TODO: figure out how to test cross-compile windows in wsl2 |
| 165 | if flowey_lib_common::_util::running_in_wsl(rt) |
| 166 | && matches!( |
| 167 | &target.as_triple().operating_system, |
| 168 | target_lexicon::OperatingSystem::Windows |
| 169 | ) |
| 170 | { |
| 171 | log::warn!("unimplemented: skip testing windows vmgs_lib via WSL2"); |
| 172 | return Ok(()); |
| 173 | } |
| 174 | |
| 175 | let openvmm_repo_path = rt.read(openvmm_repo_path); |
| 176 | |
| 177 | let VmgsLibOutput::WindowsDynamicLib { |
| 178 | dll, |
| 179 | dll_lib, |
| 180 | pdb: _, |
| 181 | } = rt.read(built_vmgs_lib) |
| 182 | else { |
| 183 | unreachable!() |
| 184 | }; |
| 185 | |
| 186 | if which::which("clang").is_err() { |
| 187 | log::warn!("skipping vmgs_lib test (could not find clang)"); |
| 188 | return Ok(()); |
| 189 | } |
| 190 | |
| 191 | let vmgs_testlib_c = |
| 192 | openvmm_repo_path.join("vm/vmgs/vmgs_lib/examples/vmgs_testlib.c"); |
| 193 | |
| 194 | // make sure to copy the dll import lib over as well! |
| 195 | fs_err::copy(dll_lib, "vmgs_lib.dll.lib")?; |
| 196 | fs_err::copy(dll, "vmgs_lib.dll")?; |
| 197 | |
| 198 | flowey::shell_cmd!( |
| 199 | rt, |
| 200 | "clang {vmgs_testlib_c} -o vmgs_lib_test.exe -l vmgs_lib.dll" |
| 201 | ) |
| 202 | .run()?; |
| 203 | flowey::shell_cmd!(rt, "./vmgs_lib_test.exe").run()?; |
| 204 | |
| 205 | Ok(()) |
| 206 | } |
| 207 | }) |
| 208 | } else { |
| 209 | anyhow::bail!("unsupported platform") |
| 210 | } |
| 211 | } else { |
| 212 | ReadVar::from_static(()).into_side_effect() |
| 213 | }; |
| 214 | |
| 215 | ctx.emit_minor_rust_step("report built vmgs_lib", |ctx| { |
| 216 | did_test.claim(ctx); |
| 217 | let built_vmgs_lib = built_vmgs_lib.claim(ctx); |
| 218 | let vmgs_lib = vmgs_lib.claim(ctx); |
| 219 | move |rt| { |
| 220 | let built_vmgs_lib = rt.read(built_vmgs_lib); |
| 221 | rt.write(vmgs_lib, &built_vmgs_lib); |
| 222 | } |
| 223 | }); |
| 224 | |
| 225 | Ok(()) |
| 226 | } |
| 227 | } |