xref: /aosp_15_r20/external/crosvm/prebuilts/src/lib.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker use std::env;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::path::Path;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::path::PathBuf;
8*bb4ee6a4SAndroid Build Coastguard Worker 
9*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::anyhow;
10*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Result;
11*bb4ee6a4SAndroid Build Coastguard Worker use named_lock::NamedLock;
12*bb4ee6a4SAndroid Build Coastguard Worker 
13*bb4ee6a4SAndroid Build Coastguard Worker mod sys;
14*bb4ee6a4SAndroid Build Coastguard Worker 
15*bb4ee6a4SAndroid Build Coastguard Worker static BASE_URL: &str = "https://storage.googleapis.com/chromeos-localmirror/distfiles/prebuilts/";
16*bb4ee6a4SAndroid Build Coastguard Worker static DOWNLOAD_RETRIES: usize = 3;
17*bb4ee6a4SAndroid Build Coastguard Worker 
18*bb4ee6a4SAndroid Build Coastguard Worker // Returns `deps` directory for the current build.
get_deps_directory() -> Result<PathBuf>19*bb4ee6a4SAndroid Build Coastguard Worker fn get_deps_directory() -> Result<PathBuf> {
20*bb4ee6a4SAndroid Build Coastguard Worker     let out_dir = env::var("OUT_DIR")
21*bb4ee6a4SAndroid Build Coastguard Worker         .ok()
22*bb4ee6a4SAndroid Build Coastguard Worker         .ok_or_else(|| anyhow!("OUT_DIR is not set"))?;
23*bb4ee6a4SAndroid Build Coastguard Worker 
24*bb4ee6a4SAndroid Build Coastguard Worker     let dest = PathBuf::from(&out_dir)
25*bb4ee6a4SAndroid Build Coastguard Worker         .parent()
26*bb4ee6a4SAndroid Build Coastguard Worker         .ok_or_else(|| anyhow!("../ not found for {:?}", out_dir))?
27*bb4ee6a4SAndroid Build Coastguard Worker         .parent()
28*bb4ee6a4SAndroid Build Coastguard Worker         .ok_or_else(|| anyhow!("../../ not found for {:?}", out_dir))?
29*bb4ee6a4SAndroid Build Coastguard Worker         .parent()
30*bb4ee6a4SAndroid Build Coastguard Worker         .ok_or_else(|| anyhow!("../../../ not found for {:?}", out_dir))?
31*bb4ee6a4SAndroid Build Coastguard Worker         .join("deps");
32*bb4ee6a4SAndroid Build Coastguard Worker     if dest.is_dir() {
33*bb4ee6a4SAndroid Build Coastguard Worker         Ok(dest)
34*bb4ee6a4SAndroid Build Coastguard Worker     } else {
35*bb4ee6a4SAndroid Build Coastguard Worker         Err(anyhow!(
36*bb4ee6a4SAndroid Build Coastguard Worker             "deps({:?}) directory not found OUT_DIR: {:?}",
37*bb4ee6a4SAndroid Build Coastguard Worker             dest,
38*bb4ee6a4SAndroid Build Coastguard Worker             out_dir
39*bb4ee6a4SAndroid Build Coastguard Worker         ))
40*bb4ee6a4SAndroid Build Coastguard Worker     }
41*bb4ee6a4SAndroid Build Coastguard Worker }
42*bb4ee6a4SAndroid Build Coastguard Worker 
43*bb4ee6a4SAndroid Build Coastguard Worker // We download the prebuilt into deps directory and create a symlink to the downloaded prebuilt in
44*bb4ee6a4SAndroid Build Coastguard Worker // deps parent directory.
45*bb4ee6a4SAndroid Build Coastguard Worker // The symlink will help windows find the dll when an executable is manually run.
46*bb4ee6a4SAndroid Build Coastguard Worker // For example, `file` is downloaded in
47*bb4ee6a4SAndroid Build Coastguard Worker // `target/x86_64-pc-windows-gnu/release/deps/` and a `link` will be crated in
48*bb4ee6a4SAndroid Build Coastguard Worker // `target/x86_64-pc-windows-gnu/release/`.
49*bb4ee6a4SAndroid Build Coastguard Worker // Any executable in those two directories will be able to find the dlls they depend as in the same
50*bb4ee6a4SAndroid Build Coastguard Worker // directory.
51*bb4ee6a4SAndroid Build Coastguard Worker struct PrebuiltPath {
52*bb4ee6a4SAndroid Build Coastguard Worker     file: PathBuf,
53*bb4ee6a4SAndroid Build Coastguard Worker     link: PathBuf,
54*bb4ee6a4SAndroid Build Coastguard Worker }
55*bb4ee6a4SAndroid Build Coastguard Worker 
get_dest_path(filename: &str) -> Result<PrebuiltPath>56*bb4ee6a4SAndroid Build Coastguard Worker fn get_dest_path(filename: &str) -> Result<PrebuiltPath> {
57*bb4ee6a4SAndroid Build Coastguard Worker     let deps = get_deps_directory()?;
58*bb4ee6a4SAndroid Build Coastguard Worker 
59*bb4ee6a4SAndroid Build Coastguard Worker     Ok(PrebuiltPath {
60*bb4ee6a4SAndroid Build Coastguard Worker         file: deps.join(filename),
61*bb4ee6a4SAndroid Build Coastguard Worker         link: deps.parent().unwrap().join(filename),
62*bb4ee6a4SAndroid Build Coastguard Worker     })
63*bb4ee6a4SAndroid Build Coastguard Worker }
64*bb4ee6a4SAndroid Build Coastguard Worker 
get_url(library: &str, filename: &str, version: u32) -> String65*bb4ee6a4SAndroid Build Coastguard Worker fn get_url(library: &str, filename: &str, version: u32) -> String {
66*bb4ee6a4SAndroid Build Coastguard Worker     let build_type = if env::var("DEBUG").is_ok() {
67*bb4ee6a4SAndroid Build Coastguard Worker         "debug"
68*bb4ee6a4SAndroid Build Coastguard Worker     } else {
69*bb4ee6a4SAndroid Build Coastguard Worker         "release"
70*bb4ee6a4SAndroid Build Coastguard Worker     };
71*bb4ee6a4SAndroid Build Coastguard Worker     let platform = env::var("CARGO_CFG_TARGET_FAMILY").unwrap();
72*bb4ee6a4SAndroid Build Coastguard Worker     let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
73*bb4ee6a4SAndroid Build Coastguard Worker     let toolchain = env::var("CARGO_CFG_TARGET_ENV").unwrap();
74*bb4ee6a4SAndroid Build Coastguard Worker 
75*bb4ee6a4SAndroid Build Coastguard Worker     format!("{BASE_URL}{platform}/{arch}/{toolchain}/{library}/{build_type}/{version}/{filename}",)
76*bb4ee6a4SAndroid Build Coastguard Worker }
77*bb4ee6a4SAndroid Build Coastguard Worker 
download_file(url: &str, destination: &Path) -> Result<()>78*bb4ee6a4SAndroid Build Coastguard Worker pub fn download_file(url: &str, destination: &Path) -> Result<()> {
79*bb4ee6a4SAndroid Build Coastguard Worker     let lock = NamedLock::create("crosvm_prebuilts_download")?;
80*bb4ee6a4SAndroid Build Coastguard Worker     let _guard = lock.lock()?;
81*bb4ee6a4SAndroid Build Coastguard Worker 
82*bb4ee6a4SAndroid Build Coastguard Worker     // Another process may have already downloaded this since we last checked.
83*bb4ee6a4SAndroid Build Coastguard Worker     if destination.exists() {
84*bb4ee6a4SAndroid Build Coastguard Worker         println!("Prebuilt {destination:?} has already been downloaded by another process.");
85*bb4ee6a4SAndroid Build Coastguard Worker         return Ok(());
86*bb4ee6a4SAndroid Build Coastguard Worker     }
87*bb4ee6a4SAndroid Build Coastguard Worker 
88*bb4ee6a4SAndroid Build Coastguard Worker     println!("Downloading prebuilt {url} to {destination:?}");
89*bb4ee6a4SAndroid Build Coastguard Worker     let mut attempts_left = DOWNLOAD_RETRIES + 1;
90*bb4ee6a4SAndroid Build Coastguard Worker     loop {
91*bb4ee6a4SAndroid Build Coastguard Worker         attempts_left -= 1;
92*bb4ee6a4SAndroid Build Coastguard Worker         let mut cmd = sys::download_command(url, destination);
93*bb4ee6a4SAndroid Build Coastguard Worker         match cmd.status() {
94*bb4ee6a4SAndroid Build Coastguard Worker             Ok(exit_code) => {
95*bb4ee6a4SAndroid Build Coastguard Worker                 if !exit_code.success() {
96*bb4ee6a4SAndroid Build Coastguard Worker                     if attempts_left == 0 {
97*bb4ee6a4SAndroid Build Coastguard Worker                         return Err(anyhow!("Cannot download {}", url));
98*bb4ee6a4SAndroid Build Coastguard Worker                     } else {
99*bb4ee6a4SAndroid Build Coastguard Worker                         println!("Failed to download {url}. Retrying.");
100*bb4ee6a4SAndroid Build Coastguard Worker                     }
101*bb4ee6a4SAndroid Build Coastguard Worker                 } else {
102*bb4ee6a4SAndroid Build Coastguard Worker                     return Ok(());
103*bb4ee6a4SAndroid Build Coastguard Worker                 }
104*bb4ee6a4SAndroid Build Coastguard Worker             }
105*bb4ee6a4SAndroid Build Coastguard Worker             Err(error) => {
106*bb4ee6a4SAndroid Build Coastguard Worker                 if attempts_left == 0 {
107*bb4ee6a4SAndroid Build Coastguard Worker                     return Err(anyhow!(error));
108*bb4ee6a4SAndroid Build Coastguard Worker                 } else {
109*bb4ee6a4SAndroid Build Coastguard Worker                     println!("Failed to download {url}: {error:?}");
110*bb4ee6a4SAndroid Build Coastguard Worker                 }
111*bb4ee6a4SAndroid Build Coastguard Worker             }
112*bb4ee6a4SAndroid Build Coastguard Worker         }
113*bb4ee6a4SAndroid Build Coastguard Worker     }
114*bb4ee6a4SAndroid Build Coastguard Worker }
115*bb4ee6a4SAndroid Build Coastguard Worker 
116*bb4ee6a4SAndroid Build Coastguard Worker /// Downloads a prebuilt file, with name `filename` of `version` from the `library` into target's
117*bb4ee6a4SAndroid Build Coastguard Worker /// `deps` directory.
download_prebuilt(library: &str, version: u32, filename: &str) -> Result<PathBuf>118*bb4ee6a4SAndroid Build Coastguard Worker pub fn download_prebuilt(library: &str, version: u32, filename: &str) -> Result<PathBuf> {
119*bb4ee6a4SAndroid Build Coastguard Worker     let dest_path = get_dest_path(filename)?;
120*bb4ee6a4SAndroid Build Coastguard Worker     let url = get_url(library, filename, version);
121*bb4ee6a4SAndroid Build Coastguard Worker 
122*bb4ee6a4SAndroid Build Coastguard Worker     println!("downloading prebuilt:{} to:{:?}", url, dest_path.file);
123*bb4ee6a4SAndroid Build Coastguard Worker     download_file(&url, Path::new(&dest_path.file))?;
124*bb4ee6a4SAndroid Build Coastguard Worker     println!(
125*bb4ee6a4SAndroid Build Coastguard Worker         "creating symlink:{:?} linking to:{:?}",
126*bb4ee6a4SAndroid Build Coastguard Worker         dest_path.link, dest_path.file
127*bb4ee6a4SAndroid Build Coastguard Worker     );
128*bb4ee6a4SAndroid Build Coastguard Worker     let _ = std::fs::remove_file(&dest_path.link);
129*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(any(target_os = "android", target_os = "linux"))]
130*bb4ee6a4SAndroid Build Coastguard Worker     std::os::unix::fs::symlink(&dest_path.file, &dest_path.link)?;
131*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(windows)]
132*bb4ee6a4SAndroid Build Coastguard Worker     let _ = std::fs::copy(&dest_path.file, &dest_path.link)?;
133*bb4ee6a4SAndroid Build Coastguard Worker     Ok(dest_path.file)
134*bb4ee6a4SAndroid Build Coastguard Worker }
135*bb4ee6a4SAndroid Build Coastguard Worker 
136*bb4ee6a4SAndroid Build Coastguard Worker /// Downloads a list of prebuilt file, with names in `filenames` of `version` from the `library`
137*bb4ee6a4SAndroid Build Coastguard Worker /// into target's `deps` directory.
download_prebuilts(library: &str, version: u32, filenames: &[&str]) -> Result<Vec<PathBuf>>138*bb4ee6a4SAndroid Build Coastguard Worker pub fn download_prebuilts(library: &str, version: u32, filenames: &[&str]) -> Result<Vec<PathBuf>> {
139*bb4ee6a4SAndroid Build Coastguard Worker     let mut paths = vec![];
140*bb4ee6a4SAndroid Build Coastguard Worker     for filename in filenames {
141*bb4ee6a4SAndroid Build Coastguard Worker         paths.push(download_prebuilt(library, version, filename)?);
142*bb4ee6a4SAndroid Build Coastguard Worker     }
143*bb4ee6a4SAndroid Build Coastguard Worker     Ok(paths)
144*bb4ee6a4SAndroid Build Coastguard Worker }
145