Merge commit 'b385428e3ddf330805241e7758e773f933357c4b' into subtree-update_cg_gcc_2024-03-05
This commit is contained in:
@@ -1,149 +1,560 @@
|
||||
use crate::utils::{get_gcc_path, get_os_name, get_rustc_host_triple};
|
||||
use crate::utils::{
|
||||
create_symlink, 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, PathBuf};
|
||||
|
||||
use boml::{types::TomlValue, Toml};
|
||||
|
||||
#[derive(Default, PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum Channel {
|
||||
#[default]
|
||||
Debug,
|
||||
Release,
|
||||
}
|
||||
|
||||
impl Channel {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Debug => "debug",
|
||||
Self::Release => "release",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn failed_config_parsing(config_file: &Path, err: &str) -> Result<ConfigFile, String> {
|
||||
Err(format!(
|
||||
"Failed to parse `{}`: {}",
|
||||
config_file.display(),
|
||||
err
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ConfigFile {
|
||||
gcc_path: Option<String>,
|
||||
download_gccjit: Option<bool>,
|
||||
}
|
||||
|
||||
impl ConfigFile {
|
||||
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.display(),
|
||||
)
|
||||
})?;
|
||||
let toml = Toml::parse(&content).map_err(|err| {
|
||||
format!(
|
||||
"Error occurred around `{}`: {:?}",
|
||||
&content[err.start..=err.end],
|
||||
err.kind
|
||||
)
|
||||
})?;
|
||||
let mut config = Self::default();
|
||||
for (key, value) in toml.iter() {
|
||||
match (key, value) {
|
||||
("gcc-path", TomlValue::String(value)) => {
|
||||
config.gcc_path = Some(value.as_str().to_string())
|
||||
}
|
||||
("gcc-path", _) => {
|
||||
return failed_config_parsing(config_file, "Expected a string for `gcc-path`")
|
||||
}
|
||||
("download-gccjit", TomlValue::Boolean(value)) => {
|
||||
config.download_gccjit = Some(*value)
|
||||
}
|
||||
("download-gccjit", _) => {
|
||||
return failed_config_parsing(
|
||||
config_file,
|
||||
"Expected a boolean for `download-gccjit`",
|
||||
)
|
||||
}
|
||||
_ => return failed_config_parsing(config_file, &format!("Unknown key `{}`", key)),
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct ConfigInfo {
|
||||
pub target: String,
|
||||
pub target_triple: String,
|
||||
pub host_triple: String,
|
||||
pub rustc_command: Vec<String>,
|
||||
pub run_in_vm: bool,
|
||||
pub cargo_target_dir: String,
|
||||
pub dylib_ext: String,
|
||||
pub sysroot_release_channel: bool,
|
||||
pub channel: Channel,
|
||||
pub sysroot_panic_abort: bool,
|
||||
pub cg_backend_path: String,
|
||||
pub sysroot_path: String,
|
||||
pub gcc_path: String,
|
||||
config_file: Option<String>,
|
||||
// This is used in particular in rust compiler bootstrap because it doesn't run at the root
|
||||
// of the `cg_gcc` folder, making it complicated for us to get access to local files we need
|
||||
// like `libgccjit.version` or `config.toml`.
|
||||
cg_gcc_path: Option<PathBuf>,
|
||||
// Needed for the `info` command which doesn't want to actually download the lib if needed,
|
||||
// just to set the `gcc_path` field to display it.
|
||||
pub no_download: bool,
|
||||
pub no_default_features: bool,
|
||||
}
|
||||
|
||||
// Returns the beginning for the command line of rustc.
|
||||
pub fn set_config(
|
||||
env: &mut HashMap<String, String>,
|
||||
test_flags: &[String],
|
||||
gcc_path: Option<&str>,
|
||||
) -> Result<ConfigInfo, String> {
|
||||
env.insert("CARGO_INCREMENTAL".to_string(), "0".to_string());
|
||||
|
||||
let gcc_path = match gcc_path {
|
||||
Some(path) => path.to_string(),
|
||||
None => get_gcc_path()?,
|
||||
};
|
||||
env.insert("GCC_PATH".to_string(), gcc_path.clone());
|
||||
|
||||
let os_name = get_os_name()?;
|
||||
let dylib_ext = match os_name.as_str() {
|
||||
"Linux" => "so",
|
||||
"Darwin" => "dylib",
|
||||
os => return Err(format!("unsupported OS `{}`", os)),
|
||||
};
|
||||
let host_triple = get_rustc_host_triple()?;
|
||||
let mut linker = None;
|
||||
let mut target_triple = host_triple.clone();
|
||||
let mut target = target_triple.clone();
|
||||
|
||||
// We skip binary name and the command.
|
||||
let mut args = std::env::args().skip(2);
|
||||
|
||||
let mut set_target_triple = false;
|
||||
let mut set_target = false;
|
||||
while let Some(arg) = args.next() {
|
||||
match arg.as_str() {
|
||||
"--target-triple" => {
|
||||
if let Some(arg) = args.next() {
|
||||
target_triple = arg;
|
||||
set_target_triple = true;
|
||||
} else {
|
||||
return Err(
|
||||
"Expected a value after `--target-triple`, found nothing".to_string()
|
||||
);
|
||||
}
|
||||
},
|
||||
impl ConfigInfo {
|
||||
/// Returns `true` if the argument was taken into account.
|
||||
pub fn parse_argument(
|
||||
&mut self,
|
||||
arg: &str,
|
||||
args: &mut impl Iterator<Item = String>,
|
||||
) -> Result<bool, String> {
|
||||
match arg {
|
||||
"--target" => {
|
||||
if let Some(arg) = args.next() {
|
||||
target = arg;
|
||||
set_target = true;
|
||||
self.target = arg;
|
||||
} else {
|
||||
return Err("Expected a value after `--target`, found nothing".to_string());
|
||||
}
|
||||
}
|
||||
"--target-triple" => match args.next() {
|
||||
Some(arg) if !arg.is_empty() => self.target_triple = arg.to_string(),
|
||||
_ => {
|
||||
return Err(
|
||||
"Expected a value after `--target`, found nothing".to_string()
|
||||
);
|
||||
"Expected a value after `--target-triple`, found nothing".to_string()
|
||||
)
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
"--out-dir" => match args.next() {
|
||||
Some(arg) if !arg.is_empty() => {
|
||||
self.cargo_target_dir = arg.to_string();
|
||||
}
|
||||
_ => return Err("Expected a value after `--out-dir`, found nothing".to_string()),
|
||||
},
|
||||
"--config-file" => match args.next() {
|
||||
Some(arg) if !arg.is_empty() => {
|
||||
self.config_file = Some(arg.to_string());
|
||||
}
|
||||
_ => {
|
||||
return Err("Expected a value after `--config-file`, found nothing".to_string())
|
||||
}
|
||||
},
|
||||
"--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())
|
||||
}
|
||||
},
|
||||
"--no-default-features" => self.no_default_features = true,
|
||||
_ => return Ok(false),
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
pub fn rustc_command_vec(&self) -> Vec<&dyn AsRef<OsStr>> {
|
||||
let mut command: Vec<&dyn AsRef<OsStr>> = Vec::with_capacity(self.rustc_command.len());
|
||||
for arg in self.rustc_command.iter() {
|
||||
command.push(arg);
|
||||
}
|
||||
command
|
||||
}
|
||||
|
||||
pub fn get_gcc_commit(&self) -> Result<String, String> {
|
||||
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();
|
||||
// This is a very simple check to ensure this is not a path. For the rest, it'll just fail
|
||||
// when trying to download the file so we should be fine.
|
||||
if commit.contains('/') || commit.contains('\\') {
|
||||
return Err(format!(
|
||||
"{}: invalid commit hash `{}`",
|
||||
commit_hash_file.display(),
|
||||
commit,
|
||||
));
|
||||
}
|
||||
Ok(commit.to_string())
|
||||
}
|
||||
|
||||
fn download_gccjit_if_needed(&mut self) -> Result<(), String> {
|
||||
let output_dir = Path::new(crate::BUILD_DIR).join("libgccjit");
|
||||
let commit = self.get_gcc_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 output_dir = output_dir.canonicalize().map_err(|err| {
|
||||
format!(
|
||||
"Failed to get absolute path of `{}`: {:?}",
|
||||
output_dir.display(),
|
||||
err
|
||||
)
|
||||
})?;
|
||||
|
||||
let libgccjit_so_name = "libgccjit.so";
|
||||
let libgccjit_so = output_dir.join(libgccjit_so_name);
|
||||
if !libgccjit_so.is_file() && !self.no_download {
|
||||
// Download time!
|
||||
let tempfile_name = format!("{}.download", libgccjit_so_name);
|
||||
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);
|
||||
download_gccjit(url, &output_dir, tempfile_name, !is_in_ci)?;
|
||||
|
||||
let libgccjit_so = output_dir.join(libgccjit_so_name);
|
||||
// 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);
|
||||
// We need to create a link named `libgccjit.so.0` because that's what the linker is
|
||||
// looking for.
|
||||
create_symlink(
|
||||
&libgccjit_so,
|
||||
output_dir.join(&format!("{}.0", libgccjit_so_name)),
|
||||
)?;
|
||||
}
|
||||
|
||||
self.gcc_path = output_dir.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),
|
||||
}
|
||||
}
|
||||
|
||||
if set_target_triple && !set_target {
|
||||
target = target_triple.clone();
|
||||
pub fn setup_gcc_path(&mut self) -> Result<(), String> {
|
||||
let config_file = match self.config_file.as_deref() {
|
||||
Some(config_file) => config_file.into(),
|
||||
None => self.compute_path("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,
|
||||
None => {
|
||||
return Err(format!(
|
||||
"missing `gcc-path` value from `{}`",
|
||||
config_file.display(),
|
||||
))
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
if host_triple != target_triple {
|
||||
linker = Some(format!("-Clinker={}-gcc", target_triple));
|
||||
}
|
||||
let current_dir =
|
||||
std_env::current_dir().map_err(|error| format!("`current_dir` failed: {:?}", error))?;
|
||||
let channel = if let Some(channel) = env.get("CHANNEL") {
|
||||
channel.as_str()
|
||||
} else {
|
||||
"debug"
|
||||
};
|
||||
let cg_backend_path = current_dir
|
||||
.join("target")
|
||||
.join(channel)
|
||||
.join(&format!("librustc_codegen_gcc.{}", dylib_ext));
|
||||
let sysroot_path = current_dir.join("build_sysroot/sysroot");
|
||||
let mut rustflags = Vec::new();
|
||||
if let Some(cg_rustflags) = env.get("CG_RUSTFLAGS") {
|
||||
rustflags.push(cg_rustflags.clone());
|
||||
}
|
||||
if let Some(linker) = linker {
|
||||
rustflags.push(linker.to_string());
|
||||
}
|
||||
rustflags.extend_from_slice(&[
|
||||
"-Csymbol-mangling-version=v0".to_string(),
|
||||
"-Cdebuginfo=2".to_string(),
|
||||
format!("-Zcodegen-backend={}", cg_backend_path.display()),
|
||||
"--sysroot".to_string(),
|
||||
sysroot_path.display().to_string(),
|
||||
]);
|
||||
pub fn setup(
|
||||
&mut self,
|
||||
env: &mut HashMap<String, String>,
|
||||
use_system_gcc: bool,
|
||||
) -> Result<(), String> {
|
||||
env.insert("CARGO_INCREMENTAL".to_string(), "0".to_string());
|
||||
|
||||
if self.gcc_path.is_empty() && !use_system_gcc {
|
||||
self.setup_gcc_path()?;
|
||||
}
|
||||
env.insert("GCC_PATH".to_string(), self.gcc_path.clone());
|
||||
|
||||
if self.cargo_target_dir.is_empty() {
|
||||
match env.get("CARGO_TARGET_DIR").filter(|dir| !dir.is_empty()) {
|
||||
Some(cargo_target_dir) => self.cargo_target_dir = cargo_target_dir.clone(),
|
||||
None => self.cargo_target_dir = "target/out".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
let os_name = get_os_name()?;
|
||||
self.dylib_ext = match os_name.as_str() {
|
||||
"Linux" => "so",
|
||||
"Darwin" => "dylib",
|
||||
os => return Err(format!("unsupported OS `{}`", os)),
|
||||
}
|
||||
.to_string();
|
||||
let rustc = match env.get("RUSTC") {
|
||||
Some(r) if !r.is_empty() => r.to_string(),
|
||||
_ => "rustc".to_string(),
|
||||
};
|
||||
self.host_triple = match rustc_version_info(Some(&rustc))?.host {
|
||||
Some(host) => host,
|
||||
None => return Err("no host found".to_string()),
|
||||
};
|
||||
|
||||
if self.target_triple.is_empty() {
|
||||
if let Some(overwrite) = env.get("OVERWRITE_TARGET_TRIPLE") {
|
||||
self.target_triple = overwrite.clone();
|
||||
}
|
||||
}
|
||||
if self.target_triple.is_empty() {
|
||||
self.target_triple = self.host_triple.clone();
|
||||
}
|
||||
if self.target.is_empty() && !self.target_triple.is_empty() {
|
||||
self.target = self.target_triple.clone();
|
||||
}
|
||||
|
||||
let mut linker = None;
|
||||
|
||||
if self.host_triple != self.target_triple {
|
||||
if self.target_triple.is_empty() {
|
||||
return Err("Unknown non-native platform".to_string());
|
||||
}
|
||||
linker = Some(format!("-Clinker={}-gcc", self.target_triple));
|
||||
self.run_in_vm = true;
|
||||
}
|
||||
|
||||
let current_dir =
|
||||
std_env::current_dir().map_err(|error| format!("`current_dir` failed: {:?}", error))?;
|
||||
let channel = if self.channel == Channel::Release {
|
||||
"release"
|
||||
} else if let Some(channel) = env.get("CHANNEL") {
|
||||
channel.as_str()
|
||||
} else {
|
||||
"debug"
|
||||
};
|
||||
|
||||
let has_builtin_backend = env
|
||||
.get("BUILTIN_BACKEND")
|
||||
.map(|backend| !backend.is_empty())
|
||||
.unwrap_or(false);
|
||||
|
||||
let mut rustflags = Vec::new();
|
||||
if has_builtin_backend {
|
||||
// It means we're building inside the rustc testsuite, so some options need to be handled
|
||||
// a bit differently.
|
||||
self.cg_backend_path = "gcc".to_string();
|
||||
|
||||
match env.get("RUSTC_SYSROOT") {
|
||||
Some(rustc_sysroot) if !rustc_sysroot.is_empty() => {
|
||||
rustflags.extend_from_slice(&["--sysroot".to_string(), rustc_sysroot.clone()]);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
// This should not be needed, but is necessary for the CI in the rust repository.
|
||||
// FIXME: Remove when the rust CI switches to the master version of libgccjit.
|
||||
rustflags.push("-Cpanic=abort".to_string());
|
||||
} else {
|
||||
self.cg_backend_path = current_dir
|
||||
.join("target")
|
||||
.join(channel)
|
||||
.join(&format!("librustc_codegen_gcc.{}", self.dylib_ext))
|
||||
.display()
|
||||
.to_string();
|
||||
self.sysroot_path = current_dir
|
||||
.join("build_sysroot/sysroot")
|
||||
.display()
|
||||
.to_string();
|
||||
rustflags.extend_from_slice(&["--sysroot".to_string(), self.sysroot_path.clone()]);
|
||||
};
|
||||
|
||||
// This environment variable is useful in case we want to change options of rustc commands.
|
||||
if let Some(cg_rustflags) = env.get("CG_RUSTFLAGS") {
|
||||
rustflags.extend_from_slice(&split_args(&cg_rustflags)?);
|
||||
}
|
||||
if let Some(test_flags) = env.get("TEST_FLAGS") {
|
||||
rustflags.extend_from_slice(&split_args(&test_flags)?);
|
||||
}
|
||||
|
||||
if let Some(linker) = linker {
|
||||
rustflags.push(linker.to_string());
|
||||
}
|
||||
|
||||
if self.no_default_features {
|
||||
rustflags.push("-Csymbol-mangling-version=v0".to_string());
|
||||
}
|
||||
|
||||
// Since we don't support ThinLTO, disable LTO completely when not trying to do LTO.
|
||||
// TODO(antoyo): remove when we can handle ThinLTO.
|
||||
if !env.contains_key(&"FAT_LTO".to_string()) {
|
||||
rustflags.push("-Clto=off".to_string());
|
||||
}
|
||||
rustflags.extend_from_slice(test_flags);
|
||||
// FIXME(antoyo): remove once the atomic shim is gone
|
||||
if os_name == "Darwin" {
|
||||
rustflags.extend_from_slice(&[
|
||||
"-Clink-arg=-undefined".to_string(),
|
||||
"-Clink-arg=dynamic_lookup".to_string(),
|
||||
"-Cdebuginfo=2".to_string(),
|
||||
format!("-Zcodegen-backend={}", self.cg_backend_path),
|
||||
]);
|
||||
|
||||
// Since we don't support ThinLTO, disable LTO completely when not trying to do LTO.
|
||||
// TODO(antoyo): remove when we can handle ThinLTO.
|
||||
if !env.contains_key(&"FAT_LTO".to_string()) {
|
||||
rustflags.push("-Clto=off".to_string());
|
||||
}
|
||||
// FIXME(antoyo): remove once the atomic shim is gone
|
||||
if os_name == "Darwin" {
|
||||
rustflags.extend_from_slice(&[
|
||||
"-Clink-arg=-undefined".to_string(),
|
||||
"-Clink-arg=dynamic_lookup".to_string(),
|
||||
]);
|
||||
}
|
||||
env.insert("RUSTFLAGS".to_string(), rustflags.join(" "));
|
||||
// display metadata load errors
|
||||
env.insert("RUSTC_LOG".to_string(), "warn".to_string());
|
||||
|
||||
let sysroot = current_dir.join(&format!(
|
||||
"build_sysroot/sysroot/lib/rustlib/{}/lib",
|
||||
self.target_triple,
|
||||
));
|
||||
let ld_library_path = format!(
|
||||
"{target}:{sysroot}:{gcc_path}",
|
||||
// FIXME: It's possible to pick another out directory. Would be nice to have a command
|
||||
// line option to change it.
|
||||
target = current_dir.join("target/out").display(),
|
||||
sysroot = sysroot.display(),
|
||||
gcc_path = self.gcc_path,
|
||||
);
|
||||
env.insert("LIBRARY_PATH".to_string(), ld_library_path.clone());
|
||||
env.insert("LD_LIBRARY_PATH".to_string(), ld_library_path.clone());
|
||||
env.insert("DYLD_LIBRARY_PATH".to_string(), ld_library_path);
|
||||
|
||||
// NOTE: To avoid the -fno-inline errors, use /opt/gcc/bin/gcc instead of cc.
|
||||
// To do so, add a symlink for cc to /opt/gcc/bin/gcc in our PATH.
|
||||
// Another option would be to add the following Rust flag: -Clinker=/opt/gcc/bin/gcc
|
||||
let path = std::env::var("PATH").unwrap_or_default();
|
||||
env.insert(
|
||||
"PATH".to_string(),
|
||||
format!(
|
||||
"/opt/gcc/bin:/opt/m68k-unknown-linux-gnu/bin{}{}",
|
||||
if path.is_empty() { "" } else { ":" },
|
||||
path
|
||||
),
|
||||
);
|
||||
|
||||
self.rustc_command = vec![rustc];
|
||||
self.rustc_command.extend_from_slice(&rustflags);
|
||||
self.rustc_command.extend_from_slice(&[
|
||||
"-L".to_string(),
|
||||
"crate=target/out".to_string(),
|
||||
"--out-dir".to_string(),
|
||||
self.cargo_target_dir.clone(),
|
||||
]);
|
||||
|
||||
if !env.contains_key("RUSTC_LOG") {
|
||||
env.insert("RUSTC_LOG".to_string(), "warn".to_string());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
env.insert("RUSTFLAGS".to_string(), rustflags.join(" "));
|
||||
// display metadata load errors
|
||||
env.insert("RUSTC_LOG".to_string(), "warn".to_string());
|
||||
|
||||
let sysroot = current_dir.join(&format!(
|
||||
"build_sysroot/sysroot/lib/rustlib/{}/lib",
|
||||
target_triple
|
||||
));
|
||||
let ld_library_path = format!(
|
||||
"{target}:{sysroot}:{gcc_path}",
|
||||
target = current_dir.join("target/out").display(),
|
||||
sysroot = sysroot.display(),
|
||||
);
|
||||
env.insert("LD_LIBRARY_PATH".to_string(), ld_library_path.clone());
|
||||
env.insert("DYLD_LIBRARY_PATH".to_string(), ld_library_path);
|
||||
|
||||
// NOTE: To avoid the -fno-inline errors, use /opt/gcc/bin/gcc instead of cc.
|
||||
// To do so, add a symlink for cc to /opt/gcc/bin/gcc in our PATH.
|
||||
// Another option would be to add the following Rust flag: -Clinker=/opt/gcc/bin/gcc
|
||||
let path = std::env::var("PATH").unwrap_or_default();
|
||||
env.insert("PATH".to_string(), format!("/opt/gcc/bin:{}", path));
|
||||
|
||||
let mut rustc_command = vec!["rustc".to_string()];
|
||||
rustc_command.extend_from_slice(&rustflags);
|
||||
rustc_command.extend_from_slice(&[
|
||||
"-L".to_string(),
|
||||
"crate=target/out".to_string(),
|
||||
"--out-dir".to_string(),
|
||||
"target/out".to_string(),
|
||||
]);
|
||||
Ok(ConfigInfo {
|
||||
target,
|
||||
target_triple,
|
||||
rustc_command,
|
||||
})
|
||||
pub fn show_usage() {
|
||||
println!(
|
||||
"\
|
||||
--target-triple [arg] : Set the target triple to [arg]
|
||||
--target [arg] : Set the target to [arg]
|
||||
--out-dir : Location where the files will be generated
|
||||
--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
|
||||
--cg_gcc-path : Location of the rustc_codegen_gcc root folder (used
|
||||
when ran from another directory)
|
||||
--no-default-features : Add `--no-default-features` flag to cargo commands"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn download_gccjit(
|
||||
url: String,
|
||||
output_dir: &Path,
|
||||
tempfile_name: String,
|
||||
with_progress_bar: bool,
|
||||
) -> Result<(), String> {
|
||||
// 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 with_progress_bar {
|
||||
&"--progress-bar"
|
||||
} else {
|
||||
&"-s"
|
||||
},
|
||||
&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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user