makefile is missing separator

gnu-make, makefile, syntax-error

Solution

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)

UPD.: `define` vs plain old variable assignment

Answering to a question from the first comment. Personally I would prefer using `define` directive in several cases.

Using with `eval` function

As 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)

Generator templates

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)))> $@

Extended Make syntax

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:

- Defining multiline functions without the need to use backslash

- Using comments inside functions (in plain-old Make comments can only occur outside variable assignment directives)

- Defining custom macros like `$(assert ...)` or `$(lambda ...)`

- Inlining simple functions like `$(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:

- Object-Oriented layer with dynamic object allocation, class inheritance, method invocations and so on

- LALR parser runtime engine for parsers generated by GOLD Parser Builder

- Modelling library with runtime support for models generated with EMF

Feel free to use any part of the code in your own projects!

Problem

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: test.mk ``` define push_dir $(info ${1}) endef define pop_dir $(info ${1}) endef define include_submake $(call push_dir,${1}) $(call pop_dir,${1}) endef ``` Simple ``` 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.

Original source