From e21382ae296576f6e136141366992a107846c851 Mon Sep 17 00:00:00 2001 From: Cloyir Date: Mon, 15 May 2023 22:01:55 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86=E5=B1=8E=E5=B1=B1?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=9A=84=E5=90=8C=E6=97=B6=E5=8F=AF=E4=BB=A5?= =?UTF-8?q?=E9=93=BE=E6=8E=A5=E9=9D=99=E6=80=81=E9=93=BE=E6=8E=A5=E5=BA=93?= =?UTF-8?q?=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cbuild/files.rs | 122 ++++++++++++++++++++++---------------------- src/cbuild/mod.rs | 102 +++++++++++++++++++++++++++--------- 2 files changed, 138 insertions(+), 86 deletions(-) diff --git a/src/cbuild/files.rs b/src/cbuild/files.rs index a626bae..48b76b3 100644 --- a/src/cbuild/files.rs +++ b/src/cbuild/files.rs @@ -15,6 +15,20 @@ impl File { extension, } } + + pub fn new_by_path(path: PathBuf) -> Self { + let name = path.file_name().unwrap().to_string_lossy().into_owned(); // 带扩展名的文件 + let extension = std::path::Path::new(&path).extension().unwrap(); + let extension = extension.to_string_lossy().into_owned(); + let name = String::from( + std::path::Path::new(&name) + .file_stem() + .unwrap() + .to_str() + .unwrap(), + ); + Self::new(path, name, extension) + } } #[derive(Debug)] @@ -29,49 +43,12 @@ pub struct FilesSet { impl FilesSet { /// 输入root/src的路径, 整理该路径下的所有文件 - pub fn read(path: PathBuf) -> Self { + pub fn read_src(path: PathBuf) -> Self { let mut entry_files = Vec::new(); let mut c_files = Vec::new(); let mut h_files = Vec::new(); - /// 将路径文件夹内所有文件信息整理到集合中 - fn read_dir( - path: &PathBuf, - c_files: &mut Vec, - h_files: &mut Vec, - ) -> std::io::Result<()> { - for file in std::fs::read_dir(path)? { - let file = file?; - if file.file_type()?.is_dir() { - let name = file.file_name().to_string_lossy().into_owned(); - // 忽略test文件夹 - if name == "test" { - continue; - } - let new_path = path.join(name); - read_dir(&new_path, c_files, h_files)?; - } else { - if let Some(name) = file.path().file_name() { - let file_name: String = name.to_string_lossy().into_owned(); - let extension = std::path::Path::new(&file_name).extension().unwrap(); - let file_name: String = file - .path() - .file_stem() - .unwrap() - .to_string_lossy() - .into_owned(); - let extension: String = extension.to_string_lossy().into_owned(); - if extension == "c" || extension == "cpp" { - c_files.push(File::new(file.path(), file_name, extension)); - } else if extension == "h" || extension == "hpp" { - h_files.push(File::new(file.path(), file_name, extension)); - } - } - } - } - Ok(()) - } - + // 将src文件夹单独处理, 逻辑和fileset_read_dir差不多 for file in std::fs::read_dir(&path).unwrap() { let file = file.unwrap(); if file.file_type().unwrap().is_dir() { @@ -84,38 +61,33 @@ impl FilesSet { // 将src下其它文件夹视作正常.c/.cpp文件 if name == "bin" { let new_path = path.join("bin"); - read_dir(&new_path, &mut entry_files, &mut h_files).unwrap(); + fileset_read_dir(&new_path, &mut entry_files, &mut h_files).unwrap(); } else { let new_path = path.join(name); - read_dir(&new_path, &mut c_files, &mut h_files).unwrap(); + fileset_read_dir(&new_path, &mut c_files, &mut h_files).unwrap(); } } else { // 如果是文件 - if let Some(name) = file.path().file_name() { - let file_name = name.to_string_lossy().into_owned(); - let file_path = file.path(); - let extension = std::path::Path::new(&file_name).extension().unwrap(); - let file_name: String = file - .path() - .file_stem() - .unwrap() - .to_string_lossy() - .into_owned(); - let extension: String = extension.to_string_lossy().into_owned(); - let file = File::new(file_path, file_name, extension); - if file.extension == "c" || file.extension == "cpp" { - if file.name == "main" { - entry_files.push(file); - } else { - c_files.push(file); - } - } else if file.extension == "h" || file.extension == "hpp" { - h_files.push(file); + let file = File::new_by_path(file.path()); + if file.extension == "c" || file.extension == "cpp" { + if file.name == "main" { + entry_files.push(file); + } else { + c_files.push(file); } + } else if file.extension == "h" || file.extension == "hpp" { + h_files.push(file); } } } + // 如果src目录下仅有一个.c/.cpp文件, 则视为唯一项目入口 + if entry_files.len() == 0 && c_files.len() == 1 { + let t = entry_files; + entry_files = c_files; + c_files = t; + } + Self { entry_files, c_files, @@ -123,3 +95,31 @@ impl FilesSet { } } } + +/// 将路径文件夹内所有文件分组整理到集合中 +fn fileset_read_dir( + path: &PathBuf, + c_files: &mut Vec, + h_files: &mut Vec, +) -> std::io::Result<()> { + for file in std::fs::read_dir(path)? { + let file = file?; + if file.file_type()?.is_dir() { + let name = file.file_name().to_string_lossy().into_owned(); + // 忽略test文件夹 + if name == "test" { + continue; + } + let new_path = path.join(name); + fileset_read_dir(&new_path, c_files, h_files)?; + } else { + let file = File::new_by_path(file.path()); + if file.extension == "c" || file.extension == "cpp" { + c_files.push(file); + } else if file.extension == "h" || file.extension == "hpp" { + h_files.push(file); + } + } + } + Ok(()) +} diff --git a/src/cbuild/mod.rs b/src/cbuild/mod.rs index 9ad5112..e061b52 100644 --- a/src/cbuild/mod.rs +++ b/src/cbuild/mod.rs @@ -1,6 +1,8 @@ mod command; mod files; +use std::path::PathBuf; + use crate::const_value::console_log; use self::files::FilesSet; @@ -11,10 +13,6 @@ pub struct CommandsBuild { #[clap(short, long, default_value = "false")] quiet: bool, - /// 对构建优化(默认只有o3优化) - #[clap(long, default_value = "false")] - release: bool, - /// 编译后是否立即运行 #[clap(short, long, default_value = "false")] run: bool, @@ -26,13 +24,17 @@ pub struct CommandsBuild { /// 采用gcc编译指令而不是g++ #[clap(short, default_value = "false")] c: bool, + + /// 其它自定义选项, 需要在语句前加'.', 举例: --other ".-O3 .-mwindows" + #[clap(long)] + other: Option, } pub fn run(config: CommandsBuild) -> Result<(), std::io::Error> { // 获取项目路径 let project_path = std::env::current_dir().unwrap(); - // 获取指定的路径 + // 获取生成文件的目标路径 // let bin_path = project_path.join("target").join("bin"); let bin_path = project_path.join("target"); std::fs::create_dir_all(&bin_path).unwrap(); // 确保bin目录存在 @@ -43,25 +45,20 @@ pub fn run(config: CommandsBuild) -> Result<(), std::io::Error> { } // 将src目录下的文件整理归纳 - let files: FilesSet = { - let mut files = FilesSet::read(project_path.join("src")); - // 如果src目录下仅有一个.c/.cpp文件, 则视为唯一项目入口 - if files.entry_files.len() == 0 && files.c_files.len() == 1 { - let t = files.entry_files; - files.entry_files = files.c_files; - files.c_files = t; - } - files - }; + let files: FilesSet = FilesSet::read_src(project_path.join("src")); // build指令需要读取rust-cmaker下的config文件 let r_config = crate::rtools::config::RConfig::read(); let mut need_run = None; + // 命令通用部分 + let current_args: Vec = make_current_args(&config, &files, project_path.join("lib")); + // 将每一个entry_file构建到指定目录下 for entry_file in &files.entry_files { let mut gcc_cmd = command::get_gcc_command(&config, &r_config); + // 指定生成文件名称 gcc_cmd.arg("-o").arg({ let mut target_name = entry_file.name.clone(); if cfg!(target_os = "windows") { @@ -71,27 +68,35 @@ pub fn run(config: CommandsBuild) -> Result<(), std::io::Error> { target_path }); + // 添加入口文件 gcc_cmd.arg(&entry_file.path); - for c_file in &files.c_files { - gcc_cmd.arg(&c_file.path); - } - - if !config.run { - console_log(&format!("{:?}", gcc_cmd)); + // 组装通用命令 + for item in ¤t_args { + gcc_cmd.arg(item); } + // 执行命令 let output = gcc_cmd.output(); match output { Ok(output) => { - if !config.run { - console_log(&format!("编译成功: {:?}", output)); + if !output.status.success() { + if !config.quiet { + let msg = String::from_utf8_lossy(&output.stderr); + console_log(&format!("编译失败: {}", msg)); + } + continue; + } else if !config.quiet { + console_log(&format!( + "编译成功: {}.{}", + entry_file.name, entry_file.extension + )); } } Err(err) => { - if !config.run { - console_log(&format!("执行出错: {}", err)); + if !config.quiet { + console_log(&format!("编译失败: {:?}", err)); } continue; } @@ -103,6 +108,7 @@ pub fn run(config: CommandsBuild) -> Result<(), std::io::Error> { } } + // 如果满足条件, 运行需要立即执行的程序 if let Some(run_file) = need_run { if !config.quiet { console_log(&format!("{}开始执行: ", run_file.name)); @@ -120,3 +126,49 @@ pub fn run(config: CommandsBuild) -> Result<(), std::io::Error> { Ok(()) } + +fn make_current_args(config: &CommandsBuild, files: &FilesSet, lib_path: PathBuf) -> Vec { + let mut current_args: Vec = Vec::new(); + + // 添加所有非入口文件 + for c_file in &files.c_files { + let arg = String::from(&c_file.path.clone().into_os_string().into_string().unwrap()); + current_args.push(arg); + } + + // 从project/lib文件夹里获取所有的.a文件作为静态链接库 + if let Ok(entries) = std::fs::read_dir(&lib_path) { + let mut a_files = Vec::new(); + + for entry in entries { + if let Ok(entry) = &entry { + let file_path = entry.path(); + if file_path.is_file() { + let file = files::File::new_by_path(file_path); + if file.extension == "a" && file.name.starts_with("lib") { + a_files.push(file); + } + } + } + } + + if a_files.len() != 0 { + current_args.push(String::from("-L")); + current_args.push(lib_path.into_os_string().into_string().to_owned().unwrap()); + for item in a_files { + let ans = item.name.replacen("lib", "-l", 1); + current_args.push(ans); + } + } + } + + // 组装config.other + if let Some(other) = &config.other { + for option in other.split_whitespace() { + let op: String = option.chars().skip(1).collect(); // 去除前置'.' + current_args.push(op); + } + } + + current_args +}