aboutsummaryrefslogtreecommitdiff
path: root/src/makefile/mod.rs
diff options
context:
space:
mode:
authorMelody Horn <melody@boringcactus.com>2021-04-03 11:29:04 -0600
committerMelody Horn <melody@boringcactus.com>2021-04-03 11:29:04 -0600
commit31a35ac86e41a698a5eafcc0b4cbfa64e2066c39 (patch)
treefdbea361b69eba7683b09d32e0a31ec4e9b33110 /src/makefile/mod.rs
parent2d87ed9a4dc8554bff082c97335b2a48659c7381 (diff)
downloadmakers-31a35ac86e41a698a5eafcc0b4cbfa64e2066c39.tar.gz
makers-31a35ac86e41a698a5eafcc0b4cbfa64e2066c39.zip
correctly handle conditional lines inside rule body
Diffstat (limited to 'src/makefile/mod.rs')
-rw-r--r--src/makefile/mod.rs129
1 files changed, 128 insertions, 1 deletions
diff --git a/src/makefile/mod.rs b/src/makefile/mod.rs
index 7904d08..88a3abb 100644
--- a/src/makefile/mod.rs
+++ b/src/makefile/mod.rs
@@ -22,9 +22,10 @@ mod pattern;
mod target;
mod token;
+use command_line::CommandLine;
use inference_rules::InferenceRule;
pub use input::MakefileReader;
-use r#macro::Set as MacroSet;
+use r#macro::{Set as MacroSet, Source as MacroSource};
use target::Target;
use token::TokenString;
@@ -38,6 +39,56 @@ pub struct Makefile<'a> {
}
impl<'a> Makefile<'a> {
+ pub fn new(args: &'a Args) -> Self {
+ let mut inference_rules = vec![];
+ let mut macros = MacroSet::new();
+ let mut targets = HashMap::new();
+ let first_non_special_target = None;
+
+ if !args.no_builtin_rules {
+ inference_rules.extend(builtin_inference_rules());
+ macros.add_builtins();
+ targets.extend(
+ builtin_targets()
+ .into_iter()
+ .map(|t| (t.name.clone(), Rc::new(RefCell::new(t)))),
+ );
+ }
+
+ macros.add_env();
+
+ for r#macro in args.macros() {
+ if let [name, value] = *r#macro.splitn(2, '=').collect::<Vec<_>>() {
+ macros.set(
+ name.into(),
+ MacroSource::CommandLineOrMakeflags,
+ TokenString::text(value),
+ );
+ }
+ }
+
+ Makefile {
+ inference_rules,
+ macros,
+ targets: RefCell::new(targets),
+ first_non_special_target,
+ args,
+ }
+ }
+
+ pub fn extend<R: std::io::BufRead>(&mut self, new: MakefileReader<R>) {
+ self.inference_rules.extend(new.inference_rules);
+ self.macros.extend(new.macros);
+ self.targets.borrow_mut().extend(
+ new.targets
+ .into_iter()
+ .map(|(k, v)| (k, Rc::new(RefCell::new(v)))),
+ );
+ if self.first_non_special_target.is_none() {
+ self.first_non_special_target = new.first_non_special_target;
+ }
+ }
+
fn special_target_has_prereq(&self, target: &str, name: &str) -> bool {
let targets = self.targets.borrow();
match targets.get(target) {
@@ -247,3 +298,79 @@ impl fmt::Display for Makefile<'_> {
Ok(())
}
}
+
+fn builtin_inference_rules() -> Vec<InferenceRule> {
+ // This is a terrible idea.
+ macro_rules! prepend_dot {
+ ($x:tt) => {
+ concat!(".", stringify!($x))
+ };
+ () => {
+ ""
+ };
+ }
+
+ macro_rules! make {
+ {$(.$first:tt$(.$second:tt)?:
+ $($cmd:literal)+)+} => {
+ vec![$(
+ InferenceRule {
+ product: prepend_dot!($($second)?).into(),
+ prereq: concat!(".", stringify!($first)).into(),
+ commands: vec![$(CommandLine::from($cmd.parse().unwrap())),+],
+ }
+ ),+]
+ };
+ }
+
+ make! {
+ .c:
+ "$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<"
+ .f:
+ "$(FC) $(FFLAGS) $(LDFLAGS) -o $@ $<"
+ .sh:
+ "cp $< $@"
+ "chmod a+x $@"
+
+ .c.o:
+ "$(CC) $(CFLAGS) -c $<"
+ .f.o:
+ "$(FC) $(FFLAGS) -c $<"
+ .y.o:
+ "$(YACC) $(YFLAGS) $<"
+ "$(CC) $(CFLAGS) -c y.tab.c"
+ "rm -f y.tab.c"
+ "mv y.tab.o $@"
+ .l.o:
+ "$(LEX) $(LFLAGS) $<"
+ "$(CC) $(CFLAGS) -c lex.yy.c"
+ "rm -f lex.yy.c"
+ "mv lex.yy.o $@"
+ .y.c:
+ "$(YACC) $(YFLAGS) $<"
+ "mv y.tab.c $@"
+ .l.c:
+ "$(LEX) $(LFLAGS) $<"
+ "mv lex.yy.c $@"
+ .c.a:
+ "$(CC) -c $(CFLAGS) $<"
+ "$(AR) $(ARFLAGS) $@ $*.o"
+ "rm -f $*.o"
+ .f.a:
+ "$(FC) -c $(FFLAGS) $<"
+ "$(AR) $(ARFLAGS) $@ $*.o"
+ "rm -f $*.o"
+ }
+}
+fn builtin_targets() -> Vec<Target> {
+ // even i'm not going to do that just for this
+ vec![Target {
+ name: ".SUFFIXES".into(),
+ prerequisites: vec![".o", ".c", ".y", ".l", ".a", ".sh", ".f"]
+ .into_iter()
+ .map(String::from)
+ .collect(),
+ commands: vec![],
+ already_updated: Cell::new(false),
+ }]
+}