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.
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!
I ran into the same problem. I inserted 'tab', deleted 'tab', reinserted to be sure. Same error message.
But, I did all of this inside of XCodem which to my surprise inserted white spaces, not '\t'. Once I used different editor these 'phantom' errors went away.
HTH...
Related
I have several files for my GNU make setup. In this.mk, I have
define this_template
THIS = $(1)
THIS_DIR = $(2)
THIS_LIBNAME = $(3)
THIS_EXTERNAL_DIRS = $(4)
...
endef
In my Makefile, I have
include this.mk
... # define VAR1 and VAR2
include util/make.mk
...
util/make.mk contains one line:
$(eval $(call this_template,UTIL,$(VAR1),plutil,$(VAR2)))
However, when I run make, I get
util/make.mk:1: *** recipe commences before first target. Stop.
Reading up on other questions that relate to this error message, what I'm understanding is that this error is caused by evaluating a string which begins in a way that looks like it's inside of a recipe. However, what I'm evaluating does not.
This error means that (a) the line begins with a TAB (or more specifically, with the character defined as .RECIPE_PREFIX if your version of GNU make supports it), and (b) it is not recognized as any sort of make command such as a rule introduction, etc.
Given what you've shared with us here, that cannot happen. So there must be something going on that you haven't shared with us. Maybe one of the other included makefiles is modifying the this_template variable to contain something else.
The way to debug eval problems is always the same no matter what they are: change the eval to info so that make will print out what it will evaluate. This usually makes it pretty obvious what the problem is. So use:
$(info $(call this_template,UTIL,$(VAR1),plutil,$(VAR2)))
$(eval $(call this_template,UTIL,$(VAR1),plutil,$(VAR2)))
and see what make shows you.
I’m trying to implement include guards in Gnu Make. In this Makefile, the first inclusion is OK, while the second one fails with an error.
ifndef INCLUDED
INCLUDED = 1
$(info Including)
define macro
ifneq ($(1),)
define inner_macro
macro content...
endef
else
define inner_macro
endef
endif
endef
endif
The same effect can be simulated by explicitly giving INCLUDED = 1 before the inclusion, e.g. on command line.
Gnu Make 4.1 under Gentoo says Makefile:14: *** missing separator. Stop., while Gnu Make 3.81 under Debian Wheezy says Makefile:14: *** extraneous `endef'. Stop.. On the first inclusion, they both say:
Including
make: *** No targets. Stop.
If I try $(eval $(call macro,whatever)) after the first inclusion, it defines inner_macro as expected.
I used make INCLUDED=1 and make commands respectively to get the described behavior.
The same happens when I clear the environment and disable built-in rules and variables: env -i make -rR INCLUDE=1. When I use -p to dump the database, without INCLUDED=1, the macro is defined as it should be, but with INCLUDED=1, empty inner_macro is defined. This is consistent across both the versions of Make. This hints me that when the condition is false, Make parses the Makefile differently and thinks the else inside macro’s definition belongs to the ifndef. Other condition types behave all the same.
If I remove both the definitions of inner_macro, the problem goes away.
I read the manual pages info make conditional\ syntax and info make multi-line (formerly defining), but I found no caveat there and I still think I am doing nothing wrong.
Am I correct with my conclusions?
Is this a bug in Make, or am I invoking undefined behavior?
How should I implement include guards in Gnu Make?
That's a bug. Report it on Savannah.
There's something wrong with the tracking of nested define/endef inside a not-taken ifdef/ifndef condition. If you don't use nested define/endef then it works; for example (obviously you may not be able to do this in your environment):
ifndef INCLUDED
INCLUDED = 1
$(info Including)
define macro
ifneq ($(1),)
inner_macro = macro content...
else
inner_macro =
endif
endef
endif
I'm having some issues after try to run some small Makefile with make 3.82.
error:
[me#localhost make]$ make
Makefile:3: *** empty variable name. Stop.
This works with make 3.81, but not with the new one. I know there are some backward compatibilities with the old version.
I have two Makefiles, a base one and main one.
This is my Makebase
define TestFile
ifeq ($$(shell test $(1) $(2) || echo 1),1)
$$(error $(2) mmm, not found)
endif
endef
define CheckIt
$(eval $(call TestFile,-d,$(1)))
endef
define CheckDir
p := $(foreach d,$1,$(call CheckIt,$d))
endef
define SomeCheck
$(call CheckDir,$(1))
endef
This is my Makefile
include Makebase
$(call SomeCheck, ~/test/make)
As I said, it works fine in make 3.81.
Any help will be appreciated.
Thanks
BR
So, I have no idea what this was intended to do in GNU make 3.81. As Etan points out, when I run your makefile with GNU make 3.81 I get this error:
make: *** No rule to make target `=', needed by `p'. Stop.
That's because a call function cannot expand to a variable assignment, so make interprets the p := as if it were p: = (that is, a target p with a prerequisite of =). I don't see how this is actually what you want. If you don't see this error all I can assume is that somewhere in your makefile, someone has declared a recipe with target = (ugh!!)
In GNU make 3.82 I see the empty variable name message. The reason for this is that GNU make 3.82 introduced parser enhancements which caused some backwards-incompatibility. The NEWS file gives this warning:
As a result of parser enhancements, three backward-compatibility issues
exist: first, a prerequisite containing an "=" cannot be escaped with a
backslash any longer. You must create a variable containing an "=" and
use that variable in the prerequisite.
An unnoticed side-effect of this is that an equals sign with no value before it in the prerequisites list is now considered a target-specific variable where the variable name is empty, whereas before it was assumed to be a target since it didn't meet the requirements for a variable assignment. I am not sure this is a bug... in general I'm not a fan of "tricking" the parser with odd corner cases so I actually prefer the newer behavior.
This entire define is quite bogus:
define CheckDir
p := $(foreach d,$1,$(call CheckIt,$d))
endef
Why? Because the CheckIt user-defined function contains nothing but an eval statement. But eval statements are expanded and the results parsed by make, so they always expand to the empty string. Therefore, the entire foreach loop expands to the empty string. Therefore even if this were interpreted as you (apparently) intended by make, it would always simply expand to:
p :=
which doesn't seem very useful. If you change the above define to simply:
define CheckDir
$(foreach d,$1,$(call CheckIt,$d))
endef
then it will always work, and you won't see these weird problems.
I'm not going to comment on how bogus this makefile is in general... :)
I'm trying to debug makefiles for a large project and I'm struggling define TEMPLATE/endef and foreach/eval/call constructs. In particular I think I'm having a hard time figuring out which variables I need to reference with $ and which I need to reference with $$.
I think would be easier for me to debug if I could see the actual results of the the eval/call expansion, before variable expansion.
For instance if we use the example in the eval documentation for gnu-make, we have the following makefile-fragment:
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
...
define PROGRAM_template =
$(1): $$($(1)_OBJS) $$($(1)_LIBS:%=-l%)
ALL_OBJS += $$($(1)_OBJS)
endef
$(foreach prog,$(PROGRAMS),$(eval $(call PROGRAM_template,$(prog))))
I think this foreach should effectively expand to the following, before variable expansion:
server: $(server_OBJS) $(server_LIBS:%=-l%)
ALL_OBJS += $(server_OBJS)
client: $(client_OBJS) $(client_LIBS:%=-l%)
ALL_OBJS += $(client_OBJS)
I figured out the above expansion by hand (corrections welcome), but I'm looking for a general method to display this expansion for more complex examples. Does such a method exist?
I have looked into make -d and make -pn options, and as far as I can tell, I don't think either of these will provide this particular output.
I'm using make-3.81.
Replace all your $(eval ...) calls with $(info ...). Actually if you're stuck with 3.81 you may have to use $(warning ...) and ignore the extra output, because I think $(info ...) might not have existed until version 3.82.
Anyway, writing:
$(foreach prog,$(PROGRAMS),$(info $(call PROGRAM_template,$(prog))))
(or warning) you'll see what make is parsing.
I've written a macro to help with seeing the results of $(eval ...):
# This version prints out rules for debugging
#c = $(eval $(call $(strip $1),$(strip $2),$(strip $3),$(strip $4),$(strip $5),$(strip $6),$(strip $7),$(strip $8),$(strip $9))) $(info $(call $(strip $1),$(strip $2),$(strip $3),$(strip $4),$(strip $5),$(strip $6),$(strip $7),$(strip $8),$(strip $9)))
# This version is the production version
c = $(eval $(call $(strip $1),$(strip $2),$(strip $3),$(strip $4),$(strip $5),$(strip $6),$(strip $7),$(strip $8),$(strip $9)))
Use it like this:
$(call c,function,arg1,arg2,...)
To see what is being generated by eval, simply use the debugging version. I needed this instead of simply replacing $(eval ...) by $(info ...) because functionality later in the makefile depended on the results of the $(eval ...)
I have to convert a set of file (let's say format fa) into another format (fb) by a command (fa2fb). Each target fb depends only on one fa file.
Data structure is in a format like this:
source:
./DATA/L1/fa/L1.fa
./DATA/L2/fa/L2.fa
...
./DATA/Ln/fa/Ln.fa
target:
./DATA/L1/fb/L1.fb
./DATA/L2/fb/L2.fb
...
./DATA/Ln/fb/Ln.fb
How can I implement it with make?
I have tried this but of course it did not work:
./DATA/%/fb/%.fb : ./DATA/%/fa/%.fb
#fa2fb $< $#
Is there any simple solution without changing the data directories?
Many thanks!
Use secondary expansion and the subst function to create a rule where the prerequisites are constructed as a more complex function of the target name:
.SECONDEXPANSION:
DATA/%.fb: $$(subst fb,fa,$$#)
#fa2fb $< $#
Note that this approach assumes that fb will not occur anywhere else in the filename (which holds true if all of your filenames are of the form DATA/Ln/fb/Ln.fb, for some integer n).
This may be the sloppiest makefile I have ever written.
define template
$(2) : $(1)
echo hi
endef
sources=DATA/L1/fa/L1.fa DATA/L2/fa/L2.fa
$(foreach source,$(sources),$(eval $(call template,$(source),$(subst /fa/,/fb/,$(subst .fa,.fb,$(source))))))
The idea is to define a macro to generate your rules, then use foreach and eval+call to invoke it once for each source. The source is the first argument to the call, so it becomes $(1) in the macro. The second argument is just the transformation from a source file name to a destination file name; it becomes $(2) in the macro.
Replace echo hi with your own rule and you should be good to go. And be sure to write a nice big clear comment or someday someone will surely show up at your door with a baseball bat.
This is basically the same as Nemo's answer. I just tried to make the foreach call a bit more readable, by creating a list of modules, containing simply L1 L2 ... Ln, instead of the list of full source names.
MODULES := $(notdir $(wildcard ./DATA/L*))
define rule
./DATA/$(1)/fb/$(1).fb: ./DATA/$(1)/fa/$(1).fa
#fa2fb $< $#
endef
$(foreach module, $(MODULES), $(eval $(call rule,$(module))))