Skip to content

Commit

Permalink
Rustify prepare.sh command
Browse files Browse the repository at this point in the history
  • Loading branch information
GuillaumeGomez committed Aug 18, 2023
1 parent 4748fdc commit 31bc169
Show file tree
Hide file tree
Showing 9 changed files with 285 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ tools/llvmint
tools/llvmint-2
# The `llvm` folder is generated by the `tools/generate_intrinsics.py` script to update intrinsics.
llvm
build_system/target
7 changes: 7 additions & 0 deletions build_system/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions build_system/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "y"
version = "0.1.0"
edition = "2021"

[[bin]]
name = "y"
path = "src/main.rs"

[features]
unstable-features = [] # for rust-analyzer
3 changes: 3 additions & 0 deletions build_system/src/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub fn run() -> Result<(), String> {
Ok(())
}
52 changes: 52 additions & 0 deletions build_system/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#![feature(exclusive_range_pattern)]

use std::env;
use std::process;

mod build;
mod prepare;
mod rustc_info;
mod utils;

macro_rules! arg_error {
($($err:tt)*) => {{
eprintln!($($err)*);
usage();
std::process::exit(1);
}};
}

fn usage() {
// eprintln!("{}", include_str!("usage.txt"));
}

pub enum Command {
Prepare,
Build,
}

fn main() {
if env::var("RUST_BACKTRACE").is_err() {
env::set_var("RUST_BACKTRACE", "1");
}

let mut args = env::args().skip(1);
let command = match args.next().as_deref() {
Some("prepare") => Command::Prepare,
Some("build") => Command::Build,
Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag),
Some(command) => arg_error!("Unknown command {}", command),
None => {
usage();
process::exit(0);
}
};

if let Err(e) = match command {
Command::Prepare => prepare::run(),
Command::Build => build::run(),
} {
eprintln!("Command failed to run: {e:?}");
process::exit(1);
}
}
113 changes: 113 additions & 0 deletions build_system/src/prepare.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
use crate::rustc_info::get_rustc_path;
use crate::utils::{cargo_install, git_clone, run_command, walk_dir};

use std::fs;
use std::path::Path;

fn prepare_libcore() -> Result<(), String> {
let rustc_path = match get_rustc_path() {
Some(path) => path,
None => return Err("`rustc` path not found".to_owned()),
};

let parent = match rustc_path.parent() {
Some(path) => path,
None => return Err(format!("No parent for `{}`", rustc_path.display())),
};

let src_dir = parent.join("../lib/rustlib/src/rust");
if !src_dir.is_dir() {
return Err("Please install `rust-src` component".to_owned());
}

let dst_dir = Path::new("sysroot_src");
if dst_dir.is_dir() {
if let Err(e) = fs::remove_dir_all(dst_dir) {
return Err(format!("Failed to remove `{}`: {:?}", dst_dir.display(), e));
}
}

let dst_dir = dst_dir.join("library");
fs::create_dir_all(&dst_dir)
.map_err(|e| format!("Failed to folder `{}`: {e:?}", dst_dir.display()))?;

run_command(&[&"cp", &"-r", &src_dir, &dst_dir], None)?;

println!("[GIT] init (cwd): `{}`", dst_dir.display());
run_command(&[&"git", &"init"], Some(&dst_dir))?;
println!("[GIT] add (cwd): `{}`", dst_dir.display());
run_command(&[&"git", &"add", &"."], Some(&dst_dir))?;
println!("[GIT] commit (cwd): `{}`", dst_dir.display());

// This is needed on systems where nothing is configured.
// git really needs something here, or it will fail.
// Even using --author is not enough.
run_command(&[&"git", &"config", &"user.email", &"[email protected]"], Some(&dst_dir))?;
run_command(&[&"git", &"config", &"user.name", &"None"], Some(&dst_dir))?;
run_command(&[&"git", &"commit", &"-m", &"Initial commit", &"-q"], Some(&dst_dir))?;

walk_dir("patches", |_| Ok(()), |file_path: &Path| {
println!("[GIT] apply `{}`", file_path.display());
let path = Path::new("../..").join(file_path);
run_command(&[&"git", &"apply", &path], Some(&dst_dir))?;
run_command(&[&"git", &"add", &"-A"], Some(&dst_dir))?;
run_command(
&[&"git", &"commit", &"--no-gpg-sign", &"-m", &format!("Patch {}", path.display())],
Some(&dst_dir),
)?;
Ok(())
})?;
println!("Successfully prepared libcore for building");
Ok(())
}

// build with cg_llvm for perf comparison
fn build_raytracer(repo_dir: &Path) -> Result<(), String> {
run_command(&[&"cargo", &"build"], Some(repo_dir))?;
run_command(&[&"mv", &"target/debug/main", &"raytracer_cg_llvm"], Some(repo_dir))?;
Ok(())
}

