1 extern crate bindgen; 2 extern crate cc; 3 // use ::std::env; 4 5 use std::path::PathBuf; 6 7 use cc::Build; 8 9 fn main() { 10 // Tell cargo to look for shared libraries in the specified directory 11 println!("cargo:rustc-link-search=src"); 12 println!("cargo:rerun-if-changed=src/include/bindings/wrapper.h"); 13 14 generate_bindings(); 15 CFilesBuilder::build(); 16 } 17 18 fn generate_bindings() { 19 // let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); 20 let out_path = PathBuf::from(String::from("src/include/bindings/")); 21 22 // The bindgen::Builder is the main entry point 23 // to bindgen, and lets you build up options for 24 // the resulting bindings. 25 { 26 let bindings = bindgen::Builder::default() 27 .clang_arg("-I./src") 28 .clang_arg("-I./src/include") 29 .clang_arg("-I./src/arch/x86_64/include") // todo: 当引入多种架构之后,需要修改这里,对于不同的架构编译时,include不同的路径 30 // The input header we would like to generate 31 // bindings for. 32 .header("src/include/bindings/wrapper.h") 33 .blocklist_file("src/include/bindings/bindings.h") 34 .clang_arg("--target=x86_64-none-none") 35 .clang_arg("-v") 36 // 使用core,并将c语言的类型改为core::ffi,而不是使用std库。 37 .use_core() 38 .ctypes_prefix("::core::ffi") 39 .generate_inline_functions(true) 40 .raw_line("#![allow(dead_code)]") 41 .raw_line("#![allow(non_upper_case_globals)]") 42 .raw_line("#![allow(non_camel_case_types)]") 43 // Tell cargo to invalidate the built crate whenever any of the 44 // included header files changed. 45 .parse_callbacks(Box::new(bindgen::CargoCallbacks)) 46 // Finish the builder and generate the bindings. 47 .generate() 48 // Unwrap the Result and panic on failure. 49 .expect("Unable to generate bindings"); 50 51 bindings 52 .write_to_file(out_path.join("bindings.rs")) 53 .expect("Couldn't write bindings!"); 54 } 55 } 56 57 /// 构建项目的c文件 58 struct CFilesBuilder; 59 60 impl CFilesBuilder { 61 fn build() { 62 let mut c = cc::Build::new(); 63 Self::setup_global_flags(&mut c); 64 Self::setup_defines(&mut c); 65 Self::setup_global_include_dir(&mut c); 66 Self::setup_files(&mut c); 67 c.compile("dragonos_kernel_cfiles"); 68 } 69 70 fn setup_global_flags(c: &mut Build) { 71 c.flag("-mcmodel=large") 72 .flag("-fno-builtin") 73 .flag("-nostdlib") 74 .flag("-fno-stack-protector") 75 .flag("-fno-pie") 76 .flag("-Wno-expansion-to-defined") 77 .flag("-Wno-unused-parameter") 78 .flag("-m64") 79 .flag("-O1"); 80 } 81 82 fn setup_defines(c: &mut Build) { 83 if let Ok(k) = std::env::var("EMULATOR") { 84 c.define("EMULATOR", Some(k.as_str())); 85 } else { 86 c.define("EMULATOR", "__NO_EMULATION__"); 87 } 88 89 { 90 #[cfg(target_arch = "x86_64")] 91 c.define("__x86_64__", None); 92 } 93 } 94 95 fn setup_global_include_dir(c: &mut Build) { 96 c.include("src/include"); 97 c.include("src"); 98 c.include("."); 99 100 #[cfg(target_arch = "x86_64")] 101 c.include("src/arch/x86_64/include"); 102 } 103 104 /// 设置需要编译的文件 105 fn setup_files(c: &mut Build) { 106 let mut files = Vec::new(); 107 108 #[cfg(target_arch = "x86_64")] 109 Self::setup_files_x86_64(&mut files); 110 111 Self::set_rerun_if_files_changed(&files); 112 c.files(files.as_slice()); 113 } 114 115 /// 设置x86_64架构下需要编译的C文件 116 fn setup_files_x86_64(files: &mut Vec<PathBuf>) { 117 files.push(PathBuf::from("src/arch/x86_64/driver/hpet.c")); 118 // 获取`kernel/src/arch/x86_64/driver/apic`下的所有C文件 119 files.append(&mut FileUtils::list_all_files( 120 &PathBuf::from("src/arch/x86_64/driver/apic"), 121 Some("c"), 122 true, 123 )); 124 } 125 126 /// 设置Cargo对文件更改的监听 127 fn set_rerun_if_files_changed(files: &Vec<PathBuf>) { 128 for f in files { 129 println!("cargo:rerun-if-changed={}", f.to_str().unwrap()); 130 } 131 } 132 } 133 134 struct FileUtils; 135 136 impl FileUtils { 137 /// 列出指定目录下的所有文件 138 /// 139 /// ## 参数 140 /// 141 /// - `path` - 指定的目录 142 /// - `ext_name` - 文件的扩展名,如果为None,则列出所有文件 143 /// - `recursive` - 是否递归列出所有文件 144 pub fn list_all_files(path: &PathBuf, ext_name: Option<&str>, recursive: bool) -> Vec<PathBuf> { 145 let mut queue: Vec<PathBuf> = Vec::new(); 146 let mut result = Vec::new(); 147 queue.push(path.clone()); 148 149 while !queue.is_empty() { 150 let path = queue.pop().unwrap(); 151 let d = std::fs::read_dir(path); 152 if d.is_err() { 153 continue; 154 } 155 let d = d.unwrap(); 156 157 d.for_each(|ent| { 158 if let Ok(ent) = ent { 159 if let Ok(file_type) = ent.file_type() { 160 if file_type.is_file() { 161 if let Some(e) = ext_name { 162 if let Some(ext) = ent.path().extension() { 163 if ext == e { 164 result.push(ent.path()); 165 } 166 } 167 } 168 } else if file_type.is_dir() && recursive { 169 queue.push(ent.path()); 170 } 171 } 172 } 173 }); 174 } 175 176 return result; 177 } 178 } 179