Skip to content

Commit

Permalink
Build scripts, stable
Browse files Browse the repository at this point in the history
* Fix tests failing to compile properly (used take_while instead of filter :p)

* Added support for build scripts, which will prompt the user for permission before running. This is a simple `build.c` file at the top level of your project. Currently the only "command" it has is to set the `src` directory, for the case of preprocessing.

* Removed redundant use of const blocks, since const assignments already allowed constant blocks expressions. Also removed the blocks entirely and just opted for more generic errors.
  • Loading branch information
DvvCz committed Jun 3, 2024
1 parent ec115eb commit 8c78685
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 64 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "cpkg"
description = "A dead simple C package manager."
version = "0.11.0"
version = "0.12.0"
edition = "2021"

authors = ["David Cruz <[email protected]>"]
Expand Down
17 changes: 1 addition & 16 deletions src/components/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,20 +104,5 @@ pub fn try_locate(proj: Option<&crate::Project>) -> anyhow::Result<Box<dyn Compi
}
}

/* todo: cleaner impl when const for / const iterators exist */
const SUPPORTED_NAMES: &[&str] = &const {
let mut i = 0;
let mut arr = [""; SUPPORTED.len()];
while i < SUPPORTED.len() {
arr[i] = SUPPORTED[i].0;
i += 1;
}

arr
};

Err(anyhow::anyhow!(
"Couldn't find {}",
SUPPORTED_NAMES.join(" or ")
))
Err(anyhow::anyhow!("Couldn't find a compiler backend."))
}
17 changes: 1 addition & 16 deletions src/components/docgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,20 +122,5 @@ pub fn try_locate(proj: &crate::Project) -> anyhow::Result<Box<dyn Docgen>> {
}
}

/* todo: cleaner impl when const for / const iterators exist */
const SUPPORTED_NAMES: &[&str] = &const {
let mut i = 0;
let mut arr = [""; SUPPORTED.len()];
while i < SUPPORTED.len() {
arr[i] = SUPPORTED[i].0;
i += 1;
}

arr
};

Err(anyhow::anyhow!(
"Couldn't find {}",
SUPPORTED_NAMES.join(" or ")
))
Err(anyhow::anyhow!("Couldn't find a docgen backend"))
}
17 changes: 1 addition & 16 deletions src/components/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,6 @@ const SUPPORTED: &[(&'static str, fn() -> Box<dyn Format>)] = &[
( "uncrustify", || Box::new(Uncrustify) )
];

/* todo: cleaner impl when const for / const iterators exist */
const SUPPORTED_NAMES: &[&str] = &const {
let mut i = 0;
let mut arr = [""; SUPPORTED.len()];
while i < SUPPORTED.len() {
arr[i] = SUPPORTED[i].0;
i += 1;
}

arr
};

/// Tries to find an available C formatter
/// Currently only supports clang-format.
pub fn try_locate(proj: &crate::Project) -> anyhow::Result<Box<dyn Format>> {
Expand Down Expand Up @@ -106,8 +94,5 @@ pub fn try_locate(proj: &crate::Project) -> anyhow::Result<Box<dyn Format>> {
}
}

Err(anyhow::anyhow!(
"Couldn't find {}",
SUPPORTED_NAMES.join(" or ")
))
Err(anyhow::anyhow!("Couldn't find a formatting backend"))
}
34 changes: 27 additions & 7 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ use project::*;
mod config;
use config::*;

fn build_script_check() -> bool {
println!("This project needs a build script to run. Accept? (y/n)");

let mut s = String::new();
std::io::stdin().read_line(&mut s).unwrap();

s.find("y").is_some()
}