fn clone_and_setup<F>(repo_url: &str, checkout_commit: &str, extra: Option<F>) -> Result<(), String>
where
F: Fn(&Path) -> Result<(), String>,
{
let res = git_clone(repo_url, None)?;
if !res.ran_clone {
println!("`{}` has already been cloned", res.repo_name);
}
let repo_path = Path::new(&res.repo_name);
run_command(&[&"git", &"checkout", &"--", &"."], Some(repo_path))?;
run_command(&[&"git", &"checkout", &checkout_commit], Some(repo_path))?;
let filter = format!("-{}-", res.repo_name);
walk_dir("crate_patches", |_| Ok(()), |file_path| {
let s = file_path.as_os_str().to_str().unwrap();
if s.contains(&filter) && s.ends_with(".patch") {
run_command(&[&"git", &"am", &s], Some(repo_path))?;
}
Ok(())
})?;
if let Some(extra) = extra {
extra(repo_path)?;
}
Ok(())
}

pub fn run() -> Result<(), String> {
prepare_libcore()?;

cargo_install("hyperfine")?;

let to_clone = &[
("https://github.com/rust-random/rand.git", "0f933f9c7176e53b2a3c7952ded484e1783f0bf1", None),
("https://github.com/rust-lang/regex.git", "341f207c1071f7290e3f228c710817c280c8dca1", None),
("https://github.com/ebobby/simple-raytracer", "804a7a21b9e673a482797aa289a18ed480e4d813", Some(build_raytracer)),
];

for (repo_url, checkout_commit, cb) in to_clone {
clone_and_setup(repo_url, checkout_commit, *cb)?;
}

println!("Successfully ran `prepare`");
Ok(())
}
12 changes: 12 additions & 0 deletions build_system/src/rustc_info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use std::path::{Path, PathBuf};

use crate::utils::run_command;

pub fn get_rustc_path() -> Option<PathBuf> {
if let Ok(rustc) = std::env::var("RUSTC") {
return Some(PathBuf::from(rustc));
}
run_command(&[&"rustup", &"which", &"rustc"], None)
.ok()
.map(|out| Path::new(String::from_utf8(out.stdout).unwrap().trim()).to_owned())
}
79 changes: 79 additions & 0 deletions build_system/src/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use std::ffi::OsStr;
use std::fs;
use std::path::Path;
use std::process::{Command, Output};

pub fn run_command(input: &[&dyn AsRef<OsStr>], cwd: Option<&Path>) -> Result<Output, String> {
let (cmd, args) = match input {
[] => panic!("empty command"),
[cmd, args @ ..] => (cmd, args),
};
let mut c = Command::new(cmd);
c.args(args);
if let Some(cwd) = cwd {
c.current_dir(cwd);
}
c.output()
.map_err(|e| format!(
"Command `{}` failed to run: {e:?}",
input.iter().fold(String::new(), |mut acc, s| {
if !acc.is_empty() {
acc.push(' ');
}
acc.push_str(s.as_ref().to_str().unwrap());
acc
})
))
}

pub fn cargo_install(to_install: &str) -> Result<(), String> {
let output = run_command(&[&"cargo", &"install", &"--list"], None)?;

let to_install = format!("{to_install} ");
if String::from_utf8(output.stdout).unwrap().lines().any(|line| line.ends_with(':') && line.starts_with(&to_install)) {
return Ok(());
}
run_command(&[&"cargo", &"install", &to_install], None)?;
Ok(())
}

pub struct CloneResult {
pub ran_clone: bool,
pub repo_name: String,
}

/// Returns `Ok(true)` if the repository was already cloned.
pub fn git_clone(to_clone: &str, dest: Option<&Path>) -> Result<CloneResult, String> {
let repo_name = to_clone.split('/').last().unwrap();
let repo_name = match repo_name.strip_suffix(".git") {
Some(n) => n.to_owned(),
None => repo_name.to_owned(),
};

let dest = dest.unwrap_or_else(|| Path::new(&repo_name));
if dest.is_dir() {
return Ok(CloneResult { ran_clone: false, repo_name });
}

run_command(&[&"git", &"clone", &to_clone, &dest], None)?;
Ok(CloneResult { ran_clone: true, repo_name })
}

pub fn walk_dir<P, D, F>(dir: P, dir_cb: D, file_cb: F) -> Result<(), String>
where
P: AsRef<Path>,
D: Fn(&Path) -> Result<(), String>,
F: Fn(&Path) -> Result<(), String>,
{
let dir = dir.as_ref();
for entry in fs::read_dir(dir).map_err(|e| format!("Failed to read dir `{}`: {e:?}", dir.display()))? {
let entry = entry.map_err(|e| format!("Failed to read entry in `{}`: {e:?}", dir.display()))?;
let entry_path = entry.path();
if entry_path.is_dir() {
dir_cb(&entry_path)?;
} else {
file_cb(&entry_path)?;
}
}
Ok(())
}
7 changes: 7 additions & 0 deletions y.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash

set -e
echo "[BUILD] build system" 1>&2
mkdir -p build_system/target
rustc build_system/src/main.rs -o build_system/target/y -Cdebuginfo=1 --edition 2021
exec ./build_system/target/y "$@"

0 comments on commit 31bc169

Please sign in to comment.