rust/build_system/src/build.rs

233 lines
7.4 KiB
Rust
Raw Normal View History

2023-12-13 21:35:05 +01:00
use crate::config::{Channel, ConfigInfo};
2023-11-08 17:31:56 +01:00
use crate::utils::{get_gcc_path, run_command, run_command_with_output_and_env, walk_dir};
2023-09-26 16:09:51 +02:00
use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs;
use std::path::Path;
#[derive(Default)]
struct BuildArg {
2023-09-06 19:01:04 -04:00
flags: Vec<String>,
2023-09-26 16:09:51 +02:00
gcc_path: String,
2023-11-08 17:31:56 +01:00
config_info: ConfigInfo,
2023-09-26 16:09:51 +02:00
}
impl BuildArg {
fn new() -> Result<Option<Self>, String> {
let gcc_path = get_gcc_path()?;
let mut build_arg = Self {
gcc_path,
..Default::default()
};
2023-10-04 16:01:02 +02:00
// We skip binary name and the `build` command.
2023-09-26 16:09:51 +02:00
let mut args = std::env::args().skip(2);
while let Some(arg) = args.next() {
match arg.as_str() {
2023-10-04 16:01:02 +02:00
"--no-default-features" => {
2023-09-06 19:01:04 -04:00
build_arg.flags.push("--no-default-features".to_string());
2023-10-04 16:01:02 +02:00
}
2023-09-26 16:09:51 +02:00
"--features" => {
if let Some(arg) = args.next() {
2023-09-06 19:01:04 -04:00
build_arg.flags.push("--features".to_string());
build_arg.flags.push(arg.as_str().into());
2023-09-26 16:09:51 +02:00
} else {
2023-10-04 16:01:02 +02:00
return Err(
"Expected a value after `--features`, found nothing".to_string()
);
2023-09-26 16:09:51 +02:00
}
}
"--help" => {
Self::usage();
return Ok(None);
}
2023-11-08 17:31:56 +01:00
arg => {
if !build_arg.config_info.parse_argument(arg, &mut args)? {
return Err(format!("Unknown argument `{}`", arg));
}
}
2023-09-26 16:09:51 +02:00
}
}
Ok(Some(build_arg))
}
fn usage() {
println!(
r#"
`build` command help:
--no-default-features : Add `--no-default-features` flag
2023-11-08 17:31:56 +01:00
--features [arg] : Add a new feature [arg]"#
);
ConfigInfo::show_usage();
println!(" --help : Show this help");
2023-09-26 16:09:51 +02:00
}
}
2023-12-01 23:57:16 +01:00
pub fn build_sysroot(env: &HashMap<String, String>, config: &ConfigInfo) -> Result<(), String> {
let start_dir = Path::new("build_sysroot");
2023-09-26 16:09:51 +02:00
// Cleanup for previous run
2023-10-04 16:01:02 +02:00
// Clean target dir except for build scripts and incremental cache
let _ = walk_dir(
2023-11-08 17:31:56 +01:00
start_dir.join("target"),
2023-09-26 16:09:51 +02:00
|dir: &Path| {
for top in &["debug", "release"] {
2023-10-04 16:01:02 +02:00
let _ = fs::remove_dir_all(dir.join(top).join("build"));
let _ = fs::remove_dir_all(dir.join(top).join("deps"));
let _ = fs::remove_dir_all(dir.join(top).join("examples"));
let _ = fs::remove_dir_all(dir.join(top).join("native"));
2023-09-26 16:09:51 +02:00
2023-10-04 16:01:02 +02:00
let _ = walk_dir(
2023-09-26 16:09:51 +02:00
dir.join(top),
|sub_dir: &Path| {
if sub_dir
.file_name()
2023-10-04 16:01:02 +02:00
.map(|filename| filename.to_str().unwrap().starts_with("libsysroot"))
2023-09-26 16:09:51 +02:00
.unwrap_or(false)
{
2023-10-04 16:01:02 +02:00
let _ = fs::remove_dir_all(sub_dir);
2023-09-26 16:09:51 +02:00
}
Ok(())
},
|file: &Path| {
if file
.file_name()
2023-10-04 16:01:02 +02:00
.map(|filename| filename.to_str().unwrap().starts_with("libsysroot"))
2023-09-26 16:09:51 +02:00
.unwrap_or(false)
{
2023-10-04 16:01:02 +02:00
let _ = fs::remove_file(file);
2023-09-26 16:09:51 +02:00
}
Ok(())
},
);
}
Ok(())
},
|_| Ok(()),
);
2023-11-08 17:31:56 +01:00
let _ = fs::remove_file(start_dir.join("Cargo.lock"));
let _ = fs::remove_file(start_dir.join("test_target/Cargo.lock"));
let _ = fs::remove_dir_all(start_dir.join("sysroot"));
2023-09-26 16:09:51 +02:00
// Builds libs
2023-11-08 17:31:56 +01:00
let mut rustflags = env.get("RUSTFLAGS").cloned().unwrap_or_default();
2023-12-01 23:57:16 +01:00
if config.sysroot_panic_abort {
2023-10-19 07:48:42 -04:00
rustflags.push_str(" -Cpanic=abort -Zpanic-abort-tests");
}
2023-12-13 21:35:05 +01:00
rustflags.push_str(" -Z force-unstable-if-unmarked");
let mut env = env.clone();
2023-12-01 23:57:16 +01:00
let channel = if config.sysroot_release_channel {
2023-11-08 17:31:56 +01:00
env.insert(
"RUSTFLAGS".to_string(),
format!("{} -Zmir-opt-level=3", rustflags),
);
2023-10-04 16:01:02 +02:00
run_command_with_output_and_env(
2023-09-26 16:09:51 +02:00
&[
&"cargo",
&"build",
2023-12-05 21:09:13 +01:00
&"--release",
2023-09-26 16:09:51 +02:00
&"--target",
2023-11-24 22:05:08 +01:00
&config.target_triple,
2023-09-26 16:09:51 +02:00
],
2023-11-08 17:31:56 +01:00
Some(start_dir),
2023-09-26 16:09:51 +02:00
Some(&env),
)?;
"release"
} else {
2023-11-24 22:05:08 +01:00
env.insert("RUSTFLAGS".to_string(), rustflags);
2023-10-04 16:01:02 +02:00
run_command_with_output_and_env(
2023-11-24 22:05:08 +01:00
&[&"cargo", &"build", &"--target", &config.target_triple],
2023-11-08 17:31:56 +01:00
Some(start_dir),
Some(&env),
2023-09-26 16:09:51 +02:00
)?;
"debug"
};
// Copy files to sysroot
2023-11-08 17:31:56 +01:00
let sysroot_path = start_dir.join(format!("sysroot/lib/rustlib/{}/lib/", config.target_triple));
fs::create_dir_all(&sysroot_path).map_err(|error| {
format!(
"Failed to create directory `{}`: {:?}",
sysroot_path.display(),
error
)
})?;
2023-10-04 16:01:02 +02:00
let copier = |dir_to_copy: &Path| {
2023-11-08 17:31:56 +01:00
// FIXME: should not use shell command!
2023-10-04 16:01:02 +02:00
run_command(&[&"cp", &"-r", &dir_to_copy, &sysroot_path], None).map(|_| ())
};
2023-09-26 16:09:51 +02:00
walk_dir(
2023-11-08 17:31:56 +01:00
start_dir.join(&format!("target/{}/{}/deps", config.target_triple, channel)),
2023-09-26 16:09:51 +02:00
copier,
copier,
)?;
// Copy the source files to the sysroot (Rust for Linux needs this).
let sysroot_src_path = "sysroot/lib/rustlib/src/rust";
fs::create_dir_all(&sysroot_src_path).map_err(|error| {
format!(
"Failed to create directory `{}`: {:?}",
sysroot_src_path, error
)
})?;
run_command(
2023-11-22 17:35:49 +01:00
&[
&"cp",
&"-r",
&start_dir.join("sysroot_src/library/"),
&sysroot_src_path,
],
None,
)?;
2023-09-26 16:09:51 +02:00
Ok(())
}
2023-11-08 17:31:56 +01:00
fn build_codegen(args: &mut BuildArg) -> Result<(), String> {
2023-09-26 16:09:51 +02:00
let mut env = HashMap::new();
2023-10-04 16:01:02 +02:00
env.insert("LD_LIBRARY_PATH".to_string(), args.gcc_path.clone());
env.insert("LIBRARY_PATH".to_string(), args.gcc_path.clone());
2023-09-26 16:09:51 +02:00
let mut command: Vec<&dyn AsRef<OsStr>> = vec![&"cargo", &"rustc"];
2023-12-13 21:35:05 +01:00
if args.config_info.channel == Channel::Release {
2023-09-26 16:09:51 +02:00
command.push(&"--release");
2023-10-04 16:01:02 +02:00
env.insert("CHANNEL".to_string(), "release".to_string());
env.insert("CARGO_INCREMENTAL".to_string(), "1".to_string());
2023-09-26 16:09:51 +02:00
} else {
2023-10-04 16:01:02 +02:00
env.insert("CHANNEL".to_string(), "debug".to_string());
2023-09-26 16:09:51 +02:00
}
2023-09-06 19:01:04 -04:00
let flags = args.flags.iter().map(|s| s.as_str()).collect::<Vec<_>>();
for flag in &flags {
command.push(flag);
2023-09-26 16:09:51 +02:00
}
run_command_with_output_and_env(&command, None, Some(&env))?;
2023-09-26 16:09:51 +02:00
2023-12-01 23:57:16 +01:00
args.config_info.setup(&mut env, Some(&args.gcc_path))?;
2023-09-26 16:09:51 +02:00
// We voluntarily ignore the error.
2023-10-04 16:01:02 +02:00
let _ = fs::remove_dir_all("target/out");
2023-09-26 16:09:51 +02:00
let gccjit_target = "target/out/gccjit";
2023-10-04 16:01:02 +02:00
fs::create_dir_all(gccjit_target).map_err(|error| {
format!(
"Failed to create directory `{}`: {:?}",
gccjit_target, error
)
})?;
2023-09-26 16:09:51 +02:00
println!("[BUILD] sysroot");
2023-12-01 23:57:16 +01:00
build_sysroot(&env, &args.config_info)?;
2023-09-26 16:09:51 +02:00
Ok(())
}
2023-08-18 16:06:20 +02:00
pub fn run() -> Result<(), String> {
2023-11-08 17:31:56 +01:00
let mut args = match BuildArg::new()? {
2023-10-04 16:01:02 +02:00
Some(args) => args,
2023-09-26 16:09:51 +02:00
None => return Ok(()),
};
2023-11-08 17:31:56 +01:00
build_codegen(&mut args)?;
2023-08-18 16:06:20 +02:00
Ok(())
}