mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-15 08:16:47 +00:00
Supporting running OSDK commands in workspace root
This commit is contained in:
parent
c7b7e2473f
commit
aaf101a53e
4
Makefile
4
Makefile
@ -122,7 +122,7 @@ initramfs:
|
||||
|
||||
.PHONY: build
|
||||
build: initramfs $(CARGO_OSDK)
|
||||
@cd kernel && cargo osdk build $(CARGO_OSDK_ARGS)
|
||||
cargo osdk build $(CARGO_OSDK_ARGS)
|
||||
|
||||
.PHONY: tools
|
||||
tools:
|
||||
@ -130,7 +130,7 @@ tools:
|
||||
|
||||
.PHONY: run
|
||||
run: build
|
||||
@cd kernel && cargo osdk run $(CARGO_OSDK_ARGS)
|
||||
@cargo osdk run $(CARGO_OSDK_ARGS)
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
|
@ -49,6 +49,9 @@ myworkspace/
|
||||
└── lib.rs
|
||||
```
|
||||
|
||||
At present, OSDK mandates that there must be only one kernel project
|
||||
within a workspace.
|
||||
|
||||
In addition to the two projects,
|
||||
OSDK will also generate `OSDK.toml` and `rust-toolchain.toml`
|
||||
at the root of the workspace.
|
||||
@ -78,8 +81,8 @@ This function will call the function from `mymodule`:
|
||||
```rust
|
||||
#[aster_main]
|
||||
fn kernel_main() {
|
||||
let avail_mem_as_mb = mymodule::available_memory() / 1_000_000;
|
||||
println!("The available memory is {} MB", avail_mem_as_mb);
|
||||
let avail_mem_as_mb = mymodule::available_memory() / 1_000_000;
|
||||
println!("The available memory is {} MB", avail_mem_as_mb);
|
||||
}
|
||||
```
|
||||
|
||||
|
6
osdk/Cargo.lock
generated
6
osdk/Cargo.lock
generated
@ -137,10 +137,12 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"linux-bzimage-builder",
|
||||
"log",
|
||||
"quote",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"syn",
|
||||
"toml",
|
||||
"which",
|
||||
]
|
||||
@ -534,9 +536,9 @@ checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.50"
|
||||
version = "2.0.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb"
|
||||
checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -15,10 +15,12 @@ indexmap = "2.2.1"
|
||||
lazy_static = "1.4.0"
|
||||
linux-bzimage-builder = { path = "../framework/libs/linux-bzimage/builder" }
|
||||
log = "0.4.20"
|
||||
quote = "1.0.35"
|
||||
regex = "1.10.3"
|
||||
serde = { version = "1.0.195", features = ["derive"] }
|
||||
serde_json = "1.0.111"
|
||||
sha2 = "0.10.8"
|
||||
syn = { version = "2.0.52", features = ["extra-traits", "full", "parsing", "printing"] }
|
||||
toml = { version = "0.8.8", features = ["preserve_order"] }
|
||||
which = "6.0.0"
|
||||
|
||||
|
@ -1,9 +1,6 @@
|
||||
#![no_std]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate ktest;
|
||||
|
||||
use aster_frame::prelude::*;
|
||||
|
||||
#[aster_main]
|
||||
|
@ -1,12 +1,6 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use std::{
|
||||
ffi::OsStr,
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
process,
|
||||
str::FromStr,
|
||||
};
|
||||
use std::{fs, path::PathBuf, process, str::FromStr};
|
||||
|
||||
use crate::{
|
||||
cli::NewArgs,
|
||||
@ -20,6 +14,7 @@ pub fn execute_new_command(args: &NewArgs) {
|
||||
let cargo_metadata = get_cargo_metadata(Some(&args.crate_name), None::<&[&str]>).unwrap();
|
||||
add_manifest_dependencies(&cargo_metadata, &args.crate_name);
|
||||
create_osdk_manifest(&cargo_metadata);
|
||||
exclude_osdk_base(&cargo_metadata);
|
||||
if args.kernel {
|
||||
write_kernel_template(&cargo_metadata, &args.crate_name);
|
||||
} else {
|
||||
@ -50,15 +45,48 @@ fn add_manifest_dependencies(cargo_metadata: &serde_json::Value, crate_name: &st
|
||||
dependencies.as_table_mut().unwrap().extend(ktest_dep);
|
||||
|
||||
// If we created a workspace by `osdk new`, we should exclude the `base` crate from the workspace.
|
||||
if get_cargo_metadata::<&Path, &OsStr>(None, None).is_none() {
|
||||
let exclude = toml::Table::from_str(r#"exclude = ["target/osdk/base"]"#).unwrap();
|
||||
manifest.insert("workspace".to_string(), toml::Value::Table(exclude));
|
||||
}
|
||||
// let exclude = toml::Table::from_str(r#"exclude = ["target/osdk/base"]"#).unwrap();
|
||||
// manifest.insert("workspace".to_string(), toml::Value::Table(exclude));
|
||||
|
||||
let content = toml::to_string(&manifest).unwrap();
|
||||
fs::write(mainfest_path, content).unwrap();
|
||||
}
|
||||
|
||||
// Add `target/osdk/base` to `exclude` array of the workspace manifest
|
||||
fn exclude_osdk_base(metadata: &serde_json::Value) {
|
||||
let osdk_base_path = "target/osdk/base";
|
||||
|
||||
let workspace_manifest_path = {
|
||||
let workspace_root = metadata.get("workspace_root").unwrap().as_str().unwrap();
|
||||
format!("{}/Cargo.toml", workspace_root)
|
||||
};
|
||||
|
||||
let content = fs::read_to_string(&workspace_manifest_path).unwrap();
|
||||
let mut manifest_toml: toml::Table = toml::from_str(&content).unwrap();
|
||||
|
||||
if let Some(workspace) = manifest_toml.get_mut("workspace") {
|
||||
let workspace = workspace.as_table_mut().unwrap();
|
||||
|
||||
if let Some(exclude) = workspace.get_mut("exclude") {
|
||||
let exclude = exclude.as_array_mut().unwrap();
|
||||
if exclude.contains(&toml::Value::String(osdk_base_path.to_string())) {
|
||||
return;
|
||||
}
|
||||
|
||||
exclude.push(toml::Value::String(osdk_base_path.to_string()));
|
||||
} else {
|
||||
let exclude = vec![toml::Value::String(osdk_base_path.to_string())];
|
||||
workspace.insert("exclude".to_string(), toml::Value::Array(exclude));
|
||||
}
|
||||
} else {
|
||||
let exclude = toml::Table::from_str(r#"exclude = ["target/osdk/base"]"#).unwrap();
|
||||
manifest_toml.insert("workspace".to_string(), toml::Value::Table(exclude));
|
||||
}
|
||||
|
||||
let content = toml::to_string(&manifest_toml).unwrap();
|
||||
fs::write(workspace_manifest_path, content).unwrap();
|
||||
}
|
||||
|
||||
fn create_osdk_manifest(cargo_metadata: &serde_json::Value) {
|
||||
let osdk_manifest_path = {
|
||||
let workspace_root = get_workspace_root(cargo_metadata);
|
||||
@ -78,6 +106,7 @@ fn create_osdk_manifest(cargo_metadata: &serde_json::Value) {
|
||||
r#"
|
||||
[boot]
|
||||
ovmf = "/usr/share/OVMF"
|
||||
protocol = "multiboot"
|
||||
[qemu]
|
||||
machine = "q35"
|
||||
args = [
|
||||
|
@ -6,10 +6,18 @@ use super::{build::do_build, util::DEFAULT_TARGET_RELPATH};
|
||||
use crate::{
|
||||
base_crate::new_base_crate,
|
||||
config_manager::{BuildConfig, RunConfig, TestConfig},
|
||||
util::{get_current_crate_info, get_target_directory},
|
||||
util::{get_cargo_metadata, get_current_crate_info, get_target_directory},
|
||||
};
|
||||
|
||||
pub fn execute_test_command(config: &TestConfig) {
|
||||
let crates = get_workspace_default_members();
|
||||
for crate_path in crates {
|
||||
std::env::set_current_dir(crate_path).unwrap();
|
||||
test_current_crate(config);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test_current_crate(config: &TestConfig) {
|
||||
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);
|
||||
@ -69,3 +77,23 @@ pub static KTEST_CRATE_WHITELIST: Option<&[&str]> = Some(&{:#?});
|
||||
|
||||
bundle.run(&required_run_config);
|
||||
}
|
||||
|
||||
fn get_workspace_default_members() -> Vec<String> {
|
||||
let metadata = get_cargo_metadata(None::<&str>, None::<&[&str]>).unwrap();
|
||||
let default_members = metadata
|
||||
.get("workspace_default_members")
|
||||
.unwrap()
|
||||
.as_array()
|
||||
.unwrap();
|
||||
default_members
|
||||
.iter()
|
||||
.map(|value| {
|
||||
// The default member is in the form of "<crate_name> <crate_version> (path+file://<crate_path>)"
|
||||
let default_member = value.as_str().unwrap();
|
||||
let path = default_member.split(" ").nth(2).unwrap();
|
||||
path.trim_start_matches("(path+file://")
|
||||
.trim_end_matches(')')
|
||||
.to_string()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
@ -2,16 +2,19 @@
|
||||
|
||||
use std::{
|
||||
ffi::OsStr,
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
process::Command,
|
||||
};
|
||||
|
||||
use crate::{error::Errno, error_msg};
|
||||
|
||||
use quote::ToTokens;
|
||||
|
||||
/// FIXME: We should publish the asterinas crates to a public registry
|
||||
/// and use the published version in the generated Cargo.toml.
|
||||
pub const ASTER_GIT_LINK: &str = "https://github.com/asterinas/asterinas";
|
||||
pub const ASTER_GIT_REV: &str = "7d0ea99";
|
||||
pub const ASTER_GIT_REV: &str = "437ab80";
|
||||
pub fn aster_crate_dep(crate_name: &str) -> String {
|
||||
format!(
|
||||
"{} = {{ git = \"{}\", rev = \"{}\" }}",
|
||||
@ -78,16 +81,90 @@ pub struct CrateInfo {
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
/// Retrieve the default member in the workspace.
|
||||
///
|
||||
/// If there is only one kernel crate, return that crate;
|
||||
/// If there are multiple kernel crates or no kernel crates in the workspace,
|
||||
/// this function will exit with an error.
|
||||
///
|
||||
/// A crate is considered a kernel crate if it utilizes the `aster_main` macro.
|
||||
fn get_default_member(metadata: &serde_json::Value) -> &str {
|
||||
let default_members = metadata
|
||||
.get("workspace_default_members")
|
||||
.unwrap()
|
||||
.as_array()
|
||||
.unwrap();
|
||||
|
||||
if default_members.len() == 1 {
|
||||
return default_members[0].as_str().unwrap();
|
||||
}
|
||||
|
||||
let packages: Vec<_> = {
|
||||
let packages = metadata.get("packages").unwrap().as_array().unwrap();
|
||||
|
||||
packages
|
||||
.iter()
|
||||
.filter(|package| {
|
||||
let id = package.get("id").unwrap();
|
||||
if !default_members.contains(&id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let src_path = {
|
||||
let targets = package.get("targets").unwrap().as_array().unwrap();
|
||||
if targets.len() != 1 {
|
||||
return false;
|
||||
}
|
||||
targets[0].get("src_path").unwrap().as_str().unwrap()
|
||||
};
|
||||
|
||||
let file = {
|
||||
let content = fs::read_to_string(src_path).unwrap();
|
||||
syn::parse_file(&content).unwrap()
|
||||
};
|
||||
|
||||
contains_aster_main_macro(&file)
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
|
||||
if packages.len() == 0 {
|
||||
error_msg!("OSDK requires there's at least one kernel package. Please navigate to the kernel package directory or the workspace root and run the command.");
|
||||
std::process::exit(Errno::BuildCrate as _);
|
||||
}
|
||||
|
||||
if packages.len() >= 2 {
|
||||
error_msg!("OSDK requires there's at most one kernel package in the workspace. Please navigate to the kernel package directory and run the command.");
|
||||
std::process::exit(Errno::BuildCrate as _);
|
||||
}
|
||||
|
||||
packages[0].get("id").unwrap().as_str().unwrap()
|
||||
}
|
||||
|
||||
fn contains_aster_main_macro(file: &syn::File) -> bool {
|
||||
for item in &file.items {
|
||||
let syn::Item::Fn(item_fn) = item else {
|
||||
continue;
|
||||
};
|
||||
|
||||
for attr in &item_fn.attrs {
|
||||
let attr = format!("{}", attr.to_token_stream());
|
||||
if attr.as_str() == "# [aster_main]" {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn get_current_crate_info() -> CrateInfo {
|
||||
let metadata = get_cargo_metadata(None::<&str>, None::<&[&str]>).unwrap();
|
||||
let default_members = metadata.get("workspace_default_members").unwrap();
|
||||
assert_eq!(default_members.as_array().unwrap().len(), 1);
|
||||
|
||||
let default_member = get_default_member(&metadata);
|
||||
|
||||
// The default member string here is in the form of "<crate_name> <crate_version> (path+file://<crate_path>)"
|
||||
let default_member = default_members[0]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.split(' ')
|
||||
.collect::<Vec<&str>>();
|
||||
let default_member = default_member.split(' ').collect::<Vec<&str>>();
|
||||
let name = default_member[0].to_string();
|
||||
let version = default_member[1].to_string();
|
||||
let path = default_member[2]
|
||||
|
Loading…
x
Reference in New Issue
Block a user