make: Eval Function

1 
1 8.9 The 'eval' Function
1 =======================
1 
1 The 'eval' function is very special: it allows you to define new
1 makefile constructs that are not constant; which are the result of
1 evaluating other variables and functions.  The argument to the 'eval'
1 function is expanded, then the results of that expansion are parsed as
1 makefile syntax.  The expanded results can define new 'make' variables,
1 targets, implicit or explicit rules, etc.
1 
1    The result of the 'eval' function is always the empty string; thus,
1 it can be placed virtually anywhere in a makefile without causing syntax
1 errors.
1 
1    It's important to realize that the 'eval' argument is expanded
1 _twice_; first by the 'eval' function, then the results of that
1 expansion are expanded again when they are parsed as makefile syntax.
1 This means you may need to provide extra levels of escaping for "$"
11 characters when using 'eval'.  The 'value' function (⇒Value
 Function) can sometimes be useful in these situations, to circumvent
1 unwanted expansions.
1 
1    Here is an example of how 'eval' can be used; this example combines a
1 number of concepts and other functions.  Although it might seem overly
1 complex to use 'eval' in this example, rather than just writing out the
1 rules, consider two things: first, the template definition (in
1 'PROGRAM_template') could need to be much more complex than it is here;
1 and second, you might put the complex, "generic" part of this example
1 into another makefile, then include it in all the individual makefiles.
1 Now your individual makefiles are quite straightforward.
1 
1      PROGRAMS    = server client
1 
1      server_OBJS = server.o server_priv.o server_access.o
1      server_LIBS = priv protocol
1 
1      client_OBJS = client.o client_api.o client_mem.o
1      client_LIBS = protocol
1 
1      # Everything after this is generic
1 
1      .PHONY: all
1      all: $(PROGRAMS)
1 
1      define PROGRAM_template =
1       $(1): $$($(1)_OBJS) $$($(1)_LIBS:%=-l%)
1       ALL_OBJS   += $$($(1)_OBJS)
1      endef
1 
1      $(foreach prog,$(PROGRAMS),$(eval $(call PROGRAM_template,$(prog))))
1 
1      $(PROGRAMS):
1              $(LINK.o) $^ $(LDLIBS) -o $@
1 
1      clean:
1              rm -f $(ALL_OBJS) $(PROGRAMS)
1