完成基本功能

This commit is contained in:
Cloyir 2023-04-17 14:55:54 +08:00
parent 394636f5fa
commit 6c6656202d
11 changed files with 398 additions and 22 deletions

29
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,29 @@
{
"terminal.integrated.profiles.windows": {
"PowerShell": {
"source": "PowerShell",
"icon": "terminal-powershell"
},
"Command Prompt": {
"path": [
"${env:windir}\\Sysnative\\cmd.exe",
"${env:windir}\\System32\\cmd.exe"
],
"args": [],
"icon": "terminal-cmd"
},
"Git Bash": {
"source": "Git Bash"
}
},
"rust-analyzer.linkedProjects": [
".\\Cargo.toml",
".\\Cargo.toml",
".\\Cargo.toml",
".\\Cargo.toml",
".\\Cargo.toml",
".\\Cargo.toml"
],
"rust-analyzer.showUnlinkedFileNotification": false
}

View File

@ -6,3 +6,4 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
clap = { version = "4.2.2", features = ["derive"] }

View File

@ -1,27 +1,13 @@
# rust-cmaker # rust-cmaker
#### 介绍 #### 介绍
> 2023年了谁还在用传统cmake啊大嘘
用rust封装MinGW的命令方便一键在vscode中构建c/c++简单项目 用rust封装MinGW的命令方便一键在vscode中构建c/c++简单项目
#### 软件架构
软件架构说明
#### 安装教程
1. xxxx
2. xxxx
3. xxxx
#### 使用说明 #### 使用说明
1. xxxx 1. 将本程序加入到Path或者干脆在每一个c/c++项目的根目录中加入一个,反正它不大
2. xxxx 2. 使用`--help`命令行参数查看使用说明
3. xxxx 3. 测试版需要环境里已经有gcc、g++的环境变量
#### 参与贡献
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request

View File

@ -0,0 +1,46 @@
use std::path::PathBuf;
use super::config::BuildConfigTrait;
pub fn cmake_o(
config: &Box<dyn BuildConfigTrait>,
src_path: PathBuf,
file_o_set: &mut Vec<PathBuf>,
) -> Result<(), std::io::Error> {
// 遍历文件夹内每个子项
let dir = std::fs::read_dir(src_path)?;
for path in dir {
let path = path?;
// 如果子项为文件夹, 递归查找内部项
if path.file_type()?.is_dir() {
cmake_o(config, path.path(), file_o_set)?;
continue;
}
// 判断是否为需要编译的文件, 即.c/.cpp文件
let file_path = path;
let file_name = String::from(file_path.file_name().to_str().unwrap());
let file_type = super::utils::file_is_c_or_cpp(&file_name);
if file_type.is_else() {
continue;
}
// 找到需要编译的文件, 将其输出到target/o目录下
let new_file_path =
PathBuf::from(config.getpath_target_o()).join((*file_o_set).len().to_string() + ".o");
use super::gcc::make_file_to_target_o;
match file_type {
super::utils::FileType::C => {
make_file_to_target_o(config.getpath_gcc(), &file_path.path(), &new_file_path)?;
}
super::utils::FileType::Cpp => {
make_file_to_target_o(config.getpath_gpp(), &file_path.path(), &new_file_path)?;
}
super::utils::FileType::Else => {
continue;
}
}
file_o_set.push(new_file_path);
}
return Ok(());
}

View File

