aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--yapymake/makefile/__init__.py82
-rw-r--r--yapymake/makefile/token.py6
2 files changed, 79 insertions, 9 deletions
diff --git a/yapymake/makefile/__init__.py b/yapymake/makefile/__init__.py
index 051a9f9..1d262e8 100644
--- a/yapymake/makefile/__init__.py
+++ b/yapymake/makefile/__init__.py
@@ -31,11 +31,19 @@ class Makefile:
if args.builtin_rules:
self._inference_rules += BUILTIN_INFERENCE_RULES
self._macros.update(BUILTIN_MACROS)
- self._targets.update(BUILTIN_TARGETS)
+ for target in BUILTIN_TARGETS:
+ self._targets[target.name] = target
for k, v in os.environ.items():
if k not in ['MAKEFLAGS', 'SHELL']:
- self._macros[k] = (MacroSource.Environment, TokenString([TextToken(v)]))
+ self._macros[k] = (MacroSource.Environment, TokenString.text(v))
+
+ for target_or_macro in args.targets_or_macros:
+ if '=' in target_or_macro:
+ # it's a macro
+ name, value = target_or_macro.split('=', 1)
+ # TODO either discern command line vs MAKEFLAGS or don't pretend we can
+ self._macros[name] = (MacroSource.CommandLine, TokenString.text(value))
def read(self, file: TextIO):
lines_iter: PeekableIterator[str] = PeekableIterator(iter(file))
@@ -117,7 +125,10 @@ class Makefile:
for target in targets:
# > A target that has prerequisites, but does not have any commands, can be used to add to the
# > prerequisite list for that target.
- if target in self._targets and len(commands) == 0:
+ # but also
+ # > If .SUFFIXES does not have any prerequisites, the list of known suffixes shall be cleared.
+ if target in self._targets and len(commands) == 0 and \
+ not (target == '.SUFFIXES' and len(prerequisites) == 0):
self._targets[target].prerequisites += prerequisites
else:
self._targets[target] = Target(target, prerequisites, commands)
@@ -148,7 +159,7 @@ class Makefile:
continue
self._macros[name] = (MacroSource.File, value)
- def expand_macros(self, text: TokenString, current_target: Optional['Target']) -> str:
+ def expand_macros(self, text: TokenString, current_target: Optional['Target'] = None) -> str:
def expand_one(this_token: Token) -> str:
if isinstance(this_token, TextToken):
return this_token.text
@@ -182,7 +193,7 @@ class Makefile:
elif macro_name[1:] == 'F':
macro_value = [str(PurePath(x).name) for x in macro_value]
- macro_value = TokenString([TextToken(' '.join(macro_value))])
+ macro_value = TokenString.text(' '.join(macro_value))
else:
_, macro_value = self._macros[this_token.name]
macro_value = self.expand_macros(macro_value, current_target)
@@ -358,6 +369,61 @@ class CommandLine:
print('error!', file=sys.stderr)
sys.exit(1)
-BUILTIN_INFERENCE_RULES = []
-BUILTIN_MACROS = {}
-BUILTIN_TARGETS = {}
+BUILTIN_INFERENCE_RULES = [
+ InferenceRule('', '.c', [CommandLine(tokenize('$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<'))]),
+ InferenceRule('', '.f', [CommandLine(tokenize('$(FC) $(FFLAGS) $(LDFLAGS) -o $@ $<'))]),
+ InferenceRule('', '.sh', [
+ CommandLine(tokenize('cp $< $@')),
+ CommandLine(tokenize('chmod a+x $@'))
+ ]),
+
+ InferenceRule('.o', '.c', [CommandLine(tokenize('$(CC) $(CFLAGS) -c $<'))]),
+ InferenceRule('.o', '.f', [CommandLine(tokenize('$(FC) $(FFLAGS) -c $<'))]),
+ InferenceRule('.o', '.y', [
+ CommandLine(tokenize('$(YACC) $(YFLAGS) $<')),
+ CommandLine(tokenize('$(CC) $(CFLAGS) -c y.tab.c')),
+ CommandLine(tokenize('rm -f y.tab.c')),
+ CommandLine(tokenize('mv y.tab.o $@')),
+ ]),
+ InferenceRule('.o', '.l', [
+ CommandLine(tokenize('$(LEX) $(LFLAGS) $<')),
+ CommandLine(tokenize('$(CC) $(CFLAGS) -c lex.yy.c')),
+ CommandLine(tokenize('rm -f lex.yy.c')),
+ CommandLine(tokenize('mv lex.yy.o $@')),
+ ]),
+ InferenceRule('.c', '.y', [
+ CommandLine(tokenize('$(YACC) $(YFLAGS) $<')),
+ CommandLine(tokenize('mv y.tab.c $@')),
+ ]),
+ InferenceRule('.c', '.l', [
+ CommandLine(tokenize('$(LEX) $(LFLAGS) $<')),
+ CommandLine(tokenize('mv lex.yy.c $@')),
+ ]),
+ InferenceRule('.a', '.c', [
+ CommandLine(tokenize('$(CC) -c $(CFLAGS) $<')),
+ CommandLine(tokenize('$(AR) $(ARFLAGS) $@ $*.o')),
+ CommandLine(tokenize('rm -f $*.o')),
+ ]),
+ InferenceRule('.a', '.f', [
+ CommandLine(tokenize('$(FC) -c $(FFLAGS) $<')),
+ CommandLine(tokenize('$(AR) $(ARFLAGS) $@ $*.o')),
+ CommandLine(tokenize('rm -f $*.o')),
+ ]),
+]
+BUILTIN_MACROS = {
+ 'MAKE': TokenString.text('make'),
+ 'AR': TokenString.text('ar'),
+ 'ARFLAGS': TokenString.text('-rv'),
+ 'YACC': TokenString.text('yacc'),
+ 'YFLAGS': TokenString.text(''),
+ 'LEX': TokenString.text('lex'),
+ 'LFLAGS': TokenString.text(''),
+ 'LDFLAGS': TokenString.text(''),
+ 'CC': TokenString.text('c99'),
+ 'CFLAGS': TokenString.text('-O 1'),
+ 'FC': TokenString.text('fort77'),
+ 'FFLAGS': TokenString.text('-O 1'),
+}
+BUILTIN_TARGETS = [
+ Target('.SUFFIXES', ['.o', '.c', '.y', '.l', '.a', '.sh', '.f'], []),
+]
diff --git a/yapymake/makefile/token.py b/yapymake/makefile/token.py
index bd673f7..a0c3f8f 100644
--- a/yapymake/makefile/token.py
+++ b/yapymake/makefile/token.py
@@ -17,6 +17,10 @@ class TokenString(Iterable['Token']):
my_tokens = []
self._tokens = my_tokens
+ @staticmethod
+ def text(body: str) -> 'TokenString':
+ return TokenString([TextToken(body)])
+
def __eq__(self, other) -> bool:
return isinstance(other, TokenString) and self._tokens == other._tokens
@@ -91,7 +95,7 @@ def single_token(until: Optional[str] = None) -> Parser[Token]:
text = text_until(until)
return alt(text, macro_expansion)
-empty_tokens = map_parser(tag(''), lambda _: TokenString([TextToken('')]))
+empty_tokens = map_parser(tag(''), lambda _: TokenString.text(''))
def tokens(until: Optional[str] = None) -> Parser[TokenString]:
return alt(map_parser(many1(single_token(until)), TokenString), empty_tokens)