started working on build system
This commit is contained in:
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
cargo-features = ["codegen-backend"]
|
cargo-features = ["codegen-backend"]
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["emulator", "common", "assembler", "dsa_editor", "compiler"]
|
members = ["emulator", "common", "assembler", "dsa_editor", "compiler", "dsx-build"]
|
||||||
resolver = "3"
|
resolver = "3"
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
|
|||||||
@@ -24,5 +24,22 @@ pub mod prelude {
|
|||||||
pub use crate::tooling::project;
|
pub use crate::tooling::project;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
use num_cpus as _;
|
use num_cpus as _;
|
||||||
use threadpool as _;
|
use threadpool as _;
|
||||||
|
|
||||||
|
use crate::prelude::CompilerEngine;
|
||||||
|
|
||||||
|
pub fn assemble_file(input: &str, output: &str) -> Result<(), std::io::Error> {
|
||||||
|
let mut engine = CompilerEngine::new();
|
||||||
|
engine.start_compilation(Path::new(input));
|
||||||
|
let result = engine.wait_for_result().unwrap();
|
||||||
|
for instruction in result {
|
||||||
|
if let Err(e) = std::fs::write(output, instruction.encode().to_be_bytes()) {
|
||||||
|
eprintln!("Failed to write to output file: {e}");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "dsx-build"
|
||||||
|
version.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
authors.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
compiler = { path = "../compiler" }
|
||||||
|
assembler = { path = "../assembler" }
|
||||||
|
chrono = "0.4.43"
|
||||||
@@ -0,0 +1,223 @@
|
|||||||
|
use std::process::{Command, Stdio};
|
||||||
|
use std::{
|
||||||
|
env, fs,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Run a command and exit on failure.
|
||||||
|
fn run(cmd: &mut Command) {
|
||||||
|
let status = cmd.status().expect("failed to execute command");
|
||||||
|
if !status.success() {
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Very small CLI – only three sub‑commands.
|
||||||
|
let args: Vec<String> = env::args().collect();
|
||||||
|
if args.len() < 2 {
|
||||||
|
eprintln!("Usage: dsx-build <new|build|package> [options]");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
match args[1].as_str() {
|
||||||
|
"new" => cmd_new(&args[2..]),
|
||||||
|
"build" => cmd_build(),
|
||||||
|
"package" => todo!("Package manager stub – not implemented yet."),
|
||||||
|
_ => {
|
||||||
|
eprintln!("Unknown command: {}", args[1]);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- new project ----------------------------------------------------
|
||||||
|
fn cmd_new(args: &[String]) {
|
||||||
|
let mut lang = "dsa";
|
||||||
|
for i in 0..args.len() {
|
||||||
|
if args[i] == "--lang" && i + 1 < args.len() {
|
||||||
|
lang = &args[i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine project root: a subdirectory named after the supplied --name argument.
|
||||||
|
let mut name_opt = None;
|
||||||
|
for i in 0..args.len() {
|
||||||
|
if args[i] == "--name" && i + 1 < args.len() {
|
||||||
|
name_opt = Some(&args[i + 1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let project_name = match name_opt {
|
||||||
|
Some(name) => name.to_string(),
|
||||||
|
None => {
|
||||||
|
eprintln!("Error: --name argument required");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let cwd = env::current_dir().unwrap();
|
||||||
|
let src_path = cwd.join(&project_name).join("src");
|
||||||
|
fs::create_dir_all(&src_path).expect("Failed to create project directory");
|
||||||
|
|
||||||
|
match lang {
|
||||||
|
"dsa" => {
|
||||||
|
// Minimal DSA binary template.
|
||||||
|
let path = src_path.join(format!("main.dsa"));
|
||||||
|
let template = format!(
|
||||||
|
r#"
|
||||||
|
// GENERATED BY DSX-BUILD
|
||||||
|
// Generated at: {timestamp}
|
||||||
|
// Project name: {project_name}
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
include print: "./lib/io/print.dsa"
|
||||||
|
|
||||||
|
// Globals & Reserved Memory
|
||||||
|
dw stack: 0x10000
|
||||||
|
db message: "Process Exited with code:"
|
||||||
|
|
||||||
|
// Entry Point
|
||||||
|
_init:
|
||||||
|
ldw stack, bpr
|
||||||
|
mov bpr, spr
|
||||||
|
push zero
|
||||||
|
call main
|
||||||
|
call print::print_newline
|
||||||
|
lwi message, rg0
|
||||||
|
push rg0
|
||||||
|
call print::print
|
||||||
|
pop zero
|
||||||
|
call print::print_hex_word
|
||||||
|
pop zero
|
||||||
|
hlt
|
||||||
|
|
||||||
|
main:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
lli 0, rg0
|
||||||
|
stw rg0, bpr, 8
|
||||||
|
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return"#,
|
||||||
|
project_name = project_name,
|
||||||
|
timestamp = chrono::Utc::now().format("%Y-%m-%d %H:%M:%S").to_string()
|
||||||
|
);
|
||||||
|
fs::write(path, template).expect("Unable to write DSA file");
|
||||||
|
}
|
||||||
|
"dsc" => {
|
||||||
|
let path = src_path.join(format!("main.dsc"));
|
||||||
|
let template = r#"
|
||||||
|
include print: "./lib/io/print.dsa";
|
||||||
|
|
||||||
|
fn main() -> u32 {
|
||||||
|
return 0;
|
||||||
|
}"#;
|
||||||
|
fs::write(path, template).expect("Unable to write DSC file");
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
eprintln!("Unsupported language: {}", lang);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Created new {} project in {}.",
|
||||||
|
lang,
|
||||||
|
src_path.parent().unwrap().display()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- build ----------------------------------------------------------
|
||||||
|
fn cmd_build() {
|
||||||
|
let cwd = env::current_dir().unwrap();
|
||||||
|
|
||||||
|
// Detect .dsc or .dsa files in current directory.
|
||||||
|
let mut has_dsc = false;
|
||||||
|
let mut has_dsa = false;
|
||||||
|
for entry in fs::read_dir(&cwd.join("src")).expect("unable to read dir") {
|
||||||
|
if let Ok(entry) = entry {
|
||||||
|
let path = entry.path();
|
||||||
|
if path.extension().and_then(|s| s.to_str()) == Some("dsc") {
|
||||||
|
has_dsc = true;
|
||||||
|
} else if path.extension().and_then(|s| s.to_str()) == Some("dsa") {
|
||||||
|
has_dsa = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !has_dsc && !has_dsa {
|
||||||
|
eprintln!("No .dsc or .dsa source found in src directory.");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble main.dsa to a dsb binary.
|
||||||
|
println!("Assembling Project to a DSB binary...");
|
||||||
|
let build_dir = cwd.join("build");
|
||||||
|
fs::create_dir_all(&build_dir).expect("Failed to create build directory");
|
||||||
|
|
||||||
|
// Copy everything from `cwd/src` to the build directory.
|
||||||
|
fn copy_recursively(src: &Path, dst: &Path) {
|
||||||
|
if src.is_file() {
|
||||||
|
fs::create_dir_all(dst.parent().unwrap())
|
||||||
|
.expect("Failed to create parent directory");
|
||||||
|
fs::copy(src, dst).expect("Failed to copy file");
|
||||||
|
} else if src.is_dir() {
|
||||||
|
for entry in fs::read_dir(src).expect("Unable to read source dir") {
|
||||||
|
let entry = entry.expect("Failed to read entry");
|
||||||
|
let child_src = entry.path();
|
||||||
|
let child_dst = dst.join(entry.file_name());
|
||||||
|
copy_recursively(&child_src, &child_dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let src_dir = cwd.join("src");
|
||||||
|
if src_dir.exists() {
|
||||||
|
copy_recursively(&src_dir, &build_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change current working directory to the build directory.
|
||||||
|
env::set_current_dir(&build_dir).expect("Failed to change to build directory");
|
||||||
|
|
||||||
|
if has_dsc {
|
||||||
|
println!("Compiling DSC to DSA...");
|
||||||
|
fn compile_recursive(path: &Path) {
|
||||||
|
if path.is_dir() {
|
||||||
|
for entry in fs::read_dir(path).expect("unable to read dir") {
|
||||||
|
let entry = entry.expect("failed to read entry");
|
||||||
|
compile_recursive(&entry.path());
|
||||||
|
}
|
||||||
|
} else if path.extension().and_then(|s| s.to_str()) == Some("dsc") {
|
||||||
|
let input_path = path;
|
||||||
|
let output_path = path.with_extension("dsa");
|
||||||
|
compiler::compile_file(&input_path, &output_path).unwrap_or_else(|e| {
|
||||||
|
eprintln!("Failed to compile {:?}: {}", input_path, e);
|
||||||
|
std::process::exit(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compile_recursive(&build_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace .dsc with .dsa only in include statements, recursively for each file.
|
||||||
|
let mut sed_cmd = Command::new("bash");
|
||||||
|
sed_cmd.args(&[
|
||||||
|
"-c",
|
||||||
|
&format!(
|
||||||
|
"find \"{}\" -type f -name '*.dsa' -exec sed -i '/^include/ s/\\.dsc/.dsa/g' {{}} +",
|
||||||
|
build_dir.display()
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
run(&mut sed_cmd);
|
||||||
|
|
||||||
|
fs::create_dir_all(&cwd.join("artifacts")).expect("Failed to create build directory");
|
||||||
|
assembler::assemble_file("./main.dsa", "../artifacts/out.dsb").unwrap_or_else(|e| {
|
||||||
|
eprintln!("Failed to assemble {:?}: {}", "./main.dsa", e);
|
||||||
|
std::process::exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
println!("Build finished. Binary at {}/main.dsb", build_dir.display());
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user