aboutsummaryrefslogtreecommitdiff
path: root/src/makefile/mod.rs
diff options
context:
space:
mode:
authorMelody Horn <melody@boringcactus.com>2021-04-03 18:01:04 -0600
committerMelody Horn <melody@boringcactus.com>2021-04-03 18:01:04 -0600
commitf73d0b2256f2afc05995929c930b2eeab6800ecf (patch)
tree8c580ae21e50a5d3c166a568bbc5955ffcb341ad /src/makefile/mod.rs
parent7c2a09e5c75d87d5dd728623517899ca7cada630 (diff)
downloadmakers-f73d0b2256f2afc05995929c930b2eeab6800ecf.tar.gz
makers-f73d0b2256f2afc05995929c930b2eeab6800ecf.zip
implement GNUish '%'-based inference rules
Diffstat (limited to 'src/makefile/mod.rs')
-rw-r--r--src/makefile/mod.rs62
1 files changed, 37 insertions, 25 deletions
diff --git a/src/makefile/mod.rs b/src/makefile/mod.rs
index 3d824b9..225ff55 100644
--- a/src/makefile/mod.rs
+++ b/src/makefile/mod.rs
@@ -2,7 +2,7 @@ use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::env;
use std::fmt;
-use std::path::Path;
+use std::path::{Path, PathBuf};
use std::rc::Rc;
use eyre::{eyre, Result};
@@ -103,7 +103,7 @@ impl<'a> Makefile<'a> {
pub fn get_target(&self, name: &str) -> Result<Rc<RefCell<Target>>> {
// TODO implement .POSIX
- let follow_gnu = true;
+ let follow_gnu = cfg!(feature = "full");
let vpath_options = match self.macros.get("VPATH") {
Some((_, vpath)) if follow_gnu => {
@@ -113,16 +113,16 @@ impl<'a> Makefile<'a> {
_ => vec![],
};
- let targets = self.targets.borrow();
let mut new_target = None;
let exists_but_infer_anyway = if follow_gnu {
- targets
+ self.targets
+ .borrow()
.get(name)
.map_or(false, |target| target.borrow().commands.is_empty())
} else {
false
};
- if !targets.contains_key(name) || exists_but_infer_anyway {
+ if !self.targets.borrow().contains_key(name) || exists_but_infer_anyway {
// When no target rule is found to update a target, the inference rules shall
// be checked. The suffix of the target to be built...
let suffix = Path::new(name)
@@ -132,39 +132,51 @@ impl<'a> Makefile<'a> {
// targets. If the .s1 suffix is found in .SUFFIXES...
if self.special_target_has_prereq(".SUFFIXES", &suffix) || suffix.is_empty() {
// the inference rules shall be searched in the order defined...
- 'rules: for rule in self
+ // TODO implement GNUish shortest-stem-first matching
+ let inference_rule_candidates = self
.inference_rules
.iter()
- // for the first .s2.s1 rule...
- .filter(|rule| rule.product == suffix)
- {
+ .filter(|rule| rule.matches(name).unwrap_or(false));
+ for rule in inference_rule_candidates {
// whose prerequisite file ($*.s2) exists.
- let prereq_path =
- Path::new(name).with_extension(rule.prereq.trim_start_matches('.'));
- if let Some(prereq) = std::iter::once(prereq_path.clone())
- .chain(
- if prereq_path.is_absolute() {
+ let prereq_paths = rule
+ .prereqs(name)?
+ .map(|prereq_path_name| {
+ if name == prereq_path_name {
+ // we can't build this based on itself! fuck outta here
+ return None;
+ }
+ if self.get_target(&prereq_path_name).is_ok() {
+ return Some(prereq_path_name);
+ }
+ let prereq_path = PathBuf::from(prereq_path_name);
+ let prereq_vpath_options = if prereq_path.is_absolute() {
None
} else {
Some(vpath_options.iter().map(|vpath| vpath.join(&prereq_path)))
}
.into_iter()
- .flatten(),
- )
- .find(|prereq| prereq.exists())
- {
+ .flatten();
+ std::iter::once(prereq_path.clone())
+ .chain(prereq_vpath_options)
+ .find(|prereq| prereq.exists())
+ .map(|path| path.to_string_lossy().to_string())
+ })
+ .collect::<Option<Vec<String>>>();
+ if let Some(prereqs) = prereq_paths {
new_target = Some(Target {
name: name.into(),
- prerequisites: vec![prereq.to_string_lossy().into()],
+ prerequisites: prereqs,
commands: rule.commands.clone(),
already_updated: Cell::new(false),
});
- break 'rules;
+ break;
}
}
}
}
+ let targets = self.targets.borrow();
if !targets.contains_key(name) && new_target.is_none() {
// well, inference didn't work. is there a default?
if let Some(default) = targets.get(".DEFAULT") {
@@ -315,11 +327,11 @@ fn builtin_inference_rules() -> Vec<InferenceRule> {
{$(.$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())),+],
- }
+ InferenceRule::new_suffix(
+ prepend_dot!($($second)?).into(),
+ concat!(".", stringify!($first)).into(),
+ vec![$(CommandLine::from($cmd.parse().unwrap())),+],
+ )
),+]
};
}