Skip to content

Commit eee04a4

Browse files
Add support for "download"
1 parent 588db24 commit eee04a4

File tree

2 files changed

+178
-24
lines changed

2 files changed

+178
-24
lines changed

build_system/src/config.rs

Lines changed: 177 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
use crate::utils::{get_os_name, rustc_version_info, split_args};
1+
use crate::utils::{get_os_name, run_command_with_output, rustc_version_info, split_args};
22
use std::collections::HashMap;
33
use std::env as std_env;
44
use std::ffi::OsStr;
55
use std::fs;
6-
use std::path::Path;
6+
use std::path::{Path, PathBuf};
77

88
use boml::{types::TomlValue, Toml};
99

@@ -23,8 +23,12 @@ impl Channel {
2323
}
2424
}
2525

26-
fn failed_config_parsing(config_file: &str, err: &str) -> Result<ConfigFile, String> {
27-
Err(format!("Failed to parse `{}`: {}", config_file, err))
26+
fn failed_config_parsing(config_file: &Path, err: &str) -> Result<ConfigFile, String> {
27+
Err(format!(
28+
"Failed to parse `{}`: {}",
29+
config_file.display(),
30+
err
31+
))
2832
}
2933

3034
#[derive(Default)]
@@ -34,12 +38,11 @@ pub struct ConfigFile {
3438
}
3539

3640
impl ConfigFile {
37-
pub fn new(config_file: Option<&str>) -> Result<Self, String> {
38-
let config_file = config_file.unwrap_or("config.toml");
41+
pub fn new(config_file: &Path) -> Result<Self, String> {
3942
let content = fs::read_to_string(config_file).map_err(|_| {
4043
format!(
4144
"Failed to read `{}`. Take a look at `Readme.md` to see how to set up the project",
42-
config_file,
45+
config_file.display(),
4346
)
4447
})?;
4548
let toml = Toml::parse(&content).map_err(|err| {
@@ -70,19 +73,30 @@ impl ConfigFile {
7073
_ => return failed_config_parsing(config_file, &format!("Unknown key `{}`", key)),
7174
}
7275
}
73-
if config.gcc_path.is_none() && config.download_gccjit.is_none() {
74-
return failed_config_parsing(
75-
config_file,
76-
"At least one of `gcc-path` or `download-gccjit` value must be set",
77-
);
78-
}
79-
if let Some(gcc_path) = config.gcc_path.as_mut() {
80-
let path = Path::new(gcc_path);
81-
*gcc_path = path
82-
.canonicalize()
83-
.map_err(|err| format!("Failed to get absolute path of `{}`: {:?}", gcc_path, err))?
84-
.display()
85-
.to_string();
76+
match (config.gcc_path.as_mut(), config.download_gccjit) {
77+
(None, None | Some(false)) => {
78+
return failed_config_parsing(
79+
config_file,
80+
"At least one of `gcc-path` or `download-gccjit` value must be set",
81+
)
82+
}
83+
(Some(_), Some(true)) => {
84+
println!(
85+
"WARNING: both `gcc-path` and `download-gccjit` arguments are used, \
86+
ignoring `gcc-path`"
87+
);
88+
}
89+
(Some(gcc_path), _) => {
90+
let path = Path::new(gcc_path);
91+
*gcc_path = path
92+
.canonicalize()
93+
.map_err(|err| {
94+
format!("Failed to get absolute path of `{}`: {:?}", gcc_path, err)
95+
})?
96+
.display()
97+
.to_string();
98+
}
99+
_ => {}
86100
}
87101
Ok(config)
88102
}
@@ -104,6 +118,7 @@ pub struct ConfigInfo {
104118
pub sysroot_path: String,
105119
pub gcc_path: String,
106120
config_file: Option<String>,
121+
cg_gcc_path: Option<PathBuf>,
107122
}
108123

109124
impl ConfigInfo {
@@ -146,6 +161,14 @@ impl ConfigInfo {
146161
"--release-sysroot" => self.sysroot_release_channel = true,
147162
"--release" => self.channel = Channel::Release,
148163
"--sysroot-panic-abort" => self.sysroot_panic_abort = true,
164+
"--cg_gcc-path" => match args.next() {
165+
Some(arg) if !arg.is_empty() => {
166+
self.cg_gcc_path = Some(arg.into());
167+
}
168+
_ => {
169+
return Err("Expected a value after `--cg_gcc-path`, found nothing".to_string())
170+
}
171+
},
149172
_ => return Ok(false),
150173
}
151174
Ok(true)
@@ -159,16 +182,144 @@ impl ConfigInfo {
159182
command
160183
}
161184

185+
fn download_gccjit_if_needed(&mut self) -> Result<(), String> {
186+
let output_dir = Path::new(
187+
std::env::var("CARGO_TARGET_DIR")
188+
.as_deref()
189+
.unwrap_or("target"),
190+
)
191+
.join("libgccjit");
192+
193+
let commit_hash_file = self.compute_path("libgccjit.version");
194+
let content = fs::read_to_string(&commit_hash_file).map_err(|_| {
195+
format!(
196+
"Failed to read `{}`. Take a look at `Readme.md` to see how to set up the project",
197+
commit_hash_file.display(),
198+
)
199+
})?;
200+
let commit = content.trim();
201+
if commit.contains('/') || commit.contains('\\') {
202+
return Err(format!(
203+
"{}: invalid commit hash `{}`",
204+
commit_hash_file.display(),
205+
commit
206+
));
207+
}
208+
let output_dir = output_dir.join(commit);
209+
if !output_dir.is_dir() {
210+
std::fs::create_dir_all(&output_dir).map_err(|err| {
211+
format!(
212+
"failed to create folder `{}`: {:?}",
213+
output_dir.display(),
214+
err,
215+
)
216+
})?;
217+
}
218+
let libgccjit_so = output_dir.join("libgccjit.so");
219+
if !libgccjit_so.is_file() {
220+
// Download time!
221+
let tempfile_name = "libgccjit.so.download";
222+
let tempfile = output_dir.join(tempfile_name);
223+
let is_in_ci = std::env::var("GITHUB_ACTIONS").is_ok();
224+
225+
let url = format!(
226+
"https://github.com/antoyo/gcc/releases/download/master-{}/libgccjit.so",
227+
commit,
228+
);
229+
230+
println!("Downloading `{}`...", url);
231+
// Try curl. If that fails and we are on windows, fallback to PowerShell.
232+
let mut ret = run_command_with_output(
233+
&[
234+
&"curl",
235+
&"--speed-time",
236+
&"30",
237+
&"--speed-limit",
238+
&"10", // timeout if speed is < 10 bytes/sec for > 30 seconds
239+
&"--connect-timeout",
240+
&"30", // timeout if cannot connect within 30 seconds
241+
&"-o",
242+
&tempfile_name,
243+
&"--retry",
244+
&"3",
245+
&"-SRfL",
246+
if is_in_ci { &"-s" } else { &"--progress-bar" },
247+
&url.as_str(),
248+
],
249+
Some(&output_dir),
250+
);
251+
if ret.is_err() && cfg!(windows) {
252+
eprintln!("Fallback to PowerShell");
253+
ret = run_command_with_output(
254+
&[
255+
&"PowerShell.exe",
256+
&"/nologo",
257+
&"-Command",
258+
&"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;",
259+
&format!(
260+
"(New-Object System.Net.WebClient).DownloadFile('{}', '{}')",
261+
url,
262+
tempfile_name,
263+
).as_str(),
264+
],
265+
Some(&output_dir),
266+
);
267+
}
268+
ret?;
269+
270+
// If we reach this point, it means the file was correctly downloaded, so let's
271+
// rename it!
272+
std::fs::rename(&tempfile, &libgccjit_so).map_err(|err| {
273+
format!(
274+
"Failed to rename `{}` into `{}`: {:?}",
275+
tempfile.display(),
276+
libgccjit_so.display(),
277+
err,
278+
)
279+
})?;
280+
281+
println!("Downloaded libgccjit.so version {} successfully!", commit);
282+
}
283+
284+
self.gcc_path = output_dir
285+
.canonicalize()
286+
.map_err(|err| {
287+
format!(
288+
"Failed to get absolute path of `{}`: {:?}",
289+
output_dir.display(),
290+
err
291+
)
292+
})?
293+
.display()
294+
.to_string();
295+
println!("Using `{}` as path for libgccjit", self.gcc_path);
296+
Ok(())
297+
}
298+
299+
pub fn compute_path<P: AsRef<Path>>(&self, other: P) -> PathBuf {
300+
match self.cg_gcc_path {
301+
Some(ref path) => path.join(other),
302+
None => PathBuf::new().join(other),
303+
}
304+
}
305+
162306
pub fn setup_gcc_path(&mut self) -> Result<(), String> {
163-
let ConfigFile { gcc_path, .. } = ConfigFile::new(self.config_file.as_deref())?;
307+
let config_file = self.compute_path(self.config_file.as_deref().unwrap_or("config.toml"));
308+
let ConfigFile {
309+
gcc_path,
310+
download_gccjit,
311+
} = ConfigFile::new(&config_file)?;
164312

313+
if let Some(true) = download_gccjit {
314+
self.download_gccjit_if_needed()?;
315+
return Ok(());
316+
}
165317
self.gcc_path = match gcc_path {
166318
Some(path) => path,
167-
// FIXME: Once we support "download", rewrite this.
168319
None => {
169320
return Err(format!(
170321
"missing `gcc-path` value from `{}`",
171-
self.config_file.as_deref().unwrap_or("config.toml"),
322+
config_file.display(),
172323
))
173324
}
174325
};
@@ -362,7 +513,9 @@ impl ConfigInfo {
362513
--release : Build in release mode
363514
--release-sysroot : Build sysroot in release mode
364515
--sysroot-panic-abort : Build the sysroot without unwinding support
365-
--config-file : Location of the config file to be used"
516+
--config-file : Location of the config file to be used
517+
--cg_gcc-path : Location of the rustc_codegen_gcc root folder (used
518+
for accessing any file from the project)"
366519
);
367520
}
368521
}

libgccjit.version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2fc8940e1

0 commit comments

Comments
 (0)