diff --git a/Makefile b/Makefile index f709ce38..97a85814 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -SUBDIRS = kernel user tools +SUBDIRS = kernel user tools build-scripts # ifndef $(EMULATOR) ifeq ($(EMULATOR), ) @@ -156,6 +156,7 @@ fmt: @echo "格式化代码" FMT_CHECK=$(FMT_CHECK) $(MAKE) fmt -C kernel FMT_CHECK=$(FMT_CHECK) $(MAKE) fmt -C user + FMT_CHECK=$(FMT_CHECK) $(MAKE) fmt -C build-scripts log-monitor: @echo "启动日志监控" diff --git a/build-scripts/Cargo.toml b/build-scripts/Cargo.toml new file mode 100644 index 00000000..94a1493f --- /dev/null +++ b/build-scripts/Cargo.toml @@ -0,0 +1,5 @@ +[workspace] +members = [ + "kernel_build", +] +resolver = "2" \ No newline at end of file diff --git a/build-scripts/Makefile b/build-scripts/Makefile new file mode 100644 index 00000000..ba60f4b5 --- /dev/null +++ b/build-scripts/Makefile @@ -0,0 +1,6 @@ +.PHONY: fmt +fmt: + cargo fmt --all $(FMT_CHECK) + +clean: + @cargo clean diff --git a/build-scripts/kernel_build/Cargo.toml b/build-scripts/kernel_build/Cargo.toml new file mode 100644 index 00000000..cc9a0aeb --- /dev/null +++ b/build-scripts/kernel_build/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "kernel_build" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +bindgen = "0.61.0" +lazy_static = "1.4.0" +cc = { version = "1.0.83", features = ["parallel"] } \ No newline at end of file diff --git a/build-scripts/kernel_build/src/bindgen/arch/mod.rs b/build-scripts/kernel_build/src/bindgen/arch/mod.rs new file mode 100644 index 00000000..0b84a1f6 --- /dev/null +++ b/build-scripts/kernel_build/src/bindgen/arch/mod.rs @@ -0,0 +1,18 @@ +use crate::utils::cargo_handler::{CargoHandler, TargetArch}; + +use self::x86_64::X86_64BindgenArch; + +pub mod x86_64; + +pub(super) trait BindgenArch { + fn generate_bindings(&self, builder: bindgen::Builder) -> bindgen::Builder; +} + +/// 获取当前的bindgen架构; +pub(super) fn current_bindgenarch() -> &'static dyn BindgenArch { + let arch = CargoHandler::target_arch(); + match arch { + TargetArch::X86_64 => &X86_64BindgenArch, + _ => panic!("Unsupported arch: {:?}", arch), + } +} diff --git a/build-scripts/kernel_build/src/bindgen/arch/x86_64.rs b/build-scripts/kernel_build/src/bindgen/arch/x86_64.rs new file mode 100644 index 00000000..b6daa47f --- /dev/null +++ b/build-scripts/kernel_build/src/bindgen/arch/x86_64.rs @@ -0,0 +1,13 @@ +use super::BindgenArch; + + + +pub struct X86_64BindgenArch; + +impl BindgenArch for X86_64BindgenArch { + fn generate_bindings(&self, builder: bindgen::Builder) -> bindgen::Builder { + builder + .clang_arg("-I./src/arch/x86_64/include") + .clang_arg("--target=x86_64-none-none") + } +} diff --git a/build-scripts/kernel_build/src/bindgen/mod.rs b/build-scripts/kernel_build/src/bindgen/mod.rs new file mode 100644 index 00000000..8a5014ae --- /dev/null +++ b/build-scripts/kernel_build/src/bindgen/mod.rs @@ -0,0 +1,50 @@ +use std::{path::PathBuf, str::FromStr}; + +use crate::{bindgen::arch::current_bindgenarch, utils::cargo_handler::CargoHandler}; + +mod arch; + +/// 生成 C->Rust bindings +pub fn generate_bindings() { + let wrapper_h = PathBuf::from_str("src/include/bindings/wrapper.h") + .expect("Failed to parse 'wrapper.h' path"); + CargoHandler::emit_rerun_if_files_changed(&[wrapper_h.clone()]); + + let out_path = PathBuf::from(String::from("src/include/bindings/")); + + // The bindgen::Builder is the main entry point + // to bindgen, and lets you build up options for + // the resulting bindings. + + let builder = bindgen::Builder::default() + .clang_arg("-I./src") + .clang_arg("-I./src/include") + // The input header we would like to generate + // bindings for. + .header(wrapper_h.to_str().unwrap()) + .blocklist_file("src/include/bindings/bindings.h") + .clang_arg("-v") + // 使用core,并将c语言的类型改为core::ffi,而不是使用std库。 + .use_core() + .ctypes_prefix("::core::ffi") + .generate_inline_functions(true) + .raw_line("#![allow(dead_code)]") + .raw_line("#![allow(non_upper_case_globals)]") + .raw_line("#![allow(non_camel_case_types)]") + // Tell cargo to invalidate the built crate whenever any of the + // included header files changed. + .parse_callbacks(Box::new(bindgen::CargoCallbacks)); + + // 处理架构相关的绑定 + let builder = current_bindgenarch().generate_bindings(builder); + + // Finish the builder and generate the bindings. + let bindings = builder + .generate() + // Unwrap the Result and panic on failure. + .expect("Unable to generate bindings"); + + bindings + .write_to_file(out_path.join("bindings.rs")) + .expect("Couldn't write bindings!"); +} diff --git a/build-scripts/kernel_build/src/cfiles/arch/mod.rs b/build-scripts/kernel_build/src/cfiles/arch/mod.rs new file mode 100644 index 00000000..4aad8270 --- /dev/null +++ b/build-scripts/kernel_build/src/cfiles/arch/mod.rs @@ -0,0 +1,27 @@ +use std::path::PathBuf; + +use cc::Build; + +use crate::utils::cargo_handler::{CargoHandler, TargetArch}; + +use self::x86_64::X86_64CFilesArch; + +pub mod x86_64; + +pub(super) trait CFilesArch { + /// 设置架构相关的宏定义 + fn setup_defines(&self, c: &mut Build); + /// 设置架构相关的全局包含目录 + fn setup_global_include_dir(&self, c: &mut Build); + /// 设置需要编译的架构相关的文件 + fn setup_files(&self, c: &mut Build, files: &mut Vec); +} + +/// 获取当前的架构; +pub(super) fn current_cfiles_arch() -> &'static dyn CFilesArch { + let arch = CargoHandler::target_arch(); + match arch { + TargetArch::X86_64 => &X86_64CFilesArch, + _ => panic!("Unsupported arch: {:?}", arch), + } +} diff --git a/build-scripts/kernel_build/src/cfiles/arch/x86_64.rs b/build-scripts/kernel_build/src/cfiles/arch/x86_64.rs new file mode 100644 index 00000000..bb301a42 --- /dev/null +++ b/build-scripts/kernel_build/src/cfiles/arch/x86_64.rs @@ -0,0 +1,29 @@ +use std::path::PathBuf; + +use cc::Build; + +use crate::utils::FileUtils; + +use super::CFilesArch; + +pub(super) struct X86_64CFilesArch; + +impl CFilesArch for X86_64CFilesArch { + fn setup_defines(&self, c: &mut cc::Build) { + c.define("__x86_64__", None); + } + + fn setup_global_include_dir(&self, c: &mut cc::Build) { + c.include("src/arch/x86_64/include"); + } + + fn setup_files(&self, _c: &mut Build, files: &mut Vec) { + files.push(PathBuf::from("src/arch/x86_64/driver/hpet.c")); + // 获取`kernel/src/arch/x86_64/driver/apic`下的所有C文件 + files.append(&mut FileUtils::list_all_files( + &PathBuf::from("src/arch/x86_64/driver/apic"), + Some("c"), + true, + )); + } +} diff --git a/build-scripts/kernel_build/src/cfiles/mod.rs b/build-scripts/kernel_build/src/cfiles/mod.rs new file mode 100644 index 00000000..7dae54f3 --- /dev/null +++ b/build-scripts/kernel_build/src/cfiles/mod.rs @@ -0,0 +1,68 @@ +use std::path::PathBuf; + +use cc::Build; + +use crate::utils::cargo_handler::CargoHandler; + +use self::arch::current_cfiles_arch; + +mod arch; + +/// 构建项目的c文件 +pub struct CFilesBuilder; + +impl CFilesBuilder { + pub fn build() { + let mut c = cc::Build::new(); + Self::setup_global_flags(&mut c); + Self::setup_defines(&mut c); + Self::setup_global_include_dir(&mut c); + Self::setup_files(&mut c); + c.compile("dragonos_kernel_cfiles"); + } + + fn setup_global_flags(c: &mut Build) { + c.flag("-mcmodel=large") + .flag("-fno-builtin") + .flag("-nostdlib") + .flag("-fno-stack-protector") + .flag("-fno-pie") + .flag("-Wno-expansion-to-defined") + .flag("-Wno-unused-parameter") + .flag("-m64") + .flag("-O1"); + } + + fn setup_defines(c: &mut Build) { + if let Ok(k) = std::env::var("EMULATOR") { + c.define("EMULATOR", Some(k.as_str())); + } else { + c.define("EMULATOR", "__NO_EMULATION__"); + } + + current_cfiles_arch().setup_defines(c); + } + + fn setup_global_include_dir(c: &mut Build) { + c.include("src/include"); + c.include("src"); + c.include("."); + + current_cfiles_arch().setup_global_include_dir(c); + } + + /// 设置需要编译的文件 + fn setup_files(c: &mut Build) { + let mut files: Vec = Vec::new(); + + current_cfiles_arch().setup_files(c, &mut files); + + Self::set_rerun_if_files_changed(&files); + c.files(files.as_slice()); + } + + /// 设置Cargo对文件更改的监听 + fn set_rerun_if_files_changed(files: &Vec) { + CargoHandler::emit_rerun_if_files_changed(files.as_slice()); + } +} diff --git a/build-scripts/kernel_build/src/lib.rs b/build-scripts/kernel_build/src/lib.rs new file mode 100644 index 00000000..8a5bd922 --- /dev/null +++ b/build-scripts/kernel_build/src/lib.rs @@ -0,0 +1,15 @@ +#[macro_use] +extern crate lazy_static; +extern crate cc; + +mod bindgen; +mod cfiles; +mod utils; + +/// 运行构建 +pub fn run() { + println!("cargo:rustc-link-search=src"); + + crate::bindgen::generate_bindings(); + crate::cfiles::CFilesBuilder::build(); +} diff --git a/build-scripts/kernel_build/src/utils/cargo_handler.rs b/build-scripts/kernel_build/src/utils/cargo_handler.rs new file mode 100644 index 00000000..a41769e6 --- /dev/null +++ b/build-scripts/kernel_build/src/utils/cargo_handler.rs @@ -0,0 +1,78 @@ +use std::{env, path::PathBuf}; + +lazy_static! { + static ref CARGO_HANDLER_DATA: CargoHandlerData = CargoHandlerData::new(); +} + +struct CargoHandlerData { + target_arch: TargetArch, +} + +impl CargoHandlerData { + fn new() -> Self { + CargoHandlerData { + target_arch: TargetArch::new(), + } + } +} + +#[derive(Debug)] +pub struct CargoHandler; + +impl CargoHandler { + pub fn readenv(key: &str) -> Option { + if let Ok(value) = env::var(key) { + Some(value) + } else { + None + } + } + + /// 获取当前编译的目标架构 + pub fn target_arch() -> TargetArch { + CARGO_HANDLER_DATA.target_arch + } + + /// 设置Cargo对文件更改的监听 + /// + /// ## Parameters + /// + /// - `files` - The files to set rerun build + pub fn emit_rerun_if_files_changed(files: &[PathBuf]) { + for f in files { + println!("cargo:rerun-if-changed={}", f.to_str().unwrap()); + } + } +} + +/// 目标架构 +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum TargetArch { + X86_64, + Aarch64, + Riscv64, + Mips64, + Powerpc64, + S390x, + Sparc64, + Unknown, +} + +impl TargetArch { + pub fn new() -> Self { + let data = CargoHandler::readenv("CARGO_CFG_TARGET_ARCH") + .expect("CARGO_CFG_TARGET_ARCH is not set") + .to_ascii_lowercase(); + + match data.as_str() { + "x86_64" => TargetArch::X86_64, + "aarch64" => TargetArch::Aarch64, + "riscv64" => TargetArch::Riscv64, + "mips64" => TargetArch::Mips64, + "powerpc64" => TargetArch::Powerpc64, + "s390x" => TargetArch::S390x, + "sparc64" => TargetArch::Sparc64, + _ => TargetArch::Unknown, + } + } +} diff --git a/build-scripts/kernel_build/src/utils/mod.rs b/build-scripts/kernel_build/src/utils/mod.rs new file mode 100644 index 00000000..f78eaf16 --- /dev/null +++ b/build-scripts/kernel_build/src/utils/mod.rs @@ -0,0 +1,49 @@ +use std::path::PathBuf; + +pub mod cargo_handler; + +pub struct FileUtils; + +impl FileUtils { + /// 列出指定目录下的所有文件 + /// + /// ## 参数 + /// + /// - `path` - 指定的目录 + /// - `ext_name` - 文件的扩展名,如果为None,则列出所有文件 + /// - `recursive` - 是否递归列出所有文件 + pub fn list_all_files(path: &PathBuf, ext_name: Option<&str>, recursive: bool) -> Vec { + let mut queue: Vec = Vec::new(); + let mut result = Vec::new(); + queue.push(path.clone()); + + while !queue.is_empty() { + let path = queue.pop().unwrap(); + let d = std::fs::read_dir(path); + if d.is_err() { + continue; + } + let d = d.unwrap(); + + d.for_each(|ent| { + if let Ok(ent) = ent { + if let Ok(file_type) = ent.file_type() { + if file_type.is_file() { + if let Some(e) = ext_name { + if let Some(ext) = ent.path().extension() { + if ext == e { + result.push(ent.path()); + } + } + } + } else if file_type.is_dir() && recursive { + queue.push(ent.path()); + } + } + } + }); + } + + return result; + } +} diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 69f24627..25bae856 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -12,7 +12,7 @@ crate-type = ["staticlib"] [workspace] members = [ "crates/*", - "src/libs/intertrait" + "src/libs/intertrait" ] [features] @@ -50,8 +50,7 @@ kdepends = { path = "crates/kdepends" } # 构建时依赖项 [build-dependencies] -bindgen = "0.61.0" -cc = { version = "1.0.83", features = ["parallel"] } +kernel_build = { path = "../build-scripts/kernel_build" } [dependencies.lazy_static] version = "1.4.0" diff --git a/kernel/build.rs b/kernel/build.rs index d1e58aa5..47ed7763 100644 --- a/kernel/build.rs +++ b/kernel/build.rs @@ -1,178 +1,3 @@ -extern crate bindgen; -extern crate cc; -// use ::std::env; - -use std::path::PathBuf; - -use cc::Build; - fn main() { - // Tell cargo to look for shared libraries in the specified directory - println!("cargo:rustc-link-search=src"); - println!("cargo:rerun-if-changed=src/include/bindings/wrapper.h"); - - generate_bindings(); - CFilesBuilder::build(); -} - -fn generate_bindings() { - // let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); - let out_path = PathBuf::from(String::from("src/include/bindings/")); - - // The bindgen::Builder is the main entry point - // to bindgen, and lets you build up options for - // the resulting bindings. - { - let bindings = bindgen::Builder::default() - .clang_arg("-I./src") - .clang_arg("-I./src/include") - .clang_arg("-I./src/arch/x86_64/include") // todo: 当引入多种架构之后,需要修改这里,对于不同的架构编译时,include不同的路径 - // The input header we would like to generate - // bindings for. - .header("src/include/bindings/wrapper.h") - .blocklist_file("src/include/bindings/bindings.h") - .clang_arg("--target=x86_64-none-none") - .clang_arg("-v") - // 使用core,并将c语言的类型改为core::ffi,而不是使用std库。 - .use_core() - .ctypes_prefix("::core::ffi") - .generate_inline_functions(true) - .raw_line("#![allow(dead_code)]") - .raw_line("#![allow(non_upper_case_globals)]") - .raw_line("#![allow(non_camel_case_types)]") - // Tell cargo to invalidate the built crate whenever any of the - // included header files changed. - .parse_callbacks(Box::new(bindgen::CargoCallbacks)) - // Finish the builder and generate the bindings. - .generate() - // Unwrap the Result and panic on failure. - .expect("Unable to generate bindings"); - - bindings - .write_to_file(out_path.join("bindings.rs")) - .expect("Couldn't write bindings!"); - } -} - -/// 构建项目的c文件 -struct CFilesBuilder; - -impl CFilesBuilder { - fn build() { - let mut c = cc::Build::new(); - Self::setup_global_flags(&mut c); - Self::setup_defines(&mut c); - Self::setup_global_include_dir(&mut c); - Self::setup_files(&mut c); - c.compile("dragonos_kernel_cfiles"); - } - - fn setup_global_flags(c: &mut Build) { - c.flag("-mcmodel=large") - .flag("-fno-builtin") - .flag("-nostdlib") - .flag("-fno-stack-protector") - .flag("-fno-pie") - .flag("-Wno-expansion-to-defined") - .flag("-Wno-unused-parameter") - .flag("-m64") - .flag("-O1"); - } - - fn setup_defines(c: &mut Build) { - if let Ok(k) = std::env::var("EMULATOR") { - c.define("EMULATOR", Some(k.as_str())); - } else { - c.define("EMULATOR", "__NO_EMULATION__"); - } - - { - #[cfg(target_arch = "x86_64")] - c.define("__x86_64__", None); - } - } - - fn setup_global_include_dir(c: &mut Build) { - c.include("src/include"); - c.include("src"); - c.include("."); - - #[cfg(target_arch = "x86_64")] - c.include("src/arch/x86_64/include"); - } - - /// 设置需要编译的文件 - fn setup_files(c: &mut Build) { - let mut files = Vec::new(); - - #[cfg(target_arch = "x86_64")] - Self::setup_files_x86_64(&mut files); - - Self::set_rerun_if_files_changed(&files); - c.files(files.as_slice()); - } - - /// 设置x86_64架构下需要编译的C文件 - fn setup_files_x86_64(files: &mut Vec) { - files.push(PathBuf::from("src/arch/x86_64/driver/hpet.c")); - // 获取`kernel/src/arch/x86_64/driver/apic`下的所有C文件 - files.append(&mut FileUtils::list_all_files( - &PathBuf::from("src/arch/x86_64/driver/apic"), - Some("c"), - true, - )); - } - - /// 设置Cargo对文件更改的监听 - fn set_rerun_if_files_changed(files: &Vec) { - for f in files { - println!("cargo:rerun-if-changed={}", f.to_str().unwrap()); - } - } -} - -struct FileUtils; - -impl FileUtils { - /// 列出指定目录下的所有文件 - /// - /// ## 参数 - /// - /// - `path` - 指定的目录 - /// - `ext_name` - 文件的扩展名,如果为None,则列出所有文件 - /// - `recursive` - 是否递归列出所有文件 - pub fn list_all_files(path: &PathBuf, ext_name: Option<&str>, recursive: bool) -> Vec { - let mut queue: Vec = Vec::new(); - let mut result = Vec::new(); - queue.push(path.clone()); - - while !queue.is_empty() { - let path = queue.pop().unwrap(); - let d = std::fs::read_dir(path); - if d.is_err() { - continue; - } - let d = d.unwrap(); - - d.for_each(|ent| { - if let Ok(ent) = ent { - if let Ok(file_type) = ent.file_type() { - if file_type.is_file() { - if let Some(e) = ext_name { - if let Some(ext) = ent.path().extension() { - if ext == e { - result.push(ent.path()); - } - } - } - } else if file_type.is_dir() && recursive { - queue.push(ent.path()); - } - } - } - }); - } - - return result; - } + kernel_build::run(); }