On Fri, 2022-01-21 at 09:24 +0800, Hongyi Zhao wrote: > define download_and_unpack > @package = $(1) > @package_URL = $(2) > @package_directory = $(3) > @package_code = $(4) > @package_archive = ../archive/`echo "$(package)" | sed 's/.*\///;s/.*=//'` > > @( > if ! gzip -t $(package_archive) > /dev/null 2>&1 ; then \
As I've already mentioned, we cannot help if you only show us the DEFINITION of the variable but don't show us how the variable is REFERENCED. However, in this case we can already say that this cannot work. You are forgetting a fundamental concept of makefiles. A rule in a makefile has the form: <target>: <prerequisites> <recipe> (where <prerequisites> can be empty). The content inside the <recipe> MUST BE a shell script. It is not makefile syntax, it is SHELL syntax. You cannot put makefile operations, like setting make variables, in the recipe. Only shell operations, like setting shell variables, can be in the recipe. It doesn't matter how complicated the content of <recipe> is, how many variables it contains, functions it uses, etc.: once it's expanded everything in it must be shell syntax and not makefile syntax. So when you put a reference to the variable $(download_and_unpack) in a recipe, like this: <target>: <prerequisites> $(download_and_unpack) the variable reference is in a recipe, so the entirety of the expanded value of that variable will be given to the shell to be interpreted. This: package = ... is not valid shell syntax. Make variables can be assigned like this, but we know this is in a recipe so it can't use make syntax, it must use shell syntax, and shell variables cannot have whitespace around the "=" sign. Try it: at your shell prompt type: $ package = foo and you'll get the error "package: Command not found" just as you see. If you wanted to set a SHELL variable you have to use SHELL syntax: @package=$(1) @package_URL=$(2) @package_directory=$(3) @package_code=$(4) @package_archive=../archive/`echo "$(package)" | sed 's/.*\///;s/.*=//'` However, this won't work for the reasons we explained before: every separate line in a recipe is run in a separate shell. So these SHELL variables are assigned, then the shell exits and the values are lost, then a new shell is started. As mentioned before, the entire script must be contained in a single logical line if you want the same shell to interpret it all. So you'll have to add "\" to combine all these into a single logical line: define download_and_unpack package='$(1)' ; \ package_URL='$(2)' ; \ package_directory='$(3)' ; \ package_code='$(4)' ; \ package_archive=../archive/`echo "$(package)" | sed 's/.*\///;s/.*=//'` ; \ ( \ if ! gzip -t $(package_archive) > /dev/null 2>&1 ; then \ etc.