fn main() -> anyhow::Result<()> {
let args: cli::Cli = clap::Parser::parse();
let cd = std::env::current_dir()?;
Expand Down Expand Up @@ -60,7 +69,11 @@ fn main() -> anyhow::Result<()> {

let now = std::time::Instant::now();

proj.build(compiler::try_locate(Some(&proj))?.as_ref(), bin)?;
proj.build(
compiler::try_locate(Some(&proj))?.as_ref(),
bin,
build_script_check,
)?;

println!(
"Successfully built program(s) in {}s",
Expand Down Expand Up @@ -112,7 +125,11 @@ fn main() -> anyhow::Result<()> {
}

let proj = proj?;
let out = proj.build(compiler::try_locate(Some(&proj))?.as_ref(), bin)?;
let out = proj.build(
compiler::try_locate(Some(&proj))?.as_ref(),
bin,
build_script_check,
)?;

std::process::Command::new(out).spawn()?;
}
Expand Down Expand Up @@ -239,9 +256,7 @@ fn main() -> anyhow::Result<()> {
.tempfile()?
.into_temp_path();

let temp_bin = tempfile::Builder::new()
.tempfile()?
.into_temp_path();
let temp_bin = tempfile::Builder::new().tempfile()?.into_temp_path();

let mut stdout = std::io::stdout().lock();
let mut buffer = String::new();
Expand All @@ -265,7 +280,12 @@ fn main() -> anyhow::Result<()> {
"#)
)?;

match backend.compile(&[temp_repl.to_path_buf()], &[], &temp_bin, &["-w".to_owned(), "-fdiagnostics-color=always".to_owned()]) {
match backend.compile(
&[temp_repl.to_path_buf()],
&[],
&temp_bin,
&["-w".to_owned(), "-fdiagnostics-color=always".to_owned()],
) {
Ok(_) => {
let mut out = std::process::Command::new(&temp_bin).output()?;

Expand All @@ -289,7 +309,7 @@ fn main() -> anyhow::Result<()> {
}
Err(e) => {
print!("{e}");
},
}
}
}
}
Expand Down
58 changes: 50 additions & 8 deletions src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ impl<'a> Project<'a> {
/// Folder containing test files
const TESTS: &'static str = "tests";

/// Prefix for build commands
const BUILD_COMMAND_PREFIX: &'static str = "cpkg::";

/*
Paths
*/
Expand Down Expand Up @@ -291,8 +294,8 @@ impl<'a> Project<'a> {
inline_tests.chain(explicit_tests)
}

pub fn c_files(&self) -> impl std::iter::Iterator<Item = std::path::PathBuf> {
walkdir::WalkDir::new(self.src())
pub fn c_files(&self, src: impl AsRef<std::path::Path>) -> impl std::iter::Iterator<Item = std::path::PathBuf> {
walkdir::WalkDir::new(src)
.into_iter()
.flat_map(std::convert::identity)
.filter(|e| e.path().is_file())
Expand Down Expand Up @@ -344,18 +347,57 @@ impl<'a> Project<'a> {
&self,
backend: &dyn crate::compiler::Compiler,
entrypoint: &Option<String>,
can_run_build: impl FnOnce() -> bool,
) -> anyhow::Result<std::path::PathBuf> {
let src = self.src();
let mut src = self.src();

if !self.target().exists() {
std::fs::create_dir(self.target())?;
}

let build_c = self.path.join("build.c");
if build_c.exists() {
if can_run_build() {
let t = tempfile::Builder::new().tempfile()?.into_temp_path();

backend.compile(&[build_c], &[], &t, &[])?;

let out = std::process::Command::new(&t).output()?;

if !out.status.success() {
anyhow::bail!(
"Build script failed: {}",
String::from_utf8_lossy(&out.stderr)
);
}

let out = String::from_utf8_lossy(&out.stdout);
let mut ptr = 0;

while let Some(r) = out[ptr..].find(Self::BUILD_COMMAND_PREFIX) {
let cmd = out[r..].split_once(" \t\n").map(|p| p.0).unwrap_or(&out[r..]);
let cmd = &cmd[Self::BUILD_COMMAND_PREFIX.len()..];

if cmd.starts_with("set_src") {
if let Some((_, to)) = cmd.split_once('=') {
src = std::env::current_dir()?.join(to.trim());
}
}

ptr = r + 1;
}
} else {
anyhow::bail!(
"This project requires a build script to run, but was not permitted to run it."
);
}
}

if let Some(entrypoint) = entrypoint {
let entrypoint = src.join(entrypoint).with_extension("c");
let out = self.build_out(Some(&entrypoint));

let mut c_files = self.c_files().collect::<Vec<_>>();
let mut c_files = self.c_files(&src).collect::<Vec<_>>();
if let Some(pos) = c_files.iter().position(|p| **p == entrypoint) {
/* Swap to beginning, so that its main is registered first by linker. */
c_files.swap(pos, 0);
Expand All @@ -366,7 +408,7 @@ impl<'a> Project<'a> {
let mut flags = self.build_flags(backend).to_vec();
flags.push("-zmuldefs".to_owned()); /* Tell linker to allow multiple entrypoints, taking first encountered */

backend.compile(&c_files, &[&self.vendor(), &src], &out, &flags)?;
backend.compile(&c_files, &[&src, &self.vendor()], &out, &flags)?;

Ok(out)
} else {
Expand All @@ -375,7 +417,7 @@ impl<'a> Project<'a> {
let out = self.build_out(None);

if main.exists() {
let c_files = self.c_files().collect::<Vec<_>>();
let c_files = self.c_files(&src).collect::<Vec<_>>();
let flags = self.build_flags(backend);

backend.compile(&c_files, &[&self.vendor(), &src], &out, &flags)?;
Expand All @@ -398,8 +440,8 @@ impl<'a> Project<'a> {
let src = self.src();

let mut c_files = self
.c_files()
.take_while(|f| f.file_name().unwrap() != "main.c")
.c_files(&src)
.filter(|f| f.file_name().unwrap() != "main.c")
.collect::<Vec<_>>();

let out_dir = Self::get_or_mkdir(Self::get_or_mkdir(self.target())?.join("test"))?;
Expand Down

0 comments on commit 8c78685

Please sign in to comment.