Skip to content

Commit 564cff4

Browse files
committed
[make] full implementation
1 parent 1ff9575 commit 564cff4

File tree

34 files changed

+2699
-140
lines changed

34 files changed

+2699
-140
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ members = [
99
"display",
1010
"file",
1111
"fs",
12+
"ftw",
1213
"make",
13-
"ftw",
1414
"m4",
1515
"m4/test-manager",
1616
"gettext-rs",

make/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ repository = "https://github.com/rustcoreutils/posixutils-rs.git"
99
[dependencies]
1010
plib = { path = "../plib" }
1111
clap.workspace = true
12+
libc.workspace = true
1213
gettext-rs.workspace = true
1314

1415
const_format = "0.2"
15-
makefile-lossless = "0.1"
16+
rowan = "0.15"
1617

1718
[[bin]]
1819
name = "make"

make/src/config.rs

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
// SPDX-License-Identifier: MIT
88
//
99

10+
use std::collections::{BTreeMap, BTreeSet};
11+
1012
/// Represents the configuration of the make utility
1113
#[derive(Debug, Clone, PartialEq, Eq)]
1214
pub struct Config {
@@ -18,16 +20,109 @@ pub struct Config {
1820
pub silent: bool,
1921
/// Whether to touch targets on execution
2022
pub touch: bool,
23+
/// Whether to replace macros within makefiles with envs
24+
pub env_macros: bool,
25+
/// Whether to quit without build
26+
pub quit: bool,
27+
/// Whether to keep going build targets and write info about errors stderr
28+
pub keep_going: bool,
29+
/// Whether to terminate on error
30+
pub terminate: bool,
31+
/// Whether to clear default_rules
32+
pub clear: bool,
33+
/// Whether to print macro definitions and target descriptions.
34+
pub print: bool,
35+
/// Whether to not delete interrupted files on async events.
36+
pub precious: bool,
37+
38+
pub rules: BTreeMap<String, BTreeSet<String>>,
2139
}
2240

23-
#[allow(clippy::derivable_impls)]
2441
impl Default for Config {
2542
fn default() -> Self {
2643
Self {
2744
ignore: false,
2845
dry_run: false,
2946
silent: false,
3047
touch: false,
48+
env_macros: false,
49+
keep_going: false,
50+
quit: false,
51+
clear: false,
52+
print: false,
53+
precious: false,
54+
terminate: true,
55+
rules: BTreeMap::from([
56+
(
57+
".SUFFIXES".to_string(),
58+
vec![
59+
".o", ".c", ".y", ".l", ".a", ".sh", ".c~", ".y~", ".l~", ".sh~",
60+
]
61+
.into_iter()
62+
.map(String::from)
63+
.collect(),
64+
),
65+
(
66+
".SCCS_GET".to_string(),
67+
BTreeSet::from([String::from("sccs $(SCCSFLAGS) get $(SCCSGETFLAGS) $@")]),
68+
),
69+
(
70+
".MACROS".to_string(),
71+
vec![
72+
"AR=ar",
73+
"ARFLAGS=-rv",
74+
"YACC=yacc",
75+
"YFLAGS=",
76+
"LEX=lex",
77+
"LFLAGS=",
78+
"LDFLAGS=",
79+
"CC=c17",
80+
"CFLAGS=-O 1",
81+
"XSI GET=get",
82+
"GFLAGS=",
83+
"SCCSFLAGS=",
84+
"SCCSGETFLAGS=-s",
85+
]
86+
.into_iter()
87+
.map(String::from)
88+
.collect(),
89+
),
90+
(
91+
"SUFFIX RULES".to_string(),
92+
[
93+
// Single-Suffix Rules
94+
".c: $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<",
95+
".sh: cp $< $@",
96+
".sh: chmod a+x $@",
97+
98+
// Double-Suffix Rules
99+
".c.o: $(CC) $(CFLAGS) -c $<",
100+
".y.o: $(YACC) $(YFLAGS) $<; $(CC) $(CFLAGS) -c y.tab.c; rm -f y.tab.c; mv y.tab.o $@",
101+
".l.o: $(LEX) $(LFLAGS) $<; $(CC) $(CFLAGS) -c lex.yy.c; rm -f lex.yy.c; mv lex.yy.o $@",
102+
".y.c: $(YACC) $(YFLAGS) $<; mv y.tab.c $@",
103+
".l.c: $(LEX) $(LFLAGS) $<; mv lex.yy.c $@",
104+
"XSI .c~.o: $(GET) $(GFLAGS) -p $< > $*.c; $(CC) $(CFLAGS) -c $*.c",
105+
".y~.o: $(GET) $(GFLAGS) -p $< > $*.y; $(YACC) $(YFLAGS) $*.y; $(CC) $(CFLAGS) -c y.tab.c; rm -f y.tab.c; mv y.tab.o $@",
106+
".l~.o: $(GET) $(GFLAGS) -p $< > $*.l; $(LEX) $(LFLAGS) $*.l; $(CC) $(CFLAGS) -c lex.yy.c; rm -f lex.yy.c; mv lex.yy.o $@",
107+
".y~.c: $(GET) $(GFLAGS) -p $< > $*.y; $(YACC) $(YFLAGS) $*.y; mv y.tab.c $@",
108+
".l~.c: $(GET) $(GFLAGS) -p $< > $*.l; $(LEX) $(LFLAGS) $*.l; mv lex.yy.c $@",
109+
".c.a: $(CC) -c $(CFLAGS) $<; $(AR) $(ARFLAGS) $@ $*.o; rm -f $*.o",
110+
]
111+
.into_iter()
112+
.map(String::from)
113+
.collect::<BTreeSet<String>>(),
114+
)
115+
]),
31116
}
32117
}
33118
}
119+
120+
impl Config {
121+
/// Adds a new suffix to the `.SUFFIXES` rule.
122+
pub fn add_suffix(&mut self, new_suffix: &str) {
123+
self.rules
124+
.entry(".SUFFIXES".to_string())
125+
.or_default()
126+
.insert(new_suffix.to_string());
127+
}
128+
}

make/src/error_code.rs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,21 @@
1010
use core::fmt;
1111
use std::io;
1212

13-
use gettextrs::gettext;
14-
13+
use crate::parser::parse::ParseError;
1514
use crate::special_target::Error;
15+
use gettextrs::gettext;
1616

1717
/// Represents the error codes that can be returned by the make utility
1818
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1919
pub enum ErrorCode {
2020
// Transparent
2121
ExecutionError { exit_code: Option<i32> },
2222
IoError(io::ErrorKind),
23-
// for now just a string, in future `makefile_lossless::parse::ParseError` must be used (now it
24-
// is private)
25-
ParseError(String),
23+
ParserError { constraint: ParseError },
2624

2725
// Specific
2826
NoMakefile,
27+
NotUpToDateError { target: String },
2928
NoTarget { target: Option<String> },
3029
NoRule { rule: String },
3130
RecursivePrerequisite { origin: String },
@@ -38,19 +37,21 @@ impl From<ErrorCode> for i32 {
3837
}
3938
}
4039

40+
// todo: tests error codes
4141
impl From<&ErrorCode> for i32 {
4242
fn from(err: &ErrorCode) -> i32 {
4343
use ErrorCode::*;
4444

4545
match err {
46-
ExecutionError { .. } => 1,
47-
IoError(_) => 2,
48-
ParseError(_) => 3,
49-
NoMakefile => 4,
50-
NoTarget { .. } => 5,
51-
NoRule { .. } => 6,
52-
RecursivePrerequisite { .. } => 7,
53-
SpecialTargetConstraintNotFulfilled { .. } => 8,
46+
NotUpToDateError { .. } => 1,
47+
ExecutionError { .. } => 2,
48+
IoError(_) => 3,
49+
ParserError { .. } => 4,
50+
NoMakefile => 5,
51+
NoTarget { .. } => 6,
52+
NoRule { .. } => 7,
53+
RecursivePrerequisite { .. } => 8,
54+
SpecialTargetConstraintNotFulfilled { .. } => 9,
5455
}
5556
}
5657
}
@@ -60,6 +61,9 @@ impl fmt::Display for ErrorCode {
6061
use ErrorCode::*;
6162

6263
match self {
64+
NotUpToDateError { target } => {
65+
write!(f, "{}: {}", target, gettext("target is not up to date"))
66+
}
6367
ExecutionError { exit_code } => match exit_code {
6468
Some(exit_code) => {
6569
write!(f, "{}: {}", gettext("execution error"), exit_code)
@@ -75,7 +79,7 @@ impl fmt::Display for ErrorCode {
7579
},
7680
IoError(err) => write!(f, "{}: {}", gettext("io error"), err),
7781
NoMakefile => write!(f, "{}", gettext("no makefile")),
78-
ParseError(err) => write!(f, "{}: {}", gettext("parse error"), err),
82+
ParserError { constraint } => write!(f, "{}: {}", gettext("parse error"), constraint),
7983
NoTarget { target } => match target {
8084
Some(target) => write!(f, "{} '{}'", gettext("no target"), target),
8185
None => write!(f, "{}", gettext("no targets to execute")),

make/src/lib.rs

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,20 @@
99

1010
pub mod config;
1111
pub mod error_code;
12+
pub mod parser;
1213
pub mod rule;
14+
pub mod signal_handler;
1315
pub mod special_target;
1416

15-
use std::{collections::HashSet, fs, time::SystemTime};
17+
use std::{
18+
collections::HashSet,
19+
fs::{self},
20+
time::SystemTime,
21+
};
1622

17-
use makefile_lossless::{Makefile, VariableDefinition};
23+
use parser::{Makefile, VariableDefinition};
1824

25+
use crate::special_target::InferenceTarget;
1926
use config::Config;
2027
use error_code::ErrorCode::{self, *};
2128
use rule::{prerequisite::Prerequisite, target::Target, Rule};
@@ -29,12 +36,11 @@ const DEFAULT_SHELL: &str = "/bin/sh";
2936

3037
/// Represents the make utility with its data and configuration.
3138
///
32-
/// The only way to create a `Make` is from a `Makefile` and a `Config`.
39+
/// The only way to create a Make is from a Makefile and a Config.
3340
pub struct Make {
3441
macros: Vec<VariableDefinition>,
3542
rules: Vec<Rule>,
3643
default_rule: Option<Rule>, // .DEFAULT
37-
3844
pub config: Config,
3945
}
4046

@@ -43,8 +49,8 @@ impl Make {
4349
///
4450
/// # Returns
4551
///
46-
/// - `Some(rule)` if a rule with the target exists.
47-
/// - `None` if no rule with the target exists.
52+
/// - Some(rule) if a rule with the target exists.
53+
/// - None if no rule with the target exists.
4854
fn rule_by_target_name(&self, target: impl AsRef<str>) -> Option<&Rule> {
4955
self.rules
5056
.iter()
@@ -59,9 +65,9 @@ impl Make {
5965
/// Builds the target with the given name.
6066
///
6167
/// # Returns
62-
/// - `Ok(true)` if the target was built.
63-
/// - `Ok(false)` if the target was already up to date.
64-
/// - `Err(_)` if any errors occur.
68+
/// - Ok(true) if the target was built.
69+
/// - Ok(false) if the target was already up to date.
70+
/// - Err(_) if any errors occur.
6571
pub fn build_target(&self, name: impl AsRef<str>) -> Result<bool, ErrorCode> {
6672
let rule = match self.rule_by_target_name(&name) {
6773
Some(rule) => rule,
@@ -82,9 +88,9 @@ impl Make {
8288
/// Runs the given rule.
8389
///
8490
/// # Returns
85-
/// - Ok(`true`) if the rule was run.
86-
/// - Ok(`false`) if the rule was already up to date.
87-
/// - `Err(_)` if any errors occur.
91+
/// - Ok(true) if the rule was run.
92+
/// - Ok(false) if the rule was already up to date.
93+
/// - Err(_) if any errors occur.
8894
fn run_rule_with_prerequisites(&self, rule: &Rule, target: &Target) -> Result<bool, ErrorCode> {
8995
if self.are_prerequisites_recursive(target) {
9096
return Err(RecursivePrerequisite {
@@ -93,15 +99,19 @@ impl Make {
9399
}
94100

95101
let newer_prerequisites = self.get_newer_prerequisites(target);
96-
if newer_prerequisites.is_empty() && get_modified_time(target).is_some() {
102+
let mut up_to_date = newer_prerequisites.is_empty() && get_modified_time(target).is_some();
103+
if rule.config.phony {
104+
up_to_date = false;
105+
}
106+
107+
if up_to_date {
97108
return Ok(false);
98109
}
99110

100-
for prerequisite in newer_prerequisites {
111+
for prerequisite in &newer_prerequisites {
101112
self.build_target(prerequisite)?;
102113
}
103-
104-
rule.run(&self.config, &self.macros, target)?;
114+
rule.run(&self.config, &self.macros, target, up_to_date)?;
105115

106116
Ok(true)
107117
}
@@ -134,7 +144,7 @@ impl Make {
134144
}
135145

136146
/// Checks if the target has recursive prerequisites.
137-
/// Returns `true` if the target has recursive prerequisites.
147+
/// Returns true if the target has recursive prerequisites.
138148
fn are_prerequisites_recursive(&self, target: impl AsRef<str>) -> bool {
139149
let mut visited = HashSet::from([target.as_ref()]);
140150
let mut stack = HashSet::from([target.as_ref()]);
@@ -176,13 +186,18 @@ impl TryFrom<(Makefile, Config)> for Make {
176186
fn try_from((makefile, config): (Makefile, Config)) -> Result<Self, Self::Error> {
177187
let mut rules = vec![];
178188
let mut special_rules = vec![];
189+
let mut inference_rules = vec![];
190+
179191
for rule in makefile.rules() {
180192
let rule = Rule::from(rule);
181193
let Some(target) = rule.targets().next() else {
182194
return Err(NoTarget { target: None });
183195
};
196+
184197
if SpecialTarget::try_from(target.clone()).is_ok() {
185198
special_rules.push(rule);
199+
} else if InferenceTarget::try_from((target.clone(), config.clone())).is_ok() {
200+
inference_rules.push(rule);
186201
} else {
187202
rules.push(rule);
188203
}

0 commit comments

Comments
 (0)