226 lines
6.3 KiB
Rust
Raw Normal View History

use std::{
fs,
path::{Path, PathBuf},
process::Command,
};
2024-11-13 16:31:26 +02:00
use crate::{
env::BuildEnv,
2024-11-13 16:31:26 +02:00
error::Error,
util::{self, git_clone},
};
use super::{
cargo::CargoBuilder,
toolchain_c::{self, Llvm},
};
2024-11-13 16:31:26 +02:00
pub const OPENLIBM_URL: &str = "https://git.alnyan.me/yggdrasil/openlibm.git";
pub struct Ygglibc {
static_lib_file: PathBuf,
shared_lib_file: PathBuf,
crt0_file: PathBuf,
include_paths: Vec<PathBuf>,
}
pub struct Openlibm {
shared_lib_file: PathBuf,
static_lib_file: PathBuf,
include_path: PathBuf,
}
2024-11-15 20:37:59 +02:00
fn build_test_cpp_program(
env: &BuildEnv,
llvm: &Llvm,
install: &mut Vec<(PathBuf, PathBuf)>,
) -> Result<(), Error> {
log::info!("Building a test C++ program [PIE]");
let target_dir = &env.userspace_output_dir;
let mut command = llvm.c_clangpp(env);
command
.args([
"-fpie",
"-Bdynamic",
"-O0",
"-ggdb",
"-fstack-protector-strong",
])
.arg("-o")
.arg(target_dir.join("cpp-test"))
.arg(env.workspace_root.join("test.cpp"));
if !command.status()?.success() {
return Err(Error::ExternalCommandFailed);
}
install.push((target_dir.join("cpp-test"), "cpp-test".into()));
Ok(())
}
fn build_test_c_program(
env: &BuildEnv,
llvm: &Llvm,
install: &mut Vec<(PathBuf, PathBuf)>,
) -> Result<(), Error> {
log::info!("Building a test C program [PIE]");
let target_dir = &env.userspace_output_dir;
let mut command = llvm.c_clang(env);
command
.args([
"-fpie",
"-Bdynamic",
"-O0",
"-ggdb",
"-lm",
"-fstack-protector-strong",
])
.arg("-o")
.arg(target_dir.join("c-test"))
.arg(env.workspace_root.join("test.c"));
if !command.status()?.success() {
return Err(Error::ExternalCommandFailed);
}
install.push((target_dir.join("c-test"), "c-test".into()));
// if env.arch == Arch::x86_64 {
log::info!("Building a test C program [static]");
let mut command = llvm.c_clang(env);
command
2024-11-19 00:09:41 +02:00
.args(["-static", "-O0", "-ggdb", "-fstack-protector-strong", "-lm"])
.arg("-o")
.arg(target_dir.join("c-test-static"))
.arg(env.workspace_root.join("test.c"));
if !command.status()?.success() {
return Err(Error::ExternalCommandFailed);
}
install.push((target_dir.join("c-test-static"), "c-test-static".into()));
// }
Ok(())
}
fn install_ygglibc(env: &BuildEnv, ygglibc: &Ygglibc) -> Result<(), Error> {
log::info!("Installing ygglibc into LLVM sysroot");
let dst_lib_dir = env.llvm_sysroot.join("lib");
let dst_include_dir = env.llvm_sysroot.join("usr/include");
fs::create_dir_all(&dst_lib_dir)?;
fs::create_dir_all(&dst_include_dir)?;
fs::copy(&ygglibc.static_lib_file, dst_lib_dir.join("libygglibc.a"))?;
fs::copy(&ygglibc.shared_lib_file, dst_lib_dir.join("libygglibc.so"))?;
fs::copy(&ygglibc.crt0_file, dst_lib_dir.join("crt0.o"))?;
for path in ygglibc.include_paths.iter() {
util::copy_dir_recursive(path, &dst_include_dir)?;
}
Ok(())
}
fn build_ygglibc(env: &BuildEnv) -> Result<Ygglibc, Error> {
let ygglibc_dir = env.workspace_root.join("userspace/lib/ygglibc");
let target_dir = ygglibc_dir.join(format!(
"target/{}-unknown-none/{}",
env.arch.name(),
env.profile.dir()
));
CargoBuilder::Ygglibc(env).build(&ygglibc_dir)?;
let static_lib_file = target_dir.join("libygglibc.a");
let shared_lib_file = target_dir.join("libygglibc.so");
let crt0_file = target_dir.join("crt0.o");
let generated_includes = target_dir.join("include");
let static_includes = ygglibc_dir.join("include");
Ok(Ygglibc {
static_lib_file,
shared_lib_file,
crt0_file,
include_paths: vec![generated_includes, static_includes],
})
}
// TODO clone openlibm
fn build_openlibm(env: &BuildEnv, llvm: &Llvm) -> Result<Openlibm, Error> {
fn make(env: &BuildEnv, llvm: &Llvm, libm_path: &Path) -> Command {
let mut command = Command::new("make");
command.env("SYSROOT", &env.llvm_sysroot);
command.env("ARCH", env.arch.name());
command.env("OS", "yggdrasil");
command.env("TRIPLE", format!("{}-unknown-yggdrasil", env.arch.name()));
command.env("USEGCC", "0");
command.env("USECLANG", "1");
command.env("CC", llvm.clang());
command.current_dir(&libm_path);
command
}
2024-11-13 16:31:26 +02:00
let libm_path = env
.workspace_root
.join(format!("toolchain-c/libs/openlibm-{}", env.arch.name()));
git_clone(&libm_path, OPENLIBM_URL, "alnyan/yggdrasil")?;
2024-11-13 16:31:26 +02:00
log::info!("Building openlibm");
let mut command = make(env, llvm, &libm_path);
if !command.status()?.success() {
return Err(Error::ExternalCommandFailed);
}
Ok(Openlibm {
shared_lib_file: libm_path.join("libopenlibm.so.4.0"),
static_lib_file: libm_path.join("libopenlibm.a"),
include_path: libm_path.join("include"),
})
}
fn install_openlibm(env: &BuildEnv, libm: &Openlibm) -> Result<(), Error> {
fs::copy(&libm.static_lib_file, env.llvm_sysroot.join("lib/libm.a"))?;
fs::copy(&libm.shared_lib_file, env.llvm_sysroot.join("lib/libm.so"))?;
util::copy_dir_recursive(&libm.include_path, env.llvm_sysroot.join("usr/include"))?;
Ok(())
}
pub fn build_c(env: &BuildEnv, install: &mut Vec<(PathBuf, PathBuf)>) -> Result<(), Error> {
let llvm = toolchain_c::install_llvm_compiler(env)?;
let ygglibc = build_ygglibc(env)?;
install_ygglibc(env, &ygglibc)?;
toolchain_c::install_compiler_rt(env, &llvm)?;
let libm = build_openlibm(env, &llvm)?;
install_openlibm(env, &libm)?;
2024-11-18 20:59:29 +02:00
if env.config.components(env).libcxx {
toolchain_c::install_llvm_cxx_runtime(env, &llvm)?;
}
build_test_c_program(env, &llvm, install)?;
2024-11-18 20:59:29 +02:00
if env.config.components(env).libcxx {
build_test_cpp_program(env, &llvm, install)?;
install.push((
env.llvm_sysroot.join("lib/libc++.so"),
"lib/libc++.so".into(),
));
}
install.push((ygglibc.shared_lib_file, "lib/libygglibc.so".into()));
install.push((libm.shared_lib_file, "lib/libopenlibm.so.4".into()));
Ok(())
}