Alright I am stuck on this and I have no idea what I am doing wrong. Everything was going great working on a more complicated makefile but then all of a sudden I got the "Missing separator" error. I was able to isolate it down to a very simple scenario:
define push_dir
$(info ${1})
endef
define pop_dir
$(info ${1})
endef
define include_submake
$(call push_dir,${1})
$(call pop_dir,${1})
endef
include test.mk
INITIAL_SUBMAKE:= includeme.mk
$(call include_submake,${INITIAL_SUBMAKE})
process:
@echo Processed...
And the output:
C:\project>make -f Simple process
includeme.mk
includeme.mk
Simple:4: *** missing separator. Stop.
includeme.mk
does not actually exist. I have no idea what is going wrong here I have tried a multitude of things. If I surround the call to include_submake in info like so:
$(info $(call include_submake,${INITIAL_SUBMAKE}))
The missing separator error goes away. Also If in the include_submake
define I only call one of the functions it works fine. Additionally if I directly call the functions instead of calling them include_submake
it works as well:
include test.mk
INITIAL_SUBMAKE:= includeme.mk
$(call push_dir,${INITIAL_SUBMAKE})
$(call pop_dir,${INITIAL_SUBMAKE})
process:
@echo Processed...
C:\project>make -f Simple process
includeme.mk
includeme.mk
Processed...
I feel like I'm overlooking something fundamental here. Thanks for your help.
The missing separator
error happens because of a non-empty return value of include_submake
, which is a single line feed character in your case. Make only permits whitespace characters (that is, a space or tab) to occur in an expression which is not assumed to be a part of some rule or another directive.
Rewrite your functions using plain-old Make variable assignment and the error should go away:
push_dir = \
$(info $1)
pop_dir = \
$(info $1)
include_submake = \
$(call push_dir,$1) \
$(call pop_dir,$1)
define
vs plain old variable assignmentAnswering to a question from the first comment. Personally I would prefer using define
directive in several cases.
eval
functionAs the GNU Make manual suggests, define
directive is very useful in conjunction with the eval
function. Example from the manual (emphasis is mine):
PROGRAMS = server client server_OBJS = server.o server_priv.o server_access.o server_LIBS = priv protocol client_OBJS = client.o client_api.o client_mem.o client_LIBS = protocol # Everything after this is generic .PHONY: all all: $(PROGRAMS) define PROGRAM_template $(1): $$($(1)_OBJS) $$($(1)_LIBS:%=-l%) ALL_OBJS += $$($(1)_OBJS) endef $(foreach prog,$(PROGRAMS),$(eval $(call PROGRAM_template,$(prog)))) $(PROGRAMS): $(LINK.o) $^ $(LDLIBS) -o $@ clean: rm -f $(ALL_OBJS) $(PROGRAMS)
Verbatim variables fit perfectly for cases when you want to generate a file from GNU Make. For example, consider generating a header file based on some information from Makefile.
# Args: # 1. Header identifier. define header_template /* This file is generated by GNU Make $(MAKE_VERSION). */ #ifndef $(inclusion_guard) #define $(inclusion_guard) $(foreach inc,$($1.includes), #include <$(inc).h>) /* Something else... */ #endif /* $(inclusion_guard) */ endef # 1. Unique header identifier. inclusion_guard = \ __GEN_$1_H # Shell escape. sh_quote = \ '$(subst ','"'"',$1)' foo.includes := bar baz HEADERS := foo.h $(HEADERS) : %.h : @printf "%s" $(call sh_quote,$(call header_template,$(*F)))> $@
In our project we use our own build system called Mybuild, and it is implemented entirely on top of GNU Make. As one of low-level hacks that we used to improve the poor syntax of the builtin language of Make, we have developed a special script which allows one to use extended syntax for function definitions. The script itself is written in Make too, so it is a sort of meta-programming in Make.
In particular, one can use such features as:
$(assert ...)
or $(lambda ...)
$(eq s1,s2)
(string equality check)This is an example of how a function can be written using the extended syntax. Note that it becomes a valid Make function and can be called as usual after a call to $(def_all)
.
# Reverses the specified list. # 1. The list # Return: # The list with its elements in reverse order. define reverse # Start from the empty list. $(fold ,$1, # Prepend each new element ($2) to # the result of previous computations. $(lambda $2 $1)) endef $(def_all)
Using these new features we were able to implement some really cool things (well, at least for Make :-) ) including:
Feel free to use any part of the code in your own projects!