Skip to content

Instantly share code, notes, and snippets.

@weshouman
Last active February 20, 2024 18:16
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save weshouman/f44f330227972073371e1baa510c0d37 to your computer and use it in GitHub Desktop.
Save weshouman/f44f330227972073371e1baa510c0d37 to your computer and use it in GitHub Desktop.
Makefile function example
PATH = /tmp/
define myfn
processed_input=${PATH}/$(2)
$(1) := $$(processed_input)
endef
mytarget:
$(eval FILE=myfile)
$(eval $(call myfn,abs_filename,$(FILE)))
/bin/echo ${abs_filename}
PATH = /tmp/
define myfn
return_var=${PATH}/$(2)
/bin/echo complex # we used an echo function here for simplicity
# but instead it could be "if condition", "for loop" or any further shell expression
$(1) := $$(return_var)
endef
mytarget:
$(eval FILE=myfile)
# using value here to avoid unwanted expansion will result in the return not being correctly assigned
# And if we didn't use value at all, ```echo complex``` will be treated as a target without previous tabs
# if we added the tabs Make will complain because ```echo complex``` is now considered a target body without a previous target
# if we added a target "without tabs" then added ```echo complex```, it renders useless in generalization cause the make target won't give us output when we want
# in the 3-correct-complex.mk it will be clearer how the define is treated as another Makefile
$(eval $(value $(call myfn,abs_filename,$(FILE)))
/bin/echo ${abs_filename}
PATH = /tmp/
define myfn
processed_input=${PATH}/$(2)
processed_more=$(shell echo $(processed_input))
# could be "if condition", "for loop" or any further shell expression
# Notice that: the output of the shell function is the stdout/stderr, for more advanced usage
# Either use a file communication, or better, another scriptfile (shell, python or whatever)
$(1) := $$(processed_more)
# NOTE: Uncommenting dummy_target will fail the main my_target unless $(value ..) got used between the $(eval ..) and $(call ..)
# NOTE: we should not use the $(value ..) here to avoid incorrect assignment
#dummy_target:
# further targets could be added here
# Notice that, ```define``` keyword defines a multi-line expression that is very like another makefile
# with it's own variables and targets
endef
mytarget:
$(eval FILE=myfile)
# using value here to avoid unwanted expansion will result in the return not being correctly assigned
$(eval $(call myfn,abs_filename,$(FILE)))
/bin/echo ${abs_filename} # Path2 will be printed

Usage:

This is an example for a function myfn that:

  • Takes a local input file name FILE
  • Returns an abs_filename, created by using the global variable PATH

Notes:

  • We couldn't replace myfn with another make target as it wouldn't give us a clear return value
  • We had to use ($value ...) to avoid the unwanted expansion described in Eval Function and Value Function
  • When we miss the value function, we get "Missing Separator Stop error"
  • Commenting an ($eval ($call ... ) expression is not possible (even the syntax highlighting showed so -_-).
  • Use this way only if the function expression is complicated and needs multiple lines, otherwise, one could use filters and similar stuff

References:

@Tiempogithub
Copy link

Thanks for the nice example.
One remark: 1-simple.mk line 10: closing parenthesis is missing

@weshouman
Copy link
Author

Thanks for the hint!
Now it's fixed ^_^

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment