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::download_lxutil::LxutilArch;
7use crate::init_openvmm_magicpath_openhcl_sysroot::OpenvmmSysrootArch;
8use crate::run_cargo_build::common::CommonArch;
9use crate::run_cargo_build::common::CommonPlatform;
10use crate::run_cargo_build::common::CommonProfile;
11use crate::run_cargo_build::common::CommonTriple;
12use flowey::node::prelude::*;
13use flowey_lib_common::run_cargo_build::CargoBuildProfile;
14use flowey_lib_common::run_cargo_build::CargoFeatureSet;
15use flowey_lib_common::run_cargo_clippy::CargoPackage;
16
17flowey_request! {
18    pub struct Request {
19        pub target: target_lexicon::Triple,
20        pub profile: CommonProfile,
21        pub done: WriteVar<SideEffect>,
22        pub also_check_misc_nostd_crates: bool,
23    }
24}
25
26new_simple_flow_node!(struct Node);
27
28impl SimpleFlowNode for Node {
29    type Request = Request;
30
31    fn imports(ctx: &mut ImportCtx<'_>) {
32        ctx.import::<crate::build_xtask::Node>();
33        ctx.import::<crate::git_checkout_openvmm_repo::Node>();
34        ctx.import::<crate::init_openvmm_magicpath_openhcl_sysroot::Node>();
35        ctx.import::<crate::init_openvmm_magicpath_lxutil::Node>();
36        ctx.import::<crate::install_openvmm_rust_build_essential::Node>();
37        ctx.import::<crate::init_cross_build::Node>();
38        ctx.import::<flowey_lib_common::install_rust::Node>();
39        ctx.import::<flowey_lib_common::install_dist_pkg::Node>();
40        ctx.import::<flowey_lib_common::run_cargo_clippy::Node>();
41    }
42
43    fn process_request(request: Self::Request, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
44        let Request {
45            target,
46            profile,
47            done,
48            also_check_misc_nostd_crates,
49        } = request;
50
51        let flowey_platform = ctx.platform();
52        let flowey_arch = ctx.arch();
53
54        let (boot_target, uefi_target, sysroot_arch, lxutil_arch) = match target.architecture {
55            target_lexicon::Architecture::X86_64 => (
56                "x86_64-unknown-none",
57                "x86_64-unknown-uefi",
58                OpenvmmSysrootArch::X64,
59                LxutilArch::X86_64,
60            ),
61            target_lexicon::Architecture::Aarch64(_) => (
62                "aarch64-unknown-linux-musl",
63                "aarch64-unknown-uefi",
64                OpenvmmSysrootArch::Aarch64,
65                LxutilArch::Aarch64,
66            ),
67            arch => anyhow::bail!("unsupported arch {arch}"),
68        };
69
70        let mut pre_build_deps = Vec::new();
71
72        // FIXME: this will go away once we have a dedicated cargo .config.toml
73        // for the openhcl _bin_. until we have that, we are building _every_
74        // musl target using the openhcl toolchain...
75
76        if matches!(target.environment, target_lexicon::Environment::Musl) {
77            pre_build_deps.push(
78                ctx.reqv(|v| crate::init_openvmm_magicpath_openhcl_sysroot::Request {
79                    arch: sysroot_arch,
80                    path: v,
81                })
82                .into_side_effect(),
83            );
84        }
85
86        // required due to build-scripts in the openvmm repo
87        pre_build_deps.push(ctx.reqv(|v| crate::init_openvmm_magicpath_lxutil::Request {
88            arch: lxutil_arch,
89            done: v,
90        }));
91
92        ctx.req(flowey_lib_common::install_rust::Request::InstallTargetTriple(target.clone()));
93        if also_check_misc_nostd_crates {
94            ctx.req(
95                flowey_lib_common::install_rust::Request::InstallTargetTriple(
96                    target_lexicon::triple!(uefi_target),
97                ),
98            );
99            ctx.req(
100                flowey_lib_common::install_rust::Request::InstallTargetTriple(
101                    target_lexicon::triple!(boot_target),
102                ),
103            );
104        }
105
106        pre_build_deps.push(
107            ctx.reqv(|v| flowey_lib_common::install_dist_pkg::Request::Install {
108                package_names: vec!["libssl-dev".into()],
109                done: v,
110            }),
111        );
112
113        pre_build_deps.push(ctx.reqv(crate::install_openvmm_rust_build_essential::Request));
114
115        // Cross compiling for MacOS isn't supported, but clippy still works
116        // with no additional dependencies
117        if !matches!(
118            target.operating_system,
119            target_lexicon::OperatingSystem::Darwin(_)
120        ) {
121            pre_build_deps.push(
122                ctx.reqv(|v| crate::init_cross_build::Request {
123                    target: target.clone(),
124                    injected_env: v,
125                })
126                .into_side_effect(),
127            );
128        }
129
130        let xtask_target = CommonTriple::Common {
131            arch: match flowey_arch {
132                FlowArch::X86_64 => CommonArch::X86_64,
133                FlowArch::Aarch64 => CommonArch::Aarch64,
134                arch => anyhow::bail!("unsupported arch {arch}"),
135            },
136            platform: match flowey_platform {
137                FlowPlatform::Windows => CommonPlatform::WindowsMsvc,
138                FlowPlatform::Linux(_) => CommonPlatform::LinuxGnu,
139                FlowPlatform::MacOs => CommonPlatform::MacOs,
140                platform => anyhow::bail!("unsupported platform {platform}"),
141            },
142        };
143
144        let xtask = ctx.reqv(|v| crate::build_xtask::Request {
145            target: xtask_target,
146            xtask: v,
147        });
148
149        let profile = match profile {
150            CommonProfile::Release => CargoBuildProfile::Release,
151            CommonProfile::Debug => CargoBuildProfile::Debug,
152        };
153
154        let openvmm_repo_path = ctx.reqv(crate::git_checkout_openvmm_repo::req::GetRepoDir);
155
156        let exclude = ctx.emit_rust_stepv("determine clippy exclusions", |ctx| {
157            let xtask = xtask.claim(ctx);
158            let repo_path = openvmm_repo_path.clone().claim(ctx);
159            move |rt| {
160                let xtask = rt.read(xtask);
161                let repo_path = rt.read(repo_path);
162
163                let mut exclude = vec!["guest_test_uefi".into()];
164
165                // packages depending on libfuzzer-sys are currently x86 only
166                if !(matches!(target.architecture, target_lexicon::Architecture::X86_64)
167                    && matches!(flowey_arch, FlowArch::X86_64))
168                {
169                    let xtask_bin = match xtask {
170                        crate::build_xtask::XtaskOutput::LinuxBin { bin, dbg: _ } => bin,
171                        crate::build_xtask::XtaskOutput::WindowsBin { exe, pdb: _ } => exe,
172                    };
173
174                    let sh = xshell::Shell::new()?;
175                    sh.change_dir(repo_path);
176                    let output = xshell::cmd!(sh, "{xtask_bin} fuzz list --crates").output()?;
177                    let output = String::from_utf8(output.stdout)?;
178
179                    let fuzz_crates = output.trim().split('\n').map(|s| s.to_owned());
180                    exclude.extend(fuzz_crates);
181
182                    exclude.push("chipset_device_fuzz".into());
183                    exclude.push("xtask_fuzz".into());
184                }
185
186                // packages requiring openssl-sys won't cross compile for macos
187                if matches!(
188                    target.operating_system,
189                    target_lexicon::OperatingSystem::Darwin(_)
190                ) {
191                    exclude.extend(
192                        ["openssl_kdf", "vmgs_lib", "block_crypto", "disk_crypt"].map(|x| x.into()),
193                    );
194                }
195
196                Ok(Some(exclude))
197            }
198        });
199
200        let extra_env = if matches!(
201            target.operating_system,
202            target_lexicon::OperatingSystem::Darwin(_)
203        ) {
204            Some(vec![("SPARSE_MMAP_NO_BUILD".into(), "1".into())])
205        } else {
206            None
207        };
208
209        // HACK: the following behavior has been cargo-culted from our old
210        // CI, and at some point, we should actually improve the testing
211        // story on windows, so that we can run with FeatureSet::All in CI.
212        //
213        // On windows & mac, we can't build with all features, as many crates
214        // require openSSL for crypto, which isn't supported in CI yet.
215        let features = if matches!(
216            target.operating_system,
217            target_lexicon::OperatingSystem::Windows | target_lexicon::OperatingSystem::Darwin(_)
218        ) {
219            CargoFeatureSet::None
220        } else {
221            CargoFeatureSet::All
222        };
223
224        let mut reqs = vec![ctx.reqv(|v| flowey_lib_common::run_cargo_clippy::Request {
225            in_folder: openvmm_repo_path.clone(),
226            package: CargoPackage::Workspace,
227            profile: profile.clone(),
228            features: features.clone(),
229            target,
230            extra_env,
231            exclude,
232            keep_going: true,
233            all_targets: true,
234            pre_build_deps: pre_build_deps.clone(),
235            done: v,
236        })];
237
238        if also_check_misc_nostd_crates {
239            reqs.push(ctx.reqv(|v| flowey_lib_common::run_cargo_clippy::Request {
240                in_folder: openvmm_repo_path.clone(),
241                package: CargoPackage::Crate("openhcl_boot".into()),
242                profile: profile.clone(),
243                features: features.clone(),
244                target: target_lexicon::triple!(boot_target),
245                extra_env: Some(vec![("MINIMAL_RT_BUILD".into(), "1".into())]),
246                exclude: ReadVar::from_static(None),
247                keep_going: true,
248                all_targets: false,
249                pre_build_deps: pre_build_deps.clone(),
250                done: v,
251            }));
252
253            // don't pass --all-targets, since that pulls in a std dependency
254            reqs.push(ctx.reqv(|v| flowey_lib_common::run_cargo_clippy::Request {
255                in_folder: openvmm_repo_path.clone(),
256                package: CargoPackage::Crate("guest_test_uefi".into()),
257                profile: profile.clone(),
258                features,
259                target: target_lexicon::triple!(uefi_target),
260                extra_env: None,
261                exclude: ReadVar::from_static(None),
262                keep_going: true,
263                all_targets: false,
264                pre_build_deps: pre_build_deps.clone(),
265                done: v,
266            }));
267        }
268
269        ctx.emit_side_effect_step(reqs, [done]);
270
271        Ok(())
272    }
273}