Indresh Kumar
Indresh Kumar

Reputation: 1

recipe commences before first target

Error : Makefile:12: *** recipe commences before first target. Stop.

My makefile:

objDir := obj
incDir := include
srcDir := src
binDir := bin
files := matrix palindrome encryption

define generateObject
    @nasm -f elf32 -o $(objDir)/$(1).o $(srcDir)/$(1).asm
endef

object: $(addprefix $(srcDir)/,$(addsuffix .asm,$(files)))
    @echo -n "Generating object files... "
    $(foreach file,$(files),$(eval $(call generateObject,$(file))))
    @echo "Done"

I read in a post that this could be due to unwanted whitespace/tab but i could not find any.

I tried cat -e -t -v Makefile and the output was :

objDir := obj$
incDir := include$
srcDir := src$
binDir := bin$
files := matrix palindrome encryption$
$
define generateObject$
^I@nasm -f elf32 -o $(objDir)/$(1).o $(srcDir)/$(1).asm$
endef$
$
object: $(addprefix $(srcDir)/,$(addsuffix .asm,$(files)))$
^I@echo -n "Generating object files... "$
^I$(foreach file,$(files),$(eval $(call generateObject,$(file))))$
^I@echo "Done"$

Upvotes: 0

Views: 3574

Answers (1)

MadScientist
MadScientist

Reputation: 101111

Your problem is use of the eval function. eval is used to parse make constructs, but you're passing it a shell command. Consider this line:

$(foreach file,$(files),$(eval $(call generateObject,$(file))))

Each time through the list you'll call generateObject with a filename. That will expand to a shell command; for example if file is matrix then call will expand to:

^I@nasm -f elf32 -o obj/matrix.o src/matrix.asm

Then you take that text string and pass it to eval which tries to read that as a makefile. Note that the text passed to eval must be a complete and valid makefile in itself; it's like you invoked make recursively and gave it this string as a makefile, except that the result of parsing are applied to the current makefile. You can't give eval just a part of a valid makefile (like one command line in a recipe) and have it insert that into the current makefile. Because that line by itself isn't valid, you get this error.

Instead of running eval on the results you want to concatenate them into one shell command. Try this:

define generateObject
  nasm -f elf32 -o $(objDir)/$(1).o $(srcDir)/$(1).asm
endef

object: $(addprefix $(srcDir)/,$(addsuffix .asm,$(files)))
        @echo -n "Generating object files... "
        @$(foreach file,$(files),$(call generateObject,$(file)) && ) true
        @echo "Done"

However, that's really not "the make way". You don't want to build multiple targets within a single rule: that defeats the main point of make which is that it only rebuilds the files that are out of date.

You should write your makefile like this:

object: $(files:%=$(objDir)/%.o)

$(objDir)/%.o : $(srcDir)/%.asm
        @nasm -f elf32 -o $@ $<

You don't need the generateObject variable, or call, or eval, or even foreach.

Upvotes: 1

Related Questions