From b2981456916d334e5fed607f22d496809ba31d36 Mon Sep 17 00:00:00 2001 From: David Poole Date: Sun, 26 Jan 2025 15:52:13 -0800 Subject: [PATCH 1/2] fix problems found running GNU Make's makefile - fix list reference problem in adding recipes to rules - add a better message when tripping over a not yet implemented static pattern rule - also new argument --print-rule to dump the rule, unprocessed (no variable substitutions performed, unlike -n) --- pymake/pargs.py | 23 +++++++++++++++-------- pymake/pymake.py | 32 +++++++++++++++++++++++++++++--- pymake/rules.py | 8 +++++--- pymake/tokenizer.py | 2 +- 4 files changed, 50 insertions(+), 15 deletions(-) diff --git a/pymake/pargs.py b/pymake/pargs.py index 7d9a8dc..d50d9fa 100644 --- a/pymake/pargs.py +++ b/pymake/pargs.py @@ -50,10 +50,11 @@ def usage(): Write the Rules' dependency graph as a GraphViz dot file. (Work in progress.) --html FILE Write the Rules' dependency graph as an HTML file. (Work in progress.) - --explain Give a verbose error message for common GNU Make errors. --output FILE - Rewrite the parsed makefile to FILE. - -S Print the makefile as an S-Expression. (Useful for debugging pymake itself.) + Rewrite the parsed makefile to FILE. Do not execute. + --print-rule + Print the rule and recipes for the target. Do not execute. + -S Print the makefile as an S-Expression. (Useful for debugging pymake itself.) Do not execute. """) class Args: @@ -108,6 +109,9 @@ def __init__(self): # -s self.silent = False + # --print-rule + self.print_rule = False + self.warn_undefined_variables = False self.detailed_error_explain = False @@ -143,17 +147,18 @@ def parse_args(argv): "help", "always-make", "debug=", + "directory=", "dotfile=", - "html=", "explain", "file=", "makefile=", - "output=", + "html=", + "just-print", "dry-run", "recon", "no-builtin-rules", + "output=", + "print-rule", + "silent", "quiet" "version", "warn-undefined-variables", - "directory=", - "just-print", "dry-run", "recon", - "silent", "quiet" ] ) for opt in optlist: @@ -194,6 +199,8 @@ def parse_args(argv): args.silent = True elif opt[0] == '--debug': args.debug_flags = _parse_debug_flags(opt[1]) + elif opt[0] == '--print-rule': + args.print_rule = True else: # wtf? assert 0, opt diff --git a/pymake/pymake.py b/pymake/pymake.py index c9b85b0..f0bd6bf 100644 --- a/pymake/pymake.py +++ b/pymake/pymake.py @@ -44,6 +44,25 @@ def get_basename( filename ) : def _view(token_list): return "".join([str(t) for t in token_list]) +def print_rule_chain(rulesdb, target): + + try: + rule = rulesdb.get(target) + except KeyError: + error_message(None, "No rule to make target '%s'" % target) + return -1 + + print("# {}\n{}".format(rule.get_pos(), rule)) + print("{}".format(rule.recipe_list.makefile())) + + for t in rule.prereq_list: + try: + print_rule_chain(rulesdb, t) + except KeyError: + error_message(rule.get_pos(), "No rule to make prerequisite target '%s'" % t) + + return 0 + def _parse_one_vline(virt_line, vline_iter, rules): logger.debug("parse_vline() rules=%d", rules[0]) @@ -617,6 +636,7 @@ def execute(makefile, args): title = get_basename(makefile.get_pos()[0]) rulesdb.html_graph(title + "_makefile", args.htmlfile) print("wrote %s for html" % args.htmlfile) + return 0 try: if not target_list: @@ -625,6 +645,12 @@ def execute(makefile, args): error_message(makefile.get_pos(), "No targets" ) return exit_status["error"] + if args.print_rule: + for target in target_list: + print_rule_chain(rulesdb, target) + + return exit_status["success"] + # # At this point, we start executing the makefile Rules. # @@ -651,9 +677,9 @@ def execute(makefile, args): # walk a dependency tree for rule in rulesdb.walk_tree(target): - if not rule.recipe_list: - # this warning catches where I fail to find an implicit rule - logger.warning("I didn't find a recipe to build target=\"%s\"", target) +# if not rule.recipe_list: +# # this warning catches where I fail to find an implicit rule +# logger.warning("I didn't find a recipe to build target=\"%s\"", target) # target specific variables if rule.assignment_list: diff --git a/pymake/rules.py b/pymake/rules.py index 0f10751..a1cffac 100644 --- a/pymake/rules.py +++ b/pymake/rules.py @@ -37,8 +37,8 @@ def __init__(self, target, prereq_list, recipe_list, assignment, pos): logger.debug("create rule target=%r at %r", target, pos) self.target = target - self.prereq_list = prereq_list - self.recipe_list = recipe_list + self.prereq_list = list(prereq_list) + self.recipe_list = list(recipe_list) self.assignment_list = [assignment] if assignment else [] _rule_sanity(pos, prereq_list, assignment) @@ -49,7 +49,7 @@ def __init__(self, target, prereq_list, recipe_list, assignment, pos): def __str__(self): target = "" if self.target is None else self.target - return "%s <- %s" % (target, ",".join(self.prereq_list)) + return "%s : %s" % (target, " ".join(self.prereq_list)) def makefile(self): s = "".join([ "%s:%s\n" % (self.target,a.makefile()) for a in self.assignment_list]) @@ -105,6 +105,8 @@ def add(self, target, prereq_list, recipe_list, assignment, pos): if target == ".PHONY": raise NotImplementedError(target) + elif target == ".PRECIOUS": + raise NotImplementedError(target) _rule_sanity(pos, prereq_list, assignment) diff --git a/pymake/tokenizer.py b/pymake/tokenizer.py index 3039dcb..e03ea19 100644 --- a/pymake/tokenizer.py +++ b/pymake/tokenizer.py @@ -482,7 +482,7 @@ def save_prereq(token_list): # found a : on the Rule's right hand side # static pattern rule, e.g. # $(objects): %.o: %.c - raise NotImplementedError("static pattern rule") + raise NotImplementedError("static pattern rule at pos=%r" % (vchar.get_pos(),)) elif state==state_backslash : if not c in eol : From fea1523d8b2a367e7057a90dc8e0d02009cf0ec1 Mon Sep 17 00:00:00 2001 From: David Poole Date: Sun, 26 Jan 2025 15:56:35 -0800 Subject: [PATCH 2/2] add python 3.13 to CI --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4642fcf..5ecd60f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,7 +9,7 @@ jobs: max-parallel: 4 matrix: platform: [ubuntu-latest] - python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13'] env: PLATFORM: ${{ matrix.platform }} steps: