Skip to main content

flowey_lib_hvlite/_jobs/
check_clippy.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Ensure the OpenVMM repo is `clippy` clean.
5
6use crate::common::CommonArch;
7use crate::common::CommonProfile;
8use crate::common::CommonTriple;
9use flowey::node::prelude::*;
10use flowey_lib_common::run_cargo_build::CargoBuildProfile;
11use flowey_lib_common::run_cargo_build::CargoFeatureSet;
12use flowey_lib_common::run_cargo_clippy::CargoPackage;
13
14flowey_request! {
15    pub struct Request {
16        pub target: target_lexicon::Triple,
17        pub profile: CommonProfile,
18        pub done: WriteVar<SideEffect>,
19        pub also_check_misc_nostd_crates: bool,
20    }
21}
22
23new_simple_flow_node!(struct Node);
24
25impl SimpleFlowNode for Node {
26    type Request = Request;
27
28    fn imports(ctx: &mut ImportCtx<'_>) {
29        ctx.import::<crate::build_xtask::Node>();
30        ctx.import::<crate::git_checkout_openvmm_repo::Node>();
31        ctx.import::<crate::init_openvmm_magicpath_openhcl_sysroot::Node>();
32        ctx.import::<crate::install_openvmm_rust_build_essential::Node>();
33        ctx.import::<crate::init_cross_build::Node>();
34        ctx.import::<flowey_lib_common::install_rust::Node>();
35        ctx.import::<flowey_lib_common::install_dist_pkg::Node>();
36        ctx.import::<flowey_lib_common::run_cargo_clippy::Node>();
37    }
38
39    fn process_request(request: Self::Request, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
40        let Request {
41            target,
42            profile,
43            done,
44            also_check_misc_nostd_crates,
45        } = request;
46
47        let flowey_platform = ctx.platform();
48        let flowey_arch = ctx.arch();
49
50        let sysroot_arch = CommonArch::from_architecture(target.architecture)?;
51        let (boot_target, uefi_target) = match sysroot_arch {
52            CommonArch::X86_64 => ("x86_64-unknown-none", "x86_64-unknown-uefi"),
53            CommonArch::Aarch64 => ("aarch64-unknown-linux-musl", "aarch64-unknown-uefi"),
54        };
55
56        let mut pre_build_deps = Vec::new();
57
58        // FIXME: this will go away once we have a dedicated cargo .config.toml
59        // for the openhcl _bin_. until we have that, we are building _every_
60        // musl target using the openhcl toolchain...
61
62        if matches!(target.environment, target_lexicon::Environment::Musl) {
63            pre_build_deps.push(
64                ctx.reqv(|v| crate::init_openvmm_magicpath_openhcl_sysroot::Request {
65                    arch: sysroot_arch,
66                    path: v,
67                })
68                .into_side_effect(),
69            );
70        }
71
72        ctx.req(flowey_lib_common::install_rust::Request::InstallTargetTriple(target.clone()));
73        if also_check_misc_nostd_crates {
74            ctx.req(
75                flowey_lib_common::install_rust::Request::InstallTargetTriple(
76                    target_lexicon::triple!(uefi_target),
77                ),
78            );
79            ctx.req(
80                flowey_lib_common::install_rust::Request::InstallTargetTriple(
81                    target_lexicon::triple!(boot_target),
82                ),
83            );
84        }
85
86        // TODO: install build tools for other platforms
87        if matches!(
88            ctx.platform(),
89            FlowPlatform::Linux(FlowPlatformLinuxDistro::Ubuntu)
90        ) {
91            pre_build_deps.push(ctx.reqv(|v| {
92                flowey_lib_common::install_dist_pkg::Request::Install {
93                    package_names: vec![
94                        "libssl-dev".into(),
95                        "pkg-config".into(),
96                        "build-essential".into(),
97                    ],
98                    done: v,
99                }
100            }));
101        }
102
103        pre_build_deps.push(ctx.reqv(crate::install_openvmm_rust_build_essential::Request));
104
105        // Cross compiling for MacOS isn't supported, but clippy still works
106        // with no additional dependencies
107        if !matches!(
108            target.operating_system,
109            target_lexicon::OperatingSystem::Darwin(_)
110        ) {
111            pre_build_deps.push(
112                ctx.reqv(|v| crate::init_cross_build::Request {
113                    target: target.clone(),
114                    injected_env: v,
115                })
116                .into_side_effect(),
117            );
118        }
119
120        let xtask_target = CommonTriple::Common {
121            arch: flowey_arch.try_into()?,
122            platform: flowey_platform.try_into()?,
123        };
124
125        let xtask = ctx.reqv(|v| crate::build_xtask::Request {
126            target: xtask_target,
127            xtask: v,
128        });
129
130        let profile = match profile {
131            CommonProfile::Release => CargoBuildProfile::Release,
132            CommonProfile::Debug => CargoBuildProfile::Debug,
133        };
134
135        let openvmm_repo_path = ctx.reqv(crate::git_checkout_openvmm_repo::req::GetRepoDir);
136
137        let exclude = ctx.emit_rust_stepv("determine clippy exclusions", |ctx| {
138            let xtask = xtask.claim(ctx);
139            let repo_path = openvmm_repo_path.clone().claim(ctx);
140            move |rt| {
141                let xtask = rt.read(xtask);
142                let repo_path = rt.read(repo_path);
143
144                // guest_test_uefi is uefi-only, and is handled separately below
145                // crypto is handled separately in order to deal with its non-additive features
146                let mut exclude = vec!["guest_test_uefi".into(), "crypto".into()];
147
148                // packages depending on libfuzzer-sys are currently x86 only
149                if !(matches!(target.architecture, target_lexicon::Architecture::X86_64)
150                    && matches!(flowey_arch, FlowArch::X86_64))
151                {
152                    let xtask_bin = match xtask {
153                        crate::build_xtask::XtaskOutput::LinuxBin { bin, dbg: _ } => bin,
154                        crate::build_xtask::XtaskOutput::WindowsBin { exe, pdb: _ } => exe,
155                    };
156
157                    rt.sh.change_dir(repo_path);
158                    let output =
159                        flowey::shell_cmd!(rt, "{xtask_bin} fuzz list --crates").output()?;
160                    let output = String::from_utf8(output.stdout)?;
161
162                    let fuzz_crates = output.trim().split('\n').map(|s| s.to_owned());
163                    exclude.extend(fuzz_crates);
164                }
165
166                // packages requiring crypto or openssl support won't cross compile for macos
167                if matches!(
168                    target.operating_system,
169                    target_lexicon::OperatingSystem::Darwin(_)
170                ) {
171                    exclude.extend(["openssl_kdf", "vmgs_lib", "disk_crypt"].map(|x| x.into()));
172                }
173
174                Ok(Some(exclude))
175            }
176        });
177
178        // On Windows & Mac we can't build with all features since the TPM
179        // requires OpenSSL for crypto, which isn't supported in CI on those
180        // platforms today.
181        //
182        // We don't add the CI feature here, as it's used purely to exclude
183        // tests that can't run in CI. We still want those tests to be linted.
184        let features = if matches!(
185            target.operating_system,
186            target_lexicon::OperatingSystem::Windows | target_lexicon::OperatingSystem::Darwin(_)
187        ) {
188            CargoFeatureSet::None
189        } else {
190            CargoFeatureSet::All
191        };
192
193        let mut reqs = vec![ctx.reqv(|v| flowey_lib_common::run_cargo_clippy::Request {
194            in_folder: openvmm_repo_path.clone(),
195            package: CargoPackage::Workspace,
196            profile: profile.clone(),
197            features: features.clone(),
198            target: target.clone(),
199            extra_env: None,
200            exclude,
201            keep_going: true,
202            all_targets: true,
203            pre_build_deps: pre_build_deps.clone(),
204            done: v,
205        })];
206
207        // crypto has non-additive features, we need to ensure full coverage of different backends.
208        // Always test the 'native' no-feature backends.
209        reqs.push(ctx.reqv(|v| flowey_lib_common::run_cargo_clippy::Request {
210            in_folder: openvmm_repo_path.clone(),
211            package: CargoPackage::Crate("crypto".into()),
212            profile: profile.clone(),
213            features: CargoFeatureSet::None,
214            target: target.clone(),
215            extra_env: None,
216            exclude: ReadVar::from_static(None),
217            keep_going: true,
218            all_targets: true,
219            pre_build_deps: pre_build_deps.clone(),
220            done: v,
221        }));
222
223        // Always test the pure rust backend.
224        reqs.push(ctx.reqv(|v| flowey_lib_common::run_cargo_clippy::Request {
225            in_folder: openvmm_repo_path.clone(),
226            package: CargoPackage::Crate("crypto".into()),
227            profile: profile.clone(),
228            features: CargoFeatureSet::Specific(vec!["rust".into()]),
229            target: target.clone(),
230            extra_env: None,
231            exclude: ReadVar::from_static(None),
232            keep_going: true,
233            all_targets: true,
234            pre_build_deps: pre_build_deps.clone(),
235            done: v,
236        }));
237
238        // Then on linux test the openssl & symcrypt backends, and ensure that --all-features works properly.
239        // We could test openssl on non-linux targets too, but setting up builds for them is a pain.
240        if matches!(
241            target.operating_system,
242            target_lexicon::OperatingSystem::Linux
243        ) {
244            reqs.push(ctx.reqv(|v| flowey_lib_common::run_cargo_clippy::Request {
245                in_folder: openvmm_repo_path.clone(),
246                package: CargoPackage::Crate("crypto".into()),
247                profile: profile.clone(),
248                features: CargoFeatureSet::Specific(vec!["openssl".into()]),
249                target: target.clone(),
250                extra_env: None,
251                exclude: ReadVar::from_static(None),
252                keep_going: true,
253                all_targets: true,
254                pre_build_deps: pre_build_deps.clone(),
255                done: v,
256            }));
257            // Only test the symcrypt backend on musl targets with our prebuilt lib
258            if matches!(target.environment, target_lexicon::Environment::Musl) {
259                reqs.push(ctx.reqv(|v| flowey_lib_common::run_cargo_clippy::Request {
260                    in_folder: openvmm_repo_path.clone(),
261                    package: CargoPackage::Crate("crypto".into()),
262                    profile: profile.clone(),
263                    features: CargoFeatureSet::Specific(vec!["symcrypt".into()]),
264                    target: target.clone(),
265                    extra_env: None,
266                    exclude: ReadVar::from_static(None),
267                    keep_going: true,
268                    all_targets: true,
269                    pre_build_deps: pre_build_deps.clone(),
270                    done: v,
271                }));
272            }
273            reqs.push(ctx.reqv(|v| flowey_lib_common::run_cargo_clippy::Request {
274                in_folder: openvmm_repo_path.clone(),
275                package: CargoPackage::Crate("crypto".into()),
276                profile: profile.clone(),
277                features: CargoFeatureSet::All,
278                target: target.clone(),
279                extra_env: None,
280                exclude: ReadVar::from_static(None),
281                keep_going: true,
282                all_targets: true,
283                pre_build_deps: pre_build_deps.clone(),
284                done: v,
285            }));
286        }
287
288        if also_check_misc_nostd_crates {
289            // don't pass --all-targets, since that pulls in a std dependency
290            reqs.push(ctx.reqv(|v| flowey_lib_common::run_cargo_clippy::Request {
291                in_folder: openvmm_repo_path.clone(),
292                package: CargoPackage::Crate("openhcl_boot".into()),
293                profile: profile.clone(),
294                features: CargoFeatureSet::All,
295                target: target_lexicon::triple!(boot_target),
296                extra_env: Some(vec![("MINIMAL_RT_BUILD".into(), "1".into())]),
297                exclude: ReadVar::from_static(None),
298                keep_going: true,
299                all_targets: false,
300                pre_build_deps: pre_build_deps.clone(),
301                done: v,
302            }));
303
304            // don't pass --all-targets, since that pulls in a std dependency
305            reqs.push(ctx.reqv(|v| flowey_lib_common::run_cargo_clippy::Request {
306                in_folder: openvmm_repo_path.clone(),
307                package: CargoPackage::Crate("guest_test_uefi".into()),
308                profile: profile.clone(),
309                features: CargoFeatureSet::All,
310                target: target_lexicon::triple!(uefi_target),
311                extra_env: None,
312                exclude: ReadVar::from_static(None),
313                keep_going: true,
314                all_targets: false,
315                pre_build_deps: pre_build_deps.clone(),
316                done: v,
317            }));
318        }
319
320        ctx.emit_side_effect_step(reqs, [done]);
321
322        Ok(())
323    }
324}