@ -0,0 +1,89 @@
use std::path::PathBuf;
pub trait BuildConfigTrait {
fn getpath_gcc(&self) -> String;
fn getpath_gpp(&self) -> String;
fn getpath_src(&self) -> String;
fn getpath_target_o(&self) -> String;
fn get_project_name(&self) -> &str;
fn getpath_target_bin(&self) -> String;
fn getpath_target_file(&self) -> String;
}
#[derive(Debug)]
pub struct BuildConfig {
compiler_path: Option<PathBuf>,
project_path: PathBuf,
project_name: String,
}
impl BuildConfig {
pub fn new(
compiler_path: Option<PathBuf>,
project_path: PathBuf,
project_name: String,
) -> Self {
Self {
compiler_path,
project_path,
project_name,
}
}
}
impl BuildConfigTrait for BuildConfig {
fn getpath_gcc(&self) -> String {
return self.getpath_gpp(); // 此处需要修改
}
fn getpath_gpp(&self) -> String {
if self.compiler_path.is_none() {
return String::from("g++");
}
String::from(
self.compiler_path
.clone()
.unwrap()
.join("bin")
.join("g++")
.to_str()
.unwrap(),
)
}
fn getpath_src(&self) -> String {
String::from(self.project_path.clone().join("src").to_str().unwrap())
}
fn getpath_target_o(&self) -> String {
String::from(
self.project_path
.clone()
.join("target")
.join("o")
.to_str()
.unwrap(),
)
}
fn get_project_name(&self) -> &str {
&self.project_name
}
fn getpath_target_bin(&self) -> String {
String::from(
self.project_path
.clone()
.join("target")
.join("bin")
.to_str()
.unwrap(),
)
}
fn getpath_target_file(&self) -> String {
let file_name = String::from(self.get_project_name()) + ".exe";
let ans = PathBuf::from(self.getpath_target_bin()).join(file_name);
String::from(ans.to_str().unwrap())
}
}

65
src/build_project/gcc.rs Normal file
View File

@ -0,0 +1,65 @@
use std::path::{Path, PathBuf};
// 根据单个.c/.cpp文件的路径创建.o文件并输出到new_file_path
pub fn make_file_to_target_o(
command: String,
source_file_path: &PathBuf,
new_file_path: &PathBuf,
) -> Result<(), std::io::Error> {
// 获取路径
let source_file_path = source_file_path.to_str().unwrap();
let new_file_path = new_file_path.to_str().unwrap();
// 运行指令
let mut output = std::process::Command::new(command);
output.args(["-o", new_file_path]);
output.args(["-c", source_file_path]);
let output = output.output()?;
// 输出调试信息
let state = if output.status.success() {
format!("{}: success to compile 编译成功", crate::PROJECT_NAME)
} else {
format!(
"{}: failed to compile 编译失败 \n错误信息: {:?}",
crate::PROJECT_NAME,
String::from_utf8(output.stderr).unwrap()
)
};
println!(
"{}: file : {:?} ---> new file : {:?} ---> {}",
crate::PROJECT_NAME,
Path::new(source_file_path).file_name().unwrap(),
Path::new(new_file_path).file_name().unwrap(),
state
);
Ok(())
}
// 根据.o文件的集合构建可执行程序
pub fn make_o_files_to_bin(
command: String,
source_paths: &mut Vec<PathBuf>,
target_path: String,
) -> Result<(), std::io::Error> {
// 创建指令
let mut output = std::process::Command::new(command);
while !source_paths.is_empty() {
let item = source_paths.pop().unwrap();
output.arg(item.to_str().unwrap());
}
output.args(["-o", &target_path]);
// 运行指令
let output = output.output()?;
if output.status.success() {
println!("{}: success to compile 编译成功", crate::PROJECT_NAME);
} else {
println!(
"{}: failed to compile 编译失败\n{:?}",
crate::PROJECT_NAME,
output
);
}
Ok(())
}

49
src/build_project/mod.rs Normal file
View File

