1 //! # DADK - DragonOS Application Development Kit 2 //! # DragonOS 应用开发工具 3 //! 4 //! ## 简介 5 //! 6 //! DADK是一个用于开发DragonOS应用的工具包,设计目的是为了让开发者能够更加方便的开发DragonOS应用。 7 //! 8 //! ### DADK做什么? 9 //! 10 //! - 自动配置libc等编译用户程序所需的环境 11 //! - 自动处理软件库的依赖关系 12 //! - 自动处理软件库的编译 13 //! - 一键将软件库安装到DragonOS系统中 14 //! 15 //! ### DADK不做什么? 16 //! 17 //! - DADK不会帮助开发者编写代码 18 //! - DADK不提供任何开发DragonOS应用所需的API。这部分工作由libc等库来完成 19 //! 20 //! ## License 21 //! 22 //! DADK is licensed under the [GPLv2 License](https://www.gnu.org/licenses/old-licenses/gpl-2.0.html). 23 //! 24 //! ## 快速开始 25 //! 26 //! ### 安装DADK 27 //! 28 //! DADK是一个Rust程序,您可以通过Cargo来安装DADK。 29 //! 30 //! ```shell 31 //! # 从GitHub安装最新版 32 //! cargo install --git https://github.com/DragonOS-Community/DADK.git 33 //! 34 //! # 从crates.io下载 35 //! cargo install dadk 36 //! 37 //! ``` 38 //! 39 //! ## DADK的工作原理 40 //! 41 //! DADK使用(任务名,任务版本)来标识每个构建目标。当使用DADK构建DragonOS应用时,DADK会根据用户的配置文件,自动完成以下工作: 42 //! 43 //! - 解析配置文件,生成DADK任务列表 44 //! - 根据DADK任务列表,进行拓扑排序。这一步会自动处理软件库的依赖关系。 45 //! - 收集环境变量信息,并根据DADK任务列表,设置全局环境变量、任务环境变量。 46 //! - 根据拓扑排序后的DADK任务列表,自动执行任务。 47 //! 48 //! ### DADK与环境变量 49 //! 50 //! 环境变量的设置是DADK能正常工作的关键因素之一,您可以在您的编译脚本中,通过引用环境变量,来获得其他软件库的编译信息。 51 //! 这是使得您的应用能够自动依赖其他软件库的关键一步。 52 //! 53 //! 只要您的编译脚本能够正确地引用环境变量,DADK就能够自动处理软件库的依赖关系。 54 //! 55 //! DADK会设置以下全局环境变量: 56 //! 57 //! - `DADK_CACHE_ROOT`:DADK的缓存根目录。您可以在编译脚本中,通过引用该环境变量,来获得DADK的缓存根目录。 58 //! - `DADK_BUILD_CACHE_DIR_任务名_任务版本`:DADK的任务构建结果缓存目录。当您要引用其他软件库的构建结果时,可以通过该环境变量来获得。 59 //! 同时,您也要在构建您的app时,把构建结果放到您的软件库的构建结果缓存目录(通过对应的环境变量获得)中。 60 //! - `DADK_SOURCE_CACHE_DIR_任务名_任务版本`:DADK的某个任务的源码目录。当您要引用其他软件库的源码目录时,可以通过该环境变量来获得。 61 //! 62 //! 同时,DADK会为每个任务设置其自身在配置文件中指定的环境变量。 63 //! 64 //! #### 全局环境变量命名格式 65 //! 66 //! 全局环境变量中的任务名和任务版本,都会被转换为大写字母,并对特殊字符进行替换。替换表如下: 67 //! 68 //! | 原字符 | 替换字符 | 69 //! | ------ | -------- | 70 //! | `.` | `_` | 71 //! | `-` | `_` | 72 //! | `\t` | `_` | 73 //! | 空格 | `_` | 74 //! | `+` | `_` | 75 //! | `*` | `_` | 76 //! 77 //! **举例**:对于任务`libc-0.1.0`,其构建结果的全局环境变量名为`DADK_BUILD_CACHE_DIR_LIBC_0_1_0`。 78 //! 79 //! 80 //! ## TODO 81 //! 82 //! - 支持从在线归档文件下载源码、构建好的软件库 83 //! - 支持自动更新 84 //! - 完善clean命令的逻辑 85 86 #![feature(extract_if)] 87 #![feature(io_error_more)] 88 89 #[macro_use] 90 extern crate lazy_static; 91 extern crate log; 92 extern crate serde; 93 extern crate serde_json; 94 95 #[cfg(test)] 96 extern crate test_base; 97 98 use std::{path::PathBuf, process::exit, sync::Arc}; 99 100 use clap::Parser; 101 102 use log::{error, info}; 103 use parser::task::DADKTask; 104 105 use crate::{ 106 console::{interactive::InteractiveConsole, CommandLineArgs}, 107 context::DadkUserExecuteContextBuilder, 108 scheduler::Scheduler, 109 }; 110 111 mod console; 112 mod context; 113 mod executor; 114 pub mod parser; 115 mod scheduler; 116 pub mod static_resources; 117 mod utils; 118 119 pub fn dadk_user_main() { 120 let args = CommandLineArgs::parse(); 121 122 info!("DADK run with args: {:?}", &args); 123 124 let context = DadkUserExecuteContextBuilder::default() 125 .sysroot_dir(args.sysroot_dir) 126 .config_dir(args.config_dir) 127 .action(args.action) 128 .thread_num(args.thread) 129 .cache_dir(args.cache_dir) 130 .build() 131 .expect("Failed to build execute context"); 132 let context = Arc::new(context); 133 context.init(context.clone()); 134 // DragonOS sysroot在主机上的路径 135 136 info!( 137 "DragonOS sysroot dir: {}", 138 context 139 .sysroot_dir() 140 .map_or_else(|| "None".to_string(), |d| d.display().to_string()) 141 ); 142 info!( 143 "Config dir: {}", 144 context 145 .config_dir() 146 .map_or_else(|| "None".to_string(), |d| d.display().to_string()) 147 ); 148 info!("Action: {:?}", context.action()); 149 info!( 150 "Thread num: {}", 151 context.thread_num().map_or_else(|| 0, |t| t) 152 ); 153 154 match context.action() { 155 console::Action::New => { 156 let r = InteractiveConsole::new( 157 context.sysroot_dir().cloned(), 158 context.config_dir().cloned(), 159 *context.action(), 160 ) 161 .run(); 162 if r.is_err() { 163 error!("Failed to run interactive console: {:?}", r.unwrap_err()); 164 exit(1); 165 } 166 exit(0); 167 } 168 _ => {} 169 } 170 171 let mut parser = parser::Parser::new(context.config_dir().unwrap().clone()); 172 let r = parser.parse(); 173 if r.is_err() { 174 exit(1); 175 } 176 let tasks: Vec<(PathBuf, DADKTask)> = r.unwrap(); 177 // info!("Parsed tasks: {:?}", tasks); 178 179 let scheduler = Scheduler::new( 180 context.clone(), 181 context.sysroot_dir().cloned().unwrap(), 182 *context.action(), 183 tasks, 184 ); 185 if scheduler.is_err() { 186 exit(1); 187 } 188 189 let r = scheduler.unwrap().run(); 190 if r.is_err() { 191 exit(1); 192 } 193 } 194