diff options
-rw-r--r-- | yapymake/makefile/__init__.py | 82 | ||||
-rw-r--r-- | yapymake/makefile/token.py | 6 |
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) |