@ -0,0 +1,49 @@
mod cmake_o;
mod config;
mod gcc;
mod utils;
use std::path::PathBuf;
use config::{BuildConfig, BuildConfigTrait};
pub fn build_project() {
let project_path = std::env::current_dir().unwrap();
println!("{:?}", project_path);
// 获取配置
let config: Box<dyn BuildConfigTrait> = Box::new(BuildConfig::new(
None,
// Some(PathBuf::from(r"C:\Program Files\CodeBlocks\MinGW")),
PathBuf::from(project_path),
String::from("HelloWorld"),
));
// 递归所有src目录下的.c/.cpp文件并编译为.o文件输出到@/target/o目录下
let mut file_set: Vec<PathBuf> = Vec::new(); // 所有应临时存储的文件路径集合
println!(
"{}: start to compile 开始编译 step: 1/2",
crate::PROJECT_NAME
);
std::fs::create_dir_all(config.getpath_target_o()).unwrap(); // 先创建这层目录
cmake_o::cmake_o(&config, PathBuf::from(config.getpath_src()), &mut file_set).unwrap();
// 遍历@/target/o联合编译到@/target/bin中
println!(
"{}: start to compile 开始编译 step: 2/2",
crate::PROJECT_NAME
);
std::fs::create_dir_all(config.getpath_target_bin()).unwrap(); // 先创建这层目录
if PathBuf::from(config.getpath_target_file()).exists() {
std::fs::remove_file(config.getpath_target_file()).unwrap(); // 先删除目标文件
}
gcc::make_o_files_to_bin(
config.getpath_gpp(),
&mut file_set,
config.getpath_target_file(),
)
.unwrap();
// 删除@/target/o文件夹
std::fs::remove_dir_all(config.getpath_target_o()).unwrap();
}

View File

@ -0,0 +1,35 @@
pub enum FileType {
C,
Cpp,
Else,
}
impl FileType {
pub fn is_else(&self) -> bool {
match self {
Self::Else => {
return true;
}
_ => {
return false;
}
}
}
}
// 判断文件名是否为.c或.cpp结尾
pub fn file_is_c_or_cpp(file_name: &String) -> FileType {
let t: Vec<&u8> = file_name.as_bytes().iter().collect();
if t.len() >= 2 && *t[t.len() - 2] == b'.' && *t[t.len() - 1] == b'c' {
return FileType::C;
}
if t.len() >= 4
&& *t[t.len() - 4] == b'.'
&& *t[t.len() - 3] == b'c'
&& *t[t.len() - 2] == b'p'
&& *t[t.len() - 1] == b'p'
{
return FileType::Cpp;
}
return FileType::Else;
}

View File

@ -1,3 +1,42 @@
fn main() { pub mod build_project;
println!("Hello, world!"); pub mod new_project;
pub const PROJECT_NAME: &str = "rust-cmaker";
use clap::{command, Parser, Subcommand};
/// 命令行参数
#[derive(Parser, Debug)]
#[command(author = "Cloyir min123456@foxmail.com", version = "1.0.0", about = None, long_about = None)]
struct Args {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand, Debug)]
enum Commands {
/// 在当前目录新建项目
New {
/// 项目名称
project_name: String,
},
/// 在此项目内编译
Build,
}
fn main() -> std::io::Result<()> {
// 解析命令行参数
let args = Args::parse();
// println!("args: {:?}", args);
match args.command {
Commands::New { project_name } => {
new_project::new_project(project_name);
}
Commands::Build => {
build_project::build_project();
}
}
Ok(())
} }

23
src/new_project/mod.rs Normal file
View File

@ -0,0 +1,23 @@
mod text;
/// 创建新项目
pub fn new_project(project_name: String) {
println!("新建项目: {}", project_name);
let target_path = std::env::current_dir().unwrap().join(&project_name);
println!("目标路径: {:?}", target_path);
if let Ok(_) = target_path.read_dir() {
println!("创建项目失败, 已存在名为{}的文件夹", project_name);
return;
}
let src_path = target_path.join("src");
std::fs::create_dir_all(&src_path).unwrap();
// 新建README.md文件
std::fs::write(target_path.join("README.md"), text::get_readme_text()).unwrap();
// 新建main.cpp文件
std::fs::write(src_path.join("main.cpp"), text::get_maincpp_text()).unwrap();
println!("创建成功");
println!("请进入{}文件夹再使用build指令构建项目", project_name);
}

14
src/new_project/text.rs Normal file
View File

@ -0,0 +1,14 @@
// 返回生成文件的文本
pub fn get_readme_text() -> &'static str {
""
}
pub fn get_maincpp_text() -> &'static str {
r##"#include <iostream>
int main() {
std::cout << "Hello World!" << std::endl;
}
"##
}