完成基本功能
This commit is contained in:
parent
394636f5fa
commit
6c6656202d
29
.vscode/settings.json
vendored
Normal file
29
.vscode/settings.json
vendored
Normal 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
|
||||||
|
}
|
||||||
@ -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"] }
|
||||||
|
|||||||
26
README.md
26
README.md
@ -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
|
|
||||||
|
|||||||
46
src/build_project/cmake_o.rs
Normal file
46
src/build_project/cmake_o.rs
Normal 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(());
|
||||||
|
}
|
||||||
89
src/build_project/config.rs
Normal file
89
src/build_project/config.rs
Normal 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
65
src/build_project/gcc.rs
Normal 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
49
src/build_project/mod.rs
Normal 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();
|
||||||
|
}
|
||||||
35
src/build_project/utils.rs
Normal file
35
src/build_project/utils.rs
Normal 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;
|
||||||
|
}
|
||||||
43
src/main.rs
43
src/main.rs
@ -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
23
src/new_project/mod.rs
Normal 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
14
src/new_project/text.rs
Normal 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;
|
||||||
|
}
|
||||||
|
"##
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user