mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-26 19:03:27 +00:00
Implement the next OSDK
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
79bdbbe4f9
commit
e4c2151566
@ -14,7 +14,6 @@ use crate::{
|
||||
bin::{AsterBin, AsterBinType, AsterBzImageMeta, AsterElfMeta},
|
||||
file::BundleFile,
|
||||
},
|
||||
config_manager::action::BootProtocol,
|
||||
util::get_current_crate_info,
|
||||
};
|
||||
|
||||
@ -22,13 +21,13 @@ pub fn make_install_bzimage(
|
||||
install_dir: impl AsRef<Path>,
|
||||
target_dir: impl AsRef<Path>,
|
||||
aster_elf: &AsterBin,
|
||||
protocol: &BootProtocol,
|
||||
linux_x86_legacy_boot: bool,
|
||||
) -> AsterBin {
|
||||
let target_name = get_current_crate_info().name;
|
||||
let image_type = match protocol {
|
||||
BootProtocol::LinuxLegacy32 => BzImageType::Legacy32,
|
||||
BootProtocol::LinuxEfiHandover64 => BzImageType::Efi64,
|
||||
_ => unreachable!(),
|
||||
let image_type = if linux_x86_legacy_boot {
|
||||
BzImageType::Legacy32
|
||||
} else {
|
||||
BzImageType::Efi64
|
||||
};
|
||||
let setup_bin = {
|
||||
let setup_install_dir = target_dir.as_ref();
|
||||
@ -60,9 +59,9 @@ pub fn make_install_bzimage(
|
||||
AsterBin::new(
|
||||
&install_path,
|
||||
AsterBinType::BzImage(AsterBzImageMeta {
|
||||
support_legacy32_boot: matches!(protocol, BootProtocol::LinuxLegacy32),
|
||||
support_legacy32_boot: linux_x86_legacy_boot,
|
||||
support_efi_boot: false,
|
||||
support_efi_handover: matches!(protocol, BootProtocol::LinuxEfiHandover64),
|
||||
support_efi_handover: !linux_x86_legacy_boot,
|
||||
}),
|
||||
aster_elf.version().clone(),
|
||||
aster_elf.stripped(),
|
||||
|
@ -12,7 +12,10 @@ use crate::{
|
||||
file::BundleFile,
|
||||
vm_image::{AsterGrubIsoImageMeta, AsterVmImage, AsterVmImageType},
|
||||
},
|
||||
config_manager::{action::BootProtocol, BuildConfig},
|
||||
config::{
|
||||
scheme::{ActionChoice, BootProtocol},
|
||||
Config,
|
||||
},
|
||||
util::get_current_crate_info,
|
||||
};
|
||||
|
||||
@ -20,11 +23,16 @@ pub fn create_bootdev_image(
|
||||
target_dir: impl AsRef<Path>,
|
||||
aster_bin: &AsterBin,
|
||||
initramfs_path: Option<impl AsRef<Path>>,
|
||||
config: &BuildConfig,
|
||||
config: &Config,
|
||||
action: ActionChoice,
|
||||
) -> AsterVmImage {
|
||||
let target_name = get_current_crate_info().name;
|
||||
let iso_root = &target_dir.as_ref().join("iso_root");
|
||||
let protocol = &config.settings.boot_protocol;
|
||||
let action = match &action {
|
||||
ActionChoice::Run => &config.run,
|
||||
ActionChoice::Test => &config.test,
|
||||
};
|
||||
let protocol = &action.grub.boot_protocol;
|
||||
|
||||
// Clear or make the iso dir.
|
||||
if iso_root.exists() {
|
||||
@ -43,12 +51,12 @@ pub fn create_bootdev_image(
|
||||
|
||||
// Make the kernel image and place it in the boot directory.
|
||||
match protocol {
|
||||
Some(BootProtocol::LinuxLegacy32) | Some(BootProtocol::LinuxEfiHandover64) => {
|
||||
BootProtocol::Linux => {
|
||||
make_install_bzimage(
|
||||
iso_root.join("boot"),
|
||||
&target_dir,
|
||||
aster_bin,
|
||||
&protocol.clone().unwrap(),
|
||||
action.build.linux_x86_legacy_boot,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
@ -65,22 +73,17 @@ pub fn create_bootdev_image(
|
||||
None
|
||||
};
|
||||
let grub_cfg = generate_grub_cfg(
|
||||
&config.settings.combined_kcmd_args().join(" "),
|
||||
true,
|
||||
&action.boot.kcmdline.join(" "),
|
||||
!action.grub.display_grub_menu,
|
||||
initramfs_in_image,
|
||||
&protocol.clone().unwrap_or(BootProtocol::Multiboot2),
|
||||
protocol,
|
||||
);
|
||||
let grub_cfg_path = iso_root.join("boot").join("grub").join("grub.cfg");
|
||||
fs::write(grub_cfg_path, grub_cfg).unwrap();
|
||||
|
||||
// Make the boot device CDROM image using `grub-mkrescue`.
|
||||
let iso_path = &target_dir.as_ref().join(target_name.to_string() + ".iso");
|
||||
let grub_mkrescue_bin = &config
|
||||
.settings
|
||||
.grub_mkrescue
|
||||
.clone()
|
||||
.unwrap_or_else(|| PathBuf::from("grub-mkrescue"));
|
||||
let mut grub_mkrescue_cmd = std::process::Command::new(grub_mkrescue_bin.as_os_str());
|
||||
let mut grub_mkrescue_cmd = std::process::Command::new(action.grub.grub_mkrescue.as_os_str());
|
||||
grub_mkrescue_cmd
|
||||
.arg(iso_root.as_os_str())
|
||||
.arg("-o")
|
||||
@ -92,7 +95,7 @@ pub fn create_bootdev_image(
|
||||
AsterVmImage::new(
|
||||
iso_path,
|
||||
AsterVmImageType::GrubIso(AsterGrubIsoImageMeta {
|
||||
grub_version: get_grub_mkrescue_version(grub_mkrescue_bin),
|
||||
grub_version: get_grub_mkrescue_version(&action.grub.grub_mkrescue),
|
||||
}),
|
||||
aster_bin.version().clone(),
|
||||
)
|
||||
@ -115,7 +118,7 @@ fn generate_grub_cfg(
|
||||
"#GRUB_TIMEOUT_STYLE#",
|
||||
if skip_grub_menu { "hidden" } else { "menu" },
|
||||
)
|
||||
.replace("#GRUB_TIMEOUT#", if skip_grub_menu { "0" } else { "1" });
|
||||
.replace("#GRUB_TIMEOUT#", if skip_grub_menu { "0" } else { "5" });
|
||||
// Replace all occurrences of "#KERNEL_COMMAND_LINE#" with the desired value.
|
||||
let grub_cfg = grub_cfg.replace("#KERNEL_COMMAND_LINE#", kcmdline);
|
||||
// Replace the grub commands according to the protocol selected.
|
||||
@ -147,7 +150,7 @@ fn generate_grub_cfg(
|
||||
"".to_owned()
|
||||
},
|
||||
),
|
||||
BootProtocol::LinuxLegacy32 | BootProtocol::LinuxEfiHandover64 => grub_cfg
|
||||
BootProtocol::Linux => grub_cfg
|
||||
.replace("#GRUB_CMD_KERNEL#", "linux")
|
||||
.replace("#KERNEL#", &aster_bin_path_on_device)
|
||||
.replace(
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -1,15 +1,13 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use crate::commands::util::{bin_file_name, profile_adapter};
|
||||
use crate::config_manager::DebugConfig;
|
||||
use crate::commands::util::bin_file_name;
|
||||
|
||||
use crate::util::get_target_directory;
|
||||
use crate::{cli::DebugArgs, util::get_target_directory};
|
||||
use std::process::Command;
|
||||
|
||||
pub fn execute_debug_command(config: &DebugConfig) {
|
||||
let DebugConfig { cargo_args, remote } = config;
|
||||
pub fn execute_debug_command(profile: &String, args: &DebugArgs) {
|
||||
let remote = &args.remote;
|
||||
|
||||
let profile = profile_adapter(&cargo_args.profile);
|
||||
let file_path = get_target_directory()
|
||||
.join("x86_64-unknown-none")
|
||||
.join(profile)
|
||||
|
@ -19,12 +19,11 @@ use crate::arch::get_default_arch;
|
||||
/// Execute the forwarded cargo command with args containing the subcommand and its arguments.
|
||||
pub fn execute_forwarded_command(subcommand: &str, args: &Vec<String>) -> ! {
|
||||
let mut cargo = util::cargo();
|
||||
cargo
|
||||
.arg(subcommand)
|
||||
.args(util::COMMON_CARGO_ARGS)
|
||||
.arg("--target")
|
||||
.arg(get_default_arch().triple())
|
||||
.args(args);
|
||||
cargo.arg(subcommand).args(util::COMMON_CARGO_ARGS);
|
||||
if !args.contains(&"--target".to_owned()) {
|
||||
cargo.arg("--target").arg(get_default_arch().triple());
|
||||
}
|
||||
cargo.args(args);
|
||||
let status = cargo.status().expect("Failed to execute cargo");
|
||||
std::process::exit(status.code().unwrap_or(1));
|
||||
}
|
||||
|
@ -1,18 +1,25 @@
|
||||
[project]
|
||||
type = "kernel"
|
||||
project_type = "kernel"
|
||||
|
||||
[run]
|
||||
bootloader = "grub"
|
||||
ovmf = "/usr/share/OVMF"
|
||||
qemu_args = [
|
||||
"-machine q35,kernel-irqchip=split",
|
||||
"-cpu Icelake-Server,+x2apic",
|
||||
"--no-reboot",
|
||||
"-m 2G",
|
||||
"-nographic",
|
||||
"-serial chardev:mux",
|
||||
"-monitor chardev:mux",
|
||||
"-chardev stdio,id=mux,mux=on,signal=off",
|
||||
"-display none",
|
||||
"-device isa-debug-exit,iobase=0xf4,iosize=0x04",
|
||||
vars = [
|
||||
["OVMF_PATH", "/usr/share/OVMF"],
|
||||
]
|
||||
|
||||
[boot]
|
||||
method = "grub-rescue-iso"
|
||||
|
||||
[qemu]
|
||||
args = """\
|
||||
-machine q35,kernel-irqchip=split \
|
||||
-cpu Icelake-Server,+x2apic \
|
||||
--no-reboot \
|
||||
-m 2G \
|
||||
-smp 1 \
|
||||
-nographic \
|
||||
-serial chardev:mux \
|
||||
-monitor chardev:mux \
|
||||
-chardev stdio,id=mux,mux=on,signal=off \
|
||||
-display none \
|
||||
-device isa-debug-exit,iobase=0xf4,iosize=0x04 \
|
||||
-drive if=pflash,format=raw,unit=0,readonly=on,file=$OVMF_PATH/OVMF_CODE.fd \
|
||||
-drive if=pflash,format=raw,unit=1,file=$OVMF_PATH/OVMF_VARS.fd \
|
||||
"""
|
@ -1,17 +1,19 @@
|
||||
[project]
|
||||
type = "library"
|
||||
project_type = "lib"
|
||||
|
||||
[test]
|
||||
bootloader = "qemu"
|
||||
qemu_args = [
|
||||
"-machine q35,kernel-irqchip=split",
|
||||
"-cpu Icelake-Server,+x2apic",
|
||||
"--no-reboot",
|
||||
"-m 2G",
|
||||
"-nographic",
|
||||
"-serial chardev:mux",
|
||||
"-monitor chardev:mux",
|
||||
"-chardev stdio,id=mux,mux=on,signal=off",
|
||||
"-display none",
|
||||
"-device isa-debug-exit,iobase=0xf4,iosize=0x04",
|
||||
]
|
||||
[boot]
|
||||
method = "qemu-direct"
|
||||
|
||||
[qemu]
|
||||
args = """\
|
||||
-machine q35,kernel-irqchip=split \
|
||||
-cpu Icelake-Server,+x2apic \
|
||||
--no-reboot \
|
||||
-m 2G \
|
||||
-smp 1 \
|
||||
-nographic \
|
||||
-serial chardev:mux \
|
||||
-monitor chardev:mux \
|
||||
-chardev stdio,id=mux,mux=on,signal=off \
|
||||
-display none \
|
||||
-device isa-debug-exit,iobase=0xf4,iosize=0x04 \
|
||||
"""
|
@ -4,7 +4,7 @@ use std::{fs, path::PathBuf, process, str::FromStr};
|
||||
|
||||
use crate::{
|
||||
cli::NewArgs,
|
||||
config_manager::manifest::ProjectType,
|
||||
config::manifest::ProjectType,
|
||||
error::Errno,
|
||||
error_msg,
|
||||
util::{aster_crate_dep, cargo_new_lib, get_cargo_metadata},
|
||||
|
@ -1,19 +1,14 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
time::{Duration, SystemTime},
|
||||
};
|
||||
|
||||
use super::{build::create_base_and_build, util::DEFAULT_TARGET_RELPATH};
|
||||
use super::{build::create_base_and_cached_build, util::DEFAULT_TARGET_RELPATH};
|
||||
use crate::{
|
||||
bundle::Bundle,
|
||||
config_manager::{BuildConfig, RunConfig},
|
||||
util::{get_cargo_metadata, get_current_crate_info, get_target_directory},
|
||||
cli::GdbServerArgs,
|
||||
config::{scheme::ActionChoice, Config},
|
||||
util::{get_current_crate_info, get_target_directory},
|
||||
};
|
||||
|
||||
pub fn execute_run_command(config: &RunConfig) {
|
||||
if config.gdb_server_args.is_gdb_enabled {
|
||||
pub fn execute_run_command(config: &Config, gdb_server_args: &GdbServerArgs) {
|
||||
if gdb_server_args.is_gdb_enabled {
|
||||
use std::env;
|
||||
env::set_var(
|
||||
"RUSTFLAGS",
|
||||
@ -21,111 +16,48 @@ pub fn execute_run_command(config: &RunConfig) {
|
||||
);
|
||||
}
|
||||
|
||||
let ws_target_directory = get_target_directory();
|
||||
let osdk_target_directory = ws_target_directory.join(DEFAULT_TARGET_RELPATH);
|
||||
let cargo_target_directory = get_target_directory();
|
||||
let osdk_output_directory = cargo_target_directory.join(DEFAULT_TARGET_RELPATH);
|
||||
let target_name = get_current_crate_info().name;
|
||||
let default_bundle_directory = osdk_target_directory.join(target_name);
|
||||
let existing_bundle = Bundle::load(&default_bundle_directory);
|
||||
|
||||
let config = RunConfig {
|
||||
settings: {
|
||||
if config.gdb_server_args.is_gdb_enabled {
|
||||
let qemu_gdb_args: Vec<_> = {
|
||||
let gdb_stub_addr = config.gdb_server_args.gdb_server_addr.as_str();
|
||||
match gdb::stub_type_of(gdb_stub_addr) {
|
||||
gdb::StubAddrType::Unix => {
|
||||
let chardev = format!(
|
||||
"-chardev socket,path={},server=on,wait=off,id=gdb0",
|
||||
gdb_stub_addr
|
||||
);
|
||||
let stub = "-gdb chardev:gdb0".to_owned();
|
||||
vec![chardev, stub, "-S".into()]
|
||||
}
|
||||
gdb::StubAddrType::Tcp => {
|
||||
vec![
|
||||
format!(
|
||||
"-gdb tcp:{}",
|
||||
gdb::tcp_addr_util::format_tcp_addr(gdb_stub_addr)
|
||||
),
|
||||
"-S".into(),
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let qemu_gdb_args: Vec<_> = qemu_gdb_args
|
||||
.into_iter()
|
||||
.filter(|arg| !config.settings.qemu_args.iter().any(|x| x == arg))
|
||||
.map(|x| x.to_string())
|
||||
.collect();
|
||||
let mut settings = config.settings.clone();
|
||||
settings.qemu_args.extend(qemu_gdb_args);
|
||||
settings
|
||||
} else {
|
||||
config.settings.clone()
|
||||
}
|
||||
},
|
||||
..config.clone()
|
||||
};
|
||||
let _vsc_launch_file = config.gdb_server_args.vsc_launch_file.then(|| {
|
||||
vsc::check_gdb_config(&config.gdb_server_args);
|
||||
let profile = super::util::profile_adapter(&config.cargo_args.profile);
|
||||
vsc::VscLaunchConfig::new(profile, &config.gdb_server_args.gdb_server_addr)
|
||||
});
|
||||
|
||||
// If the source is not since modified and the last build is recent, we can reuse the existing bundle.
|
||||
if let Some(existing_bundle) = existing_bundle {
|
||||
if existing_bundle.can_run_with_config(&config) {
|
||||
if let Ok(built_since) =
|
||||
SystemTime::now().duration_since(existing_bundle.last_modified_time())
|
||||
{
|
||||
if built_since < Duration::from_secs(600) {
|
||||
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()
|
||||
{
|
||||
existing_bundle.run(&config);
|
||||
return;
|
||||
}
|
||||
let mut config = config.clone();
|
||||
if gdb_server_args.is_gdb_enabled {
|
||||
let qemu_gdb_args = {
|
||||
let gdb_stub_addr = gdb_server_args.gdb_server_addr.as_str();
|
||||
match gdb::stub_type_of(gdb_stub_addr) {
|
||||
gdb::StubAddrType::Unix => {
|
||||
format!(
|
||||
" -chardev socket,path={},server=on,wait=off,id=gdb0 -gdb chardev:gdb0 -S",
|
||||
gdb_stub_addr
|
||||
)
|
||||
}
|
||||
gdb::StubAddrType::Tcp => {
|
||||
format!(
|
||||
" -gdb tcp:{} -S",
|
||||
gdb::tcp_addr_util::format_tcp_addr(gdb_stub_addr)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
config.run.qemu.args += &qemu_gdb_args;
|
||||
}
|
||||
let _vsc_launch_file = gdb_server_args.vsc_launch_file.then(|| {
|
||||
vsc::check_gdb_config(gdb_server_args);
|
||||
let profile = super::util::profile_adapter(&config.build.profile);
|
||||
vsc::VscLaunchConfig::new(profile, &gdb_server_args.gdb_server_addr)
|
||||
});
|
||||
|
||||
let required_build_config = BuildConfig {
|
||||
arch: config.arch,
|
||||
settings: config.settings.clone(),
|
||||
cargo_args: config.cargo_args.clone(),
|
||||
};
|
||||
|
||||
let bundle = create_base_and_build(
|
||||
let default_bundle_directory = osdk_output_directory.join(target_name);
|
||||
let bundle = create_base_and_cached_build(
|
||||
default_bundle_directory,
|
||||
&osdk_target_directory,
|
||||
&ws_target_directory,
|
||||
&required_build_config,
|
||||
&osdk_output_directory,
|
||||
&cargo_target_directory,
|
||||
&config,
|
||||
ActionChoice::Run,
|
||||
&[],
|
||||
);
|
||||
bundle.run(&config);
|
||||
}
|
||||
|
||||
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
|
||||
bundle.run(&config, ActionChoice::Run);
|
||||
}
|
||||
|
||||
mod gdb {
|
||||
|
@ -2,38 +2,38 @@
|
||||
|
||||
use std::fs;
|
||||
|
||||
use super::{build::do_build, util::DEFAULT_TARGET_RELPATH};
|
||||
use super::{build::do_cached_build, util::DEFAULT_TARGET_RELPATH};
|
||||
use crate::{
|
||||
base_crate::new_base_crate,
|
||||
cli::GdbServerArgs,
|
||||
config_manager::{BuildConfig, RunConfig, TestConfig},
|
||||
cli::TestArgs,
|
||||
config::{scheme::ActionChoice, Config},
|
||||
util::{get_cargo_metadata, get_current_crate_info, get_target_directory},
|
||||
};
|
||||
|
||||
pub fn execute_test_command(config: &TestConfig) {
|
||||
pub fn execute_test_command(config: &Config, args: &TestArgs) {
|
||||
let crates = get_workspace_default_members();
|
||||
for crate_path in crates {
|
||||
std::env::set_current_dir(crate_path).unwrap();
|
||||
test_current_crate(config);
|
||||
test_current_crate(config, args);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test_current_crate(config: &TestConfig) {
|
||||
pub fn test_current_crate(config: &Config, args: &TestArgs) {
|
||||
let current_crate = get_current_crate_info();
|
||||
let ws_target_directory = get_target_directory();
|
||||
let osdk_target_directory = ws_target_directory.join(DEFAULT_TARGET_RELPATH);
|
||||
let target_crate_dir = osdk_target_directory.join("base");
|
||||
let cargo_target_directory = get_target_directory();
|
||||
let osdk_output_directory = cargo_target_directory.join(DEFAULT_TARGET_RELPATH);
|
||||
let target_crate_dir = osdk_output_directory.join("base");
|
||||
new_base_crate(&target_crate_dir, ¤t_crate.name, ¤t_crate.path);
|
||||
|
||||
let main_rs_path = target_crate_dir.join("src").join("main.rs");
|
||||
|
||||
let ktest_test_whitelist = match &config.test_name {
|
||||
let ktest_test_whitelist = match &args.test_name {
|
||||
Some(name) => format!(r#"Some(&["{}"])"#, name),
|
||||
None => r#"None"#.to_string(),
|
||||
};
|
||||
|
||||
let mut ktest_crate_whitelist = vec![current_crate.name];
|
||||
if let Some(name) = &config.test_name {
|
||||
if let Some(name) = &args.test_name {
|
||||
ktest_crate_whitelist.push(name.clone());
|
||||
}
|
||||
|
||||
@ -54,32 +54,21 @@ pub static KTEST_CRATE_WHITELIST: Option<&[&str]> = Some(&{:#?});
|
||||
|
||||
// Build the kernel with the given base crate
|
||||
let target_name = get_current_crate_info().name;
|
||||
let default_bundle_directory = osdk_target_directory.join(target_name);
|
||||
let required_build_config = BuildConfig {
|
||||
arch: config.arch,
|
||||
settings: config.settings.clone(),
|
||||
cargo_args: config.cargo_args.clone(),
|
||||
};
|
||||
let default_bundle_directory = osdk_output_directory.join(target_name);
|
||||
let original_dir = std::env::current_dir().unwrap();
|
||||
std::env::set_current_dir(&target_crate_dir).unwrap();
|
||||
let bundle = do_build(
|
||||
let bundle = do_cached_build(
|
||||
default_bundle_directory,
|
||||
&osdk_target_directory,
|
||||
&ws_target_directory,
|
||||
&required_build_config,
|
||||
&osdk_output_directory,
|
||||
&cargo_target_directory,
|
||||
config,
|
||||
ActionChoice::Test,
|
||||
&["--cfg ktest"],
|
||||
);
|
||||
std::env::remove_var("RUSTFLAGS");
|
||||
std::env::set_current_dir(original_dir).unwrap();
|
||||
|
||||
let required_run_config = RunConfig {
|
||||
arch: config.arch,
|
||||
settings: required_build_config.settings.clone(),
|
||||
cargo_args: required_build_config.cargo_args.clone(),
|
||||
gdb_server_args: GdbServerArgs::default(),
|
||||
};
|
||||
|
||||
bundle.run(&required_run_config);
|
||||
bundle.run(config, ActionChoice::Test);
|
||||
}
|
||||
|
||||
fn get_workspace_default_members() -> Vec<String> {
|
||||
|
Reference in New Issue
Block a user