Skip to content

Commit

Permalink
add MAKELEVEL built-in variable
Browse files Browse the repository at this point in the history
"As a special feature, the variable MAKELEVEL is changed when it is passed down from level to level. This variable’s value is a string which is the depth of the level as a decimal number. The value is ‘0’ for the top-level make; ‘1’ for a sub-make, ‘2’ for a sub-sub-make, and so on. The incrementation happens when make sets up the environment for a recipe. "

GNU Make Manual https://www.gnu.org/software/make/manual/make.html
  • Loading branch information
linuxlizard committed Jul 14, 2023
1 parent 45e77b2 commit 7c140f6
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 7 deletions.
23 changes: 16 additions & 7 deletions pymake/pymake.py
Expand Up @@ -277,7 +277,7 @@ def _execute_statement_list(stmt_list, curr_rules, rulesdb, symtable):
# bottom of loop
return exit_code

def execute_recipe(rule, recipe, symtable):
def execute_recipe(rule, recipe, symtable, dry_run=False):
def remove_duplicates(s_list):
# the $^ variable removes duplicates but must must must preserve order
seen_list = []
Expand Down Expand Up @@ -333,6 +333,8 @@ def check_prefixes(s):

return s, ignore_failure, silent

makelevel = int(symtable.fetch("MAKELEVEL"))

Check warning on line 336 in pymake/pymake.py

View check run for this annotation

Codecov / codecov/patch

pymake/pymake.py#L336

Added line #L336 was not covered by tests

# TODO many more automatic variables
symtable.push("@")
symtable.push("^")
Expand Down Expand Up @@ -373,6 +375,11 @@ def check_prefixes(s):

s, ignore_failure, silent = check_prefixes(s)

if dry_run:
# TODO submakes
print(s)
continue

Check warning on line 381 in pymake/pymake.py

View check run for this annotation

Codecov / codecov/patch

pymake/pymake.py#L380-L381

Added lines #L380 - L381 were not covered by tests

if not silent:
print(s)

Expand All @@ -391,7 +398,7 @@ def check_prefixes(s):
args = pargs.parse_args(submake_argv[1:])
# breakpoint()
currwd = os.getcwd()
exit_code = _run_it(args)
exit_code = _run_it(args, makelevel+1)

Check warning on line 401 in pymake/pymake.py

View check run for this annotation

Codecov / codecov/patch

pymake/pymake.py#L401

Added line #L401 was not covered by tests
os.chdir(currwd)
# clean up the output from the submake helper
ret.stdout = ""
Expand All @@ -408,7 +415,7 @@ def check_prefixes(s):

return exit_status["error"] if exit_code else exit_status["success"]

def execute(makefile, args):
def execute(makefile, args, makelevel):
# ha ha type checking
assert isinstance(args, pargs.Args)

Expand All @@ -429,6 +436,8 @@ def execute(makefile, args):
# The -C option will be handled before this function is called.
symtable.add("CURDIR", os.getcwd())

symtable.add("MAKELEVEL", str(makelevel))

Check warning on line 439 in pymake/pymake.py

View check run for this annotation

Codecov / codecov/patch

pymake/pymake.py#L439

Added line #L439 was not covered by tests

target_list = []

# GNU Make allows passing assignment statements on the command line.
Expand Down Expand Up @@ -496,7 +505,7 @@ def execute(makefile, args):
# walk a dependency tree
for rule in rulesdb.walk_tree(target):
for recipe in rule.recipe_list:
exit_code = execute_recipe(rule, recipe, symtable)
exit_code = execute_recipe(rule, recipe, symtable, args.dry_run)

Check warning on line 508 in pymake/pymake.py

View check run for this annotation

Codecov / codecov/patch

pymake/pymake.py#L508

Added line #L508 was not covered by tests
if exit_code != 0:
break

Expand All @@ -505,7 +514,7 @@ def execute(makefile, args):

return exit_status["error"] if exit_code else exit_status["success"]

def _run_it(args):
def _run_it(args, makelevel):
# -C option
if args.directory:
os.chdir(os.path.join(*args.directory))
Expand Down Expand Up @@ -534,7 +543,7 @@ def _run_it(args):
print(makefile.makefile(), file=outfile)
print("# end makefile %s" % args.output)

exit_code = execute(makefile, args)
exit_code = execute(makefile, args, makelevel)

Check warning on line 546 in pymake/pymake.py

View check run for this annotation

Codecov / codecov/patch

pymake/pymake.py#L546

Added line #L546 was not covered by tests
return exit_code

# FIXME ugly hack dependency injection to solve problems with circular imports
Expand All @@ -553,7 +562,7 @@ def main():
# usage()
# sys.exit(1)

sys.exit(_run_it(args))
sys.exit(_run_it(args,0))

Check warning on line 565 in pymake/pymake.py

View check run for this annotation

Codecov / codecov/patch

pymake/pymake.py#L565

Added line #L565 was not covered by tests

if __name__=='__main__':
main()
11 changes: 11 additions & 0 deletions tests/submake.mk
Expand Up @@ -2,20 +2,31 @@

$(info CURDIR=$(CURDIR))

# check on MAKELEVEL value
$(if $(MAKELEVEL),,$(error MAKELEVEL is missing))

all:
@echo hello from make pid=$$$$
$(MAKE) -f $(CURDIR)/tests/submake.mk submake A=B B=C C=D

# we should ignore this error and continue
-$(MAKE) -f $(CURDIR)/tests/submake.mk submake-error

# adding a shell expression to verify we go through the shell
@$(MAKE) -f $(CURDIR)/tests/submake.mk hello-world NUM=$$((10+20)) a={1,2,3}

if [ -z '$(MAKELEVEL)' ] ; then echo missing MAKELEVEL && exit 1 ; fi
if [ ! $(MAKELEVEL) -eq 0 ] ; then echo MAKELEVEL should be zero && exit 1 ; fi

submake:
@echo hello from submake pid=$$$$
if [ ! $(MAKELEVEL) -eq 1 ] ; then echo MAKELEVEL should be value 1 && exit 1 ; fi

hello-world:
if [ ! $(MAKELEVEL) -eq 1 ] ; then echo MAKELEVEL should be value 1 && exit 1 ; fi
@echo hello, world NUM=$(NUM) a=$(a)

submake-error:
if [ ! $(MAKELEVEL) -eq 1 ] ; then echo MAKELEVEL should be value 1 && exit 1 ; fi
@echo error && exit 1

0 comments on commit 7c140f6

Please sign in to comment.