diff options
| author | Guillaume Gomez <guillaume1.gomez@gmail.com> | 2024-02-12 18:07:05 +0100 |
|---|---|---|
| committer | Guillaume Gomez <guillaume1.gomez@gmail.com> | 2024-02-13 15:43:42 +0100 |
| commit | eee04a48d9b0ba2ca7e18c6465c51a63feed8e08 (patch) | |
| tree | e09e3ff9bcb4dad5faa3a1483690ae244ac8103a | |
| parent | 588db24344dc2b626bb050067e9e6cda2de3bc59 (diff) | |
| download | rust-eee04a48d9b0ba2ca7e18c6465c51a63feed8e08.tar.gz rust-eee04a48d9b0ba2ca7e18c6465c51a63feed8e08.zip | |
Add support for "download"
| -rw-r--r-- | build_system/src/config.rs | 201 | ||||
| -rw-r--r-- | libgccjit.version | 1 |
2 files changed, 178 insertions, 24 deletions
diff --git a/build_system/src/config.rs b/build_system/src/config.rs index 49782fc64ef..0201e3509dc 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -1,9 +1,9 @@ -use crate::utils::{get_os_name, rustc_version_info, split_args}; +use crate::utils::{get_os_name, run_command_with_output, rustc_version_info, split_args}; use std::collections::HashMap; use std::env as std_env; use std::ffi::OsStr; use std::fs; -use std::path::Path; +use std::path::{Path, PathBuf}; use boml::{types::TomlValue, Toml}; @@ -23,8 +23,12 @@ impl Channel { } } -fn failed_config_parsing(config_file: &str, err: &str) -> Result<ConfigFile, String> { - Err(format!("Failed to parse `{}`: {}", config_file, err)) +fn failed_config_parsing(config_file: &Path, err: &str) -> Result<ConfigFile, String> { + Err(format!( + "Failed to parse `{}`: {}", + config_file.display(), + err + )) } #[derive(Default)] @@ -34,12 +38,11 @@ pub struct ConfigFile { } impl ConfigFile { - pub fn new(config_file: Option<&str>) -> Result<Self, String> { - let config_file = config_file.unwrap_or("config.toml"); + pub fn new(config_file: &Path) -> Result<Self, String> { let content = fs::read_to_string(config_file).map_err(|_| { format!( "Failed to read `{}`. Take a look at `Readme.md` to see how to set up the project", - config_file, + config_file.display(), ) })?; let toml = Toml::parse(&content).map_err(|err| { @@ -70,19 +73,30 @@ impl ConfigFile { _ => return failed_config_parsing(config_file, &format!("Unknown key `{}`", key)), } } - if config.gcc_path.is_none() && config.download_gccjit.is_none() { - return failed_config_parsing( - config_file, - "At least one of `gcc-path` or `download-gccjit` value must be set", - ); - } - if let Some(gcc_path) = config.gcc_path.as_mut() { - let path = Path::new(gcc_path); - *gcc_path = path - .canonicalize() - .map_err(|err| format!("Failed to get absolute path of `{}`: {:?}", gcc_path, err))? - .display() - .to_string(); + match (config.gcc_path.as_mut(), config.download_gccjit) { + (None, None | Some(false)) => { + return failed_config_parsing( + config_file, + "At least one of `gcc-path` or `download-gccjit` value must be set", + ) + } + (Some(_), Some(true)) => { + println!( + "WARNING: both `gcc-path` and `download-gccjit` arguments are used, \ + ignoring `gcc-path`" + ); + } + (Some(gcc_path), _) => { + let path = Path::new(gcc_path); + *gcc_path = path + .canonicalize() + .map_err(|err| { + format!("Failed to get absolute path of `{}`: {:?}", gcc_path, err) + })? + .display() + .to_string(); + } + _ => {} } Ok(config) } @@ -104,6 +118,7 @@ pub struct ConfigInfo { pub sysroot_path: String, pub gcc_path: String, config_file: Option<String>, + cg_gcc_path: Option<PathBuf>, } impl ConfigInfo { @@ -146,6 +161,14 @@ impl ConfigInfo { "--release-sysroot" => self.sysroot_release_channel = true, "--release" => self.channel = Channel::Release, "--sysroot-panic-abort" => self.sysroot_panic_abort = true, + "--cg_gcc-path" => match args.next() { + Some(arg) if !arg.is_empty() => { + self.cg_gcc_path = Some(arg.into()); + } + _ => { + return Err("Expected a value after `--cg_gcc-path`, found nothing".to_string()) + } + }, _ => return Ok(false), } Ok(true) @@ -159,16 +182,144 @@ impl ConfigInfo { command } + fn download_gccjit_if_needed(&mut self) -> Result<(), String> { + let output_dir = Path::new( + std::env::var("CARGO_TARGET_DIR") + .as_deref() + .unwrap_or("target"), + ) + .join("libgccjit"); + + let commit_hash_file = self.compute_path("libgccjit.version"); + let content = fs::read_to_string(&commit_hash_file).map_err(|_| { + format!( + "Failed to read `{}`. Take a look at `Readme.md` to see how to set up the project", + commit_hash_file.display(), + ) + })?; + let commit = content.trim(); + if commit.contains('/') || commit.contains('\\') { + return Err(format!( + "{}: invalid commit hash `{}`", + commit_hash_file.display(), + commit + )); + } + let output_dir = output_dir.join(commit); + if !output_dir.is_dir() { + std::fs::create_dir_all(&output_dir).map_err(|err| { + format!( + "failed to create folder `{}`: {:?}", + output_dir.display(), + err, + ) + })?; + } + let libgccjit_so = output_dir.join("libgccjit.so"); + if !libgccjit_so.is_file() { + // Download time! + let tempfile_name = "libgccjit.so.download"; + let tempfile = output_dir.join(tempfile_name); + let is_in_ci = std::env::var("GITHUB_ACTIONS").is_ok(); + + let url = format!( + "https://github.com/antoyo/gcc/releases/download/master-{}/libgccjit.so", + commit, + ); + + println!("Downloading `{}`...", url); + // Try curl. If that fails and we are on windows, fallback to PowerShell. + let mut ret = run_command_with_output( + &[ + &"curl", + &"--speed-time", + &"30", + &"--speed-limit", + &"10", // timeout if speed is < 10 bytes/sec for > 30 seconds + &"--connect-timeout", + &"30", // timeout if cannot connect within 30 seconds + &"-o", + &tempfile_name, + &"--retry", + &"3", + &"-SRfL", + if is_in_ci { &"-s" } else { &"--progress-bar" }, + &url.as_str(), + ], + Some(&output_dir), + ); + if ret.is_err() && cfg!(windows) { + eprintln!("Fallback to PowerShell"); + ret = run_command_with_output( + &[ + &"PowerShell.exe", + &"/nologo", + &"-Command", + &"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;", + &format!( + "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')", + url, + tempfile_name, + ).as_str(), + ], + Some(&output_dir), + ); + } + ret?; + + // If we reach this point, it means the file was correctly downloaded, so let's + // rename it! + std::fs::rename(&tempfile, &libgccjit_so).map_err(|err| { + format!( + "Failed to rename `{}` into `{}`: {:?}", + tempfile.display(), + libgccjit_so.display(), + err, + ) + })?; + + println!("Downloaded libgccjit.so version {} successfully!", commit); + } + + self.gcc_path = output_dir + .canonicalize() + .map_err(|err| { + format!( + "Failed to get absolute path of `{}`: {:?}", + output_dir.display(), + err + ) + })? + .display() + .to_string(); + println!("Using `{}` as path for libgccjit", self.gcc_path); + Ok(()) + } + + pub fn compute_path<P: AsRef<Path>>(&self, other: P) -> PathBuf { + match self.cg_gcc_path { + Some(ref path) => path.join(other), + None => PathBuf::new().join(other), + } + } + pub fn setup_gcc_path(&mut self) -> Result<(), String> { - let ConfigFile { gcc_path, .. } = ConfigFile::new(self.config_file.as_deref())?; + let config_file = self.compute_path(self.config_file.as_deref().unwrap_or("config.toml")); + let ConfigFile { + gcc_path, + download_gccjit, + } = ConfigFile::new(&config_file)?; + if let Some(true) = download_gccjit { + self.download_gccjit_if_needed()?; + return Ok(()); + } self.gcc_path = match gcc_path { Some(path) => path, - // FIXME: Once we support "download", rewrite this. None => { return Err(format!( "missing `gcc-path` value from `{}`", - self.config_file.as_deref().unwrap_or("config.toml"), + config_file.display(), )) } }; @@ -362,7 +513,9 @@ impl ConfigInfo { --release : Build in release mode --release-sysroot : Build sysroot in release mode --sysroot-panic-abort : Build the sysroot without unwinding support - --config-file : Location of the config file to be used" + --config-file : Location of the config file to be used + --cg_gcc-path : Location of the rustc_codegen_gcc root folder (used + for accessing any file from the project)" ); } } diff --git a/libgccjit.version b/libgccjit.version new file mode 100644 index 00000000000..3fc84f4ddd4 --- /dev/null +++ b/libgccjit.version @@ -0,0 +1 @@ +2fc8940e1 |
