Skip to content

Commit

Permalink
Adds --export option for build command
Browse files Browse the repository at this point in the history
  • Loading branch information
ultimaweapon committed Sep 23, 2023
1 parent 21b4c8a commit 1035686
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 39 deletions.
4 changes: 2 additions & 2 deletions stage0/src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub struct Codegen<'a> {
version: &'a PackageVersion,
target: &'a Target,
namespace: &'a str,
resolver: &'a Resolver<'a>,
resolver: &'a TypeResolver<'a>,
}

impl<'a> Codegen<'a> {
Expand All @@ -45,7 +45,7 @@ impl<'a> Codegen<'a> {
version: &'a PackageVersion,
target: &'a Target,
module: M,
resolver: &'a Resolver<'a>,
resolver: &'a TypeResolver<'a>,
) -> Self
where
M: AsRef<CStr>,
Expand Down
4 changes: 2 additions & 2 deletions stage0/src/codegen/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ use crate::pkg::ExportedType;
use std::collections::HashMap;

/// An object to resolve types.
pub struct Resolver<'a> {
pub struct TypeResolver<'a> {
types: HashMap<String, ResolvedType<'a>>,
}

impl<'a> Resolver<'a> {
impl<'a> TypeResolver<'a> {
pub fn new() -> Self {
Self {
types: HashMap::new(),
Expand Down
8 changes: 8 additions & 0 deletions stage0/src/dep/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/// An object for resolving package dependencies.
pub struct DepResolver {}

impl DepResolver {
pub fn new() -> Self {
Self {}
}
}
65 changes: 56 additions & 9 deletions stage0/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
use crate::ast::ParseError;
use crate::dep::DepResolver;
use crate::ffi::llvm_init;
use crate::project::{Project, ProjectBuildError, ProjectLoadError};
use crate::project::{Project, ProjectBuildError, ProjectLoadError, ProjectType};
use clap::{command, value_parser, Arg, ArgMatches, Command};
use std::error::Error;
use std::fmt::Write;
use std::fs::create_dir_all;
use std::path::PathBuf;
use std::process::ExitCode;

mod ast;
mod codegen;
mod dep;
mod ffi;
mod lexer;
mod pkg;
Expand All @@ -19,12 +22,21 @@ fn main() -> ExitCode {
let args = command!()
.subcommand_required(true)
.subcommand(
Command::new("build").about("Build a Nitro project").arg(
Arg::new("path")
.help("Path to the project")
.value_name("PATH")
.value_parser(value_parser!(PathBuf)),
),
Command::new("build")
.about("Build a Nitro project")
.arg(
Arg::new("export")
.help("Export executables or a package to the specified directory")
.long("export")
.value_name("PATH")
.value_parser(value_parser!(PathBuf)),
)
.arg(
Arg::new("project")
.help("Path to the project")
.value_name("PATH")
.value_parser(value_parser!(PathBuf)),
),
)
.get_matches();

Expand All @@ -39,9 +51,12 @@ fn build(args: &ArgMatches) -> ExitCode {
// Initialize LLVM.
unsafe { llvm_init() };

// Setup dependency resolver.
let mut resolver = DepResolver::new();

// Open the project.
let path = args.get_one::<PathBuf>("path").unwrap();
let mut project = match Project::open(&path) {
let path = args.get_one::<PathBuf>("project").unwrap();
let mut project = match Project::open(&path, &mut resolver) {
Ok(v) => v,
Err(e) => {
eprintln!("Cannot open {}: {}.", path.display(), join_nested(&e));
Expand Down Expand Up @@ -86,6 +101,38 @@ fn build(args: &ArgMatches) -> ExitCode {
}
};

// Export the project.
if let Some(path) = args.get_one::<PathBuf>("export") {
match project.meta().package().ty() {
ProjectType::Executable => {
// Export the project.
if let Err(e) = pkg.export(&path, &mut resolver) {
eprintln!(
"Cannot export the project to {}: {}.",
path.display(),
join_nested(&e)
);
return ExitCode::FAILURE;
}
}
ProjectType::Library => {
// Create a directory to pack the package.
if let Err(e) = create_dir_all(&path) {
eprintln!("Cannot create {}: {}.", path.display(), e);
return ExitCode::FAILURE;
}

// Pack the package.
let path = path.join(format!("{}.npk", project.meta().package().name()));

if let Err(e) = pkg.pack(&path) {
eprintln!("Cannot pack {}: {}.", path.display(), join_nested(&e));
return ExitCode::FAILURE;
}
}
}
}

ExitCode::SUCCESS
}

Expand Down
12 changes: 12 additions & 0 deletions stage0/src/pkg/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pub use self::meta::*;
pub use self::target::*;
pub use self::ty::*;

use crate::dep::DepResolver;
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use thiserror::Error;
Expand Down Expand Up @@ -40,6 +41,13 @@ impl Package {
todo!()
}

pub fn export<T>(&self, to: T, resolver: &mut DepResolver) -> Result<(), PackageExportError>
where
T: AsRef<Path>,
{
todo!()
}

pub fn unpack<F, T>(file: F, to: T) -> Result<(), PackageUnpackError>
where
F: AsRef<Path>,
Expand All @@ -57,6 +65,10 @@ pub enum PackageOpenError {}
#[derive(Debug, Error)]
pub enum PackagePackError {}

/// Represents an error when a package is failed to export.
#[derive(Debug, Error)]
pub enum PackageExportError {}

/// Represents an error when a package is failed to unpack.
#[derive(Debug, Error)]
pub enum PackageUnpackError {}
28 changes: 24 additions & 4 deletions stage0/src/project/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,36 @@ use serde::Deserialize;
/// Contains information that was loaded from `.nitro` file.
#[derive(Deserialize)]
pub struct ProjectMeta {
pub package: ProjectPackage,
package: ProjectPackage,
}

impl ProjectMeta {
pub fn package(&self) -> &ProjectPackage {
&self.package
}
}

/// A package table of `.nitro` file.
#[derive(Deserialize)]
pub struct ProjectPackage {
pub name: String, // TODO: Only allow identifier.
name: String, // TODO: Only allow identifier.
#[serde(rename = "type")]
pub ty: ProjectType,
pub version: PackageVersion,
ty: ProjectType,
version: PackageVersion,
}

impl ProjectPackage {
pub fn name(&self) -> &str {
self.name.as_ref()
}

pub fn ty(&self) -> ProjectType {
self.ty
}

pub fn version(&self) -> &PackageVersion {
&self.version
}
}

/// Type of the project.
Expand Down
58 changes: 36 additions & 22 deletions stage0/src/project/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
pub use self::meta::*;

use crate::ast::{ParseError, SourceFile};
use crate::codegen::{BuildError, Codegen, Resolver};
use crate::codegen::{BuildError, Codegen, TypeResolver};
use crate::dep::DepResolver;
use crate::lexer::SyntaxError;
use crate::pkg::{Architecture, Library, OperatingSystem, Package, PackageMeta, Target};
use std::borrow::Cow;
use std::collections::{BTreeMap, HashMap, VecDeque};
use std::collections::{HashMap, VecDeque};
use std::error::Error;
use std::ffi::{c_char, CStr, CString};
use std::fmt::{Display, Formatter};
Expand All @@ -17,14 +18,18 @@ use thiserror::Error;
mod meta;

/// A Nitro project.
pub struct Project {
pub struct Project<'a> {
path: PathBuf,
meta: ProjectMeta,
sources: BTreeMap<String, SourceFile>,
sources: HashMap<String, SourceFile>,
resolver: &'a mut DepResolver,
}

impl Project {
pub fn open<P: Into<PathBuf>>(path: P) -> Result<Self, ProjectOpenError> {
impl<'a> Project<'a> {
pub fn open<P: Into<PathBuf>>(
path: P,
resolver: &'a mut DepResolver,
) -> Result<Self, ProjectOpenError> {
// Read the project.
let path = path.into();
let project = path.join(".nitro");
Expand All @@ -42,14 +47,23 @@ impl Project {
Ok(Self {
path,
meta,
sources: BTreeMap::new(),
sources: HashMap::new(),
resolver,
})
}

pub fn path(&self) -> &Path {
&self.path
}

pub fn artifacts(&self) -> PathBuf {
self.path.join(".build")
}

pub fn meta(&self) -> &ProjectMeta {
&self.meta
}

pub fn load(&mut self) -> Result<(), ProjectLoadError> {
// Enumerate all project files.
let mut jobs = VecDeque::from([self.path.clone()]);
Expand Down Expand Up @@ -95,7 +109,7 @@ impl Project {

pub fn build(&self) -> Result<Package, ProjectBuildError> {
// Setup type resolver.
let mut resolver: Resolver<'_> = Resolver::new();
let mut resolver = TypeResolver::new();

resolver.populate_project_types(&self.sources);

Expand All @@ -116,8 +130,8 @@ impl Project {
}

// Setup metadata.
let pkg = &self.meta.package;
let meta = PackageMeta::new(pkg.name.clone(), pkg.version.clone());
let pkg = self.meta.package();
let meta = PackageMeta::new(pkg.name().to_owned(), pkg.version().clone());

Ok(Package::new(meta, exes, libs))
}
Expand Down Expand Up @@ -163,15 +177,15 @@ impl Project {
fn build_for(
&self,
target: &Target,
resolver: &Resolver<'_>,
resolver: &TypeResolver<'_>,
) -> Result<BuildOutputs, ProjectBuildError> {
// Setup codegen context.
let pkg = &self.meta.package;
let pkg = self.meta.package();
let mut cx = Codegen::new(
&pkg.name,
&pkg.version,
pkg.name(),
pkg.version(),
&target,
CString::new(pkg.name.as_str()).unwrap(),
CString::new(pkg.name()).unwrap(),
resolver,
);

Expand All @@ -195,26 +209,26 @@ impl Project {
}

// Create output directory.
let mut outputs = self.path.join(".build");
let mut dir = self.artifacts();

outputs.push(target.to_llvm());
dir.push(target.to_llvm());

if let Err(e) = create_dir_all(&outputs) {
return Err(ProjectBuildError::CreateDirectoryFailed(outputs, e));
if let Err(e) = create_dir_all(&dir) {
return Err(ProjectBuildError::CreateDirectoryFailed(dir, e));
}

// Build the object file.
let obj = outputs.join(format!("{}.o", self.meta.package.name));
let obj = dir.join(format!("{}.o", self.meta.package().name()));

if let Err(e) = cx.build(&obj, false) {
return Err(ProjectBuildError::BuildFailed(obj, e));
}

// Prepare to link.
let mut args: Vec<Cow<'static, str>> = Vec::new();
let out = outputs.join(format!(
let out = dir.join(format!(
"{}.{}",
self.meta.package.name,
pkg.name(),
match target.os() {
OperatingSystem::Darwin => "dylib",
OperatingSystem::Linux => "so",
Expand Down

0 comments on commit 1035686

Please sign in to comment.