问题
I write general makefiles and functions for users' convenience, so naturally they should have the simplest interfaces possible . When defining functions, I use this paradigm:
define FUNCTION
target: $1
endef
FUNCTION2 = $(eval $(call FUNCTION,$1))
Now, instead of telling them to do this
$(eval $(call FUNCTION,
argument))
I can tell them to do this
$(call FUNCTION2,
argument)
which is simpler.
This worked like a charm until somebody decided to use .EXPORT_ALL_VARIABLES
, so that we have the total code (SSCCE) look like this:
define FUNCTION
target: $1
endef
FUNCTION2 = $(eval $(call FUNCTION,$1))
.EXPORT_ALL_VARIABLES:
all:
echo OK
Now when you make
this, you get:
Makefile:5: *** prerequisites cannot be defined in recipes. Stop.
Well, I guess this is because the recipe echo
subprocess evaluates the "variable" FUNCTION2
, which then unexpectedly puts the prerequisite line into the recipe. Or something like that.
So my question is, who is to blame?
Is my paradigm faulty and I should not be using it, because the users then cannot use .EXPORT_ALL_VARIABLES
? If so, is there a way to fix things, so that users can still call the simple FUNCTION2
?
Or is .EXPORT_ALL_VARIABLES
an evil feature and should not be used?
回答1:
My personal opinion is that .EXPORT_ALL_VARIABLES
is an evil feature and should not be used. However, i think this is worth an enhancement request for GNU make: it shouldn't be running eval
when expanding variables for export.
回答2:
Use unexport FUNCTION FUNCTION2
to get rid of this error.
Yet I have to agree with @MadScientist that .EXPORT_ALL_VARIABLES
is evil.
It forcefully performs expansion of all recursive variables before executing every recipe, so it could easily break any complicated build system.
IMO, it could be useful to have a way to stop any expansion of auto-exported variables.
The only consolation is that almost no one uses that .EXPORT_ALL_VARIABLES
thing.
回答3:
In my non-recursive build system prorab I use eval
, but without call
.
I pass parameters through this_
-prefixed variables, something like this:
include prorab.mk
this_name := myapp
this_cxxflags += -Wall
this_cxxflags += -DDEBUG
this_cflags += -Wall
this_ldlibs += -lpthread
this_srcs += main.cpp myapp.cpp legacy.c
$(eval $(prorab-build-app))
So, eval
is still there, but inserting variable instead of call
makes it shorter and also user does not have to remember which argument of the call
means what, because this_
variables have descriptive names.
来源:https://stackoverflow.com/questions/56467690/how-to-improve-call-eval-call-paradigm-in-using-make