mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-26 02:43:24 +00:00
Implement the next OSDK
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
79bdbbe4f9
commit
e4c2151566
@ -3,7 +3,12 @@
|
||||
mod bin;
|
||||
mod grub;
|
||||
|
||||
use std::{ffi::OsString, path::Path, process};
|
||||
use std::{
|
||||
ffi::OsString,
|
||||
path::{Path, PathBuf},
|
||||
process,
|
||||
time::{Duration, SystemTime},
|
||||
};
|
||||
|
||||
use bin::strip_elf_for_qemu;
|
||||
|
||||
@ -15,39 +20,53 @@ use crate::{
|
||||
bin::{AsterBin, AsterBinType, AsterElfMeta},
|
||||
Bundle,
|
||||
},
|
||||
cli::CargoArgs,
|
||||
config_manager::{action::Bootloader, BuildConfig},
|
||||
cli::BuildArgs,
|
||||
config::{
|
||||
scheme::{ActionChoice, BootMethod},
|
||||
Config,
|
||||
},
|
||||
error::Errno,
|
||||
error_msg,
|
||||
util::{get_current_crate_info, get_target_directory},
|
||||
util::{get_cargo_metadata, get_current_crate_info, get_target_directory},
|
||||
};
|
||||
|
||||
pub fn execute_build_command(config: &BuildConfig) {
|
||||
let ws_target_directory = get_target_directory();
|
||||
let osdk_target_directory = ws_target_directory.join(DEFAULT_TARGET_RELPATH);
|
||||
if !osdk_target_directory.exists() {
|
||||
std::fs::create_dir_all(&osdk_target_directory).unwrap();
|
||||
pub fn execute_build_command(config: &Config, build_args: &BuildArgs) {
|
||||
let cargo_target_directory = get_target_directory();
|
||||
let osdk_output_directory = build_args
|
||||
.output
|
||||
.clone()
|
||||
.unwrap_or(cargo_target_directory.join(DEFAULT_TARGET_RELPATH));
|
||||
if !osdk_output_directory.exists() {
|
||||
std::fs::create_dir_all(&osdk_output_directory).unwrap();
|
||||
}
|
||||
let target_info = get_current_crate_info();
|
||||
let bundle_path = osdk_target_directory.join(target_info.name);
|
||||
let bundle_path = osdk_output_directory.join(target_info.name);
|
||||
|
||||
let _bundle = create_base_and_build(
|
||||
let action = if build_args.for_test {
|
||||
ActionChoice::Test
|
||||
} else {
|
||||
ActionChoice::Run
|
||||
};
|
||||
|
||||
let _bundle = create_base_and_cached_build(
|
||||
bundle_path,
|
||||
&osdk_target_directory,
|
||||
&ws_target_directory,
|
||||
&osdk_output_directory,
|
||||
&cargo_target_directory,
|
||||
config,
|
||||
action,
|
||||
&[],
|
||||
);
|
||||
}
|
||||
|
||||
pub fn create_base_and_build(
|
||||
pub fn create_base_and_cached_build(
|
||||
bundle_path: impl AsRef<Path>,
|
||||
osdk_target_directory: impl AsRef<Path>,
|
||||
osdk_output_directory: impl AsRef<Path>,
|
||||
cargo_target_directory: impl AsRef<Path>,
|
||||
config: &BuildConfig,
|
||||
config: &Config,
|
||||
action: ActionChoice,
|
||||
rustflags: &[&str],
|
||||
) -> Bundle {
|
||||
let base_crate_path = osdk_target_directory.as_ref().join("base");
|
||||
let base_crate_path = osdk_output_directory.as_ref().join("base");
|
||||
new_base_crate(
|
||||
&base_crate_path,
|
||||
&get_current_crate_info().name,
|
||||
@ -55,55 +74,108 @@ pub fn create_base_and_build(
|
||||
);
|
||||
let original_dir = std::env::current_dir().unwrap();
|
||||
std::env::set_current_dir(&base_crate_path).unwrap();
|
||||
let bundle = do_build(
|
||||
let bundle = do_cached_build(
|
||||
&bundle_path,
|
||||
&osdk_target_directory,
|
||||
&osdk_output_directory,
|
||||
&cargo_target_directory,
|
||||
config,
|
||||
action,
|
||||
rustflags,
|
||||
);
|
||||
std::env::set_current_dir(original_dir).unwrap();
|
||||
bundle
|
||||
}
|
||||
|
||||
/// If the source is not since modified and the last build is recent, we can reuse the existing bundle.
|
||||
pub fn do_cached_build(
|
||||
bundle_path: impl AsRef<Path>,
|
||||
osdk_output_directory: impl AsRef<Path>,
|
||||
cargo_target_directory: impl AsRef<Path>,
|
||||
config: &Config,
|
||||
action: ActionChoice,
|
||||
rustflags: &[&str],
|
||||
) -> Bundle {
|
||||
let build_a_new_one = || {
|
||||
do_build(
|
||||
&bundle_path,
|
||||
&osdk_output_directory,
|
||||
&cargo_target_directory,
|
||||
config,
|
||||
action,
|
||||
rustflags,
|
||||
)
|
||||
};
|
||||
|
||||
let existing_bundle = Bundle::load(&bundle_path);
|
||||
let Some(existing_bundle) = existing_bundle else {
|
||||
return build_a_new_one();
|
||||
};
|
||||
if existing_bundle.can_run_with_config(config, action).is_err() {
|
||||
return build_a_new_one();
|
||||
}
|
||||
let Ok(built_since) = SystemTime::now().duration_since(existing_bundle.last_modified_time())
|
||||
else {
|
||||
return build_a_new_one();
|
||||
};
|
||||
if built_since > Duration::from_secs(600) {
|
||||
return build_a_new_one();
|
||||
}
|
||||
let workspace_root = {
|
||||
let meta = get_cargo_metadata(None::<&str>, None::<&[&str]>).unwrap();
|
||||
PathBuf::from(meta.get("workspace_root").unwrap().as_str().unwrap())
|
||||
};
|
||||
if get_last_modified_time(workspace_root) < existing_bundle.last_modified_time() {
|
||||
return existing_bundle;
|
||||
}
|
||||
build_a_new_one()
|
||||
}
|
||||
|
||||
pub fn do_build(
|
||||
bundle_path: impl AsRef<Path>,
|
||||
osdk_target_directory: impl AsRef<Path>,
|
||||
osdk_output_directory: impl AsRef<Path>,
|
||||
cargo_target_directory: impl AsRef<Path>,
|
||||
config: &BuildConfig,
|
||||
config: &Config,
|
||||
action: ActionChoice,
|
||||
rustflags: &[&str],
|
||||
) -> Bundle {
|
||||
if bundle_path.as_ref().exists() {
|
||||
std::fs::remove_dir_all(&bundle_path).unwrap();
|
||||
}
|
||||
let mut bundle = Bundle::new(
|
||||
&bundle_path,
|
||||
config.settings.clone(),
|
||||
config.cargo_args.clone(),
|
||||
);
|
||||
let mut bundle = Bundle::new(&bundle_path, config, action);
|
||||
|
||||
info!("Building kernel ELF");
|
||||
let aster_elf = build_kernel_elf(
|
||||
&config.arch,
|
||||
&config.cargo_args,
|
||||
&config.target_arch,
|
||||
&config.build.profile,
|
||||
&config.build.features[..],
|
||||
&cargo_target_directory,
|
||||
rustflags,
|
||||
);
|
||||
|
||||
if matches!(config.settings.bootloader, Some(Bootloader::Qemu)) {
|
||||
let stripped_elf = strip_elf_for_qemu(&osdk_target_directory, &aster_elf);
|
||||
bundle.consume_aster_bin(stripped_elf);
|
||||
}
|
||||
let boot = match action {
|
||||
ActionChoice::Run => &config.run.boot,
|
||||
ActionChoice::Test => &config.test.boot,
|
||||
};
|
||||
|
||||
if matches!(config.settings.bootloader, Some(Bootloader::Grub)) {
|
||||
info!("Building boot device image");
|
||||
let bootdev_image = grub::create_bootdev_image(
|
||||
&osdk_target_directory,
|
||||
&aster_elf,
|
||||
config.settings.initramfs.as_ref(),
|
||||
config,
|
||||
);
|
||||
bundle.consume_vm_image(bootdev_image);
|
||||
match boot.method {
|
||||
BootMethod::GrubRescueIso => {
|
||||
info!("Building boot device image");
|
||||
let bootdev_image = grub::create_bootdev_image(
|
||||
&osdk_output_directory,
|
||||
&aster_elf,
|
||||
boot.initramfs.as_ref(),
|
||||
config,
|
||||
action,
|
||||
);
|
||||
bundle.consume_vm_image(bootdev_image);
|
||||
}
|
||||
BootMethod::QemuDirect => {
|
||||
let stripped_elf = strip_elf_for_qemu(&osdk_output_directory, &aster_elf);
|
||||
bundle.consume_aster_bin(stripped_elf);
|
||||
}
|
||||
BootMethod::GrubQcow2 => {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
bundle
|
||||
@ -111,7 +183,8 @@ pub fn do_build(
|
||||
|
||||
fn build_kernel_elf(
|
||||
arch: &Arch,
|
||||
cargo_args: &CargoArgs,
|
||||
profile: &str,
|
||||
features: &[String],
|
||||
cargo_target_directory: impl AsRef<Path>,
|
||||
rustflags: &[&str],
|
||||
) -> AsterBin {
|
||||
@ -135,12 +208,13 @@ fn build_kernel_elf(
|
||||
command.env_remove("RUSTUP_TOOLCHAIN");
|
||||
command.env("RUSTFLAGS", rustflags.join(" "));
|
||||
command.arg("build");
|
||||
command.arg("--features").arg(features.join(" "));
|
||||
command.arg("--target").arg(&target_os_string);
|
||||
command
|
||||
.arg("--target-dir")
|
||||
.arg(cargo_target_directory.as_ref());
|
||||
command.args(COMMON_CARGO_ARGS);
|
||||
command.arg("--profile=".to_string() + &cargo_args.profile);
|
||||
command.arg("--profile=".to_string() + profile);
|
||||
let status = command.status().unwrap();
|
||||
if !status.success() {
|
||||
error_msg!("Cargo build failed");
|
||||
@ -148,10 +222,10 @@ fn build_kernel_elf(
|
||||
}
|
||||
|
||||
let aster_bin_path = cargo_target_directory.as_ref().join(&target_os_string);
|
||||
let aster_bin_path = if cargo_args.profile == "dev" {
|
||||
let aster_bin_path = if profile == "dev" {
|
||||
aster_bin_path.join("debug")
|
||||
} else {
|
||||
aster_bin_path.join(&cargo_args.profile)
|
||||
aster_bin_path.join(profile)
|
||||
}
|
||||
.join(get_current_crate_info().name);
|
||||
|
||||
@ -167,3 +241,21 @@ fn build_kernel_elf(
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
fn get_last_modified_time(path: impl AsRef<Path>) -> SystemTime {
|
||||
let mut last_modified = SystemTime::UNIX_EPOCH;
|
||||
for entry in std::fs::read_dir(path).unwrap() {
|
||||
let entry = entry.unwrap();
|
||||
if entry.file_name() == "target" {
|
||||
continue;
|
||||
}
|
||||
|
||||
let metadata = entry.metadata().unwrap();
|
||||
if metadata.is_dir() {
|
||||
last_modified = std::cmp::max(last_modified, get_last_modified_time(&entry.path()));
|
||||
} else {
|
||||
last_modified = std::cmp::max(last_modified, metadata.modified().unwrap());
|
||||
}
|
||||
}
|
||||
last_modified
|
||||
}
|
||||
|
Reference in New Issue
Block a user