From target/linux/ar71xx/image/Makefile
KERNEL := kernel-bin | patch-cmdline | lzma | uImage lzma
Could you please help me understand what does this line means and provide an example on how to use the symbol pipe | in a Makefile
This line is simply setting the make variable KERNEL to the string kernel-bin | patch-cmdline | lzma | uImage lzma. The pipe symbol (|) has no special meaning to make here.
You'll have to see how the variable is being used. Most likely it appears in a recipe somewhere, like this:
foo:
$(KERNEL)
In that case the variable is expanded and the results are sent to the shell. In the shell, the pipe symbol causes the stdout from the command on the lefto be hooked up to the stdin of the command on the righ: it's called a pipeline or piping data.
Here you have a pipeline of 4 comands: kernel-bin's output is sent to 'patch-cmdline's input, patch-cmdline's output is sent to lzma's input, lzma's output is sent to uImage lzma's input.
There is another use of '|' pipe symbol - to define order only prerequisites that simply provider target ordering and not build dependency:
For example:
OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)
$(OBJDIR)/%.o : %.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
all: $(OBJS)
$(OBJS): | $(OBJDIR)
$(OBJDIR):
mkdir $(OBJDIR)
Ref: https://www.gnu.org/software/make/manual/html_node/Prerequisite-Types.html
What is suggested by #MadScientist is very correct, but in this specific case i think that it is not used for passing parameters but rather for sequential calls of these command.
This is my understanding(correct me if wrong)
This is where the variable is called:
$$(call concat_cmd,$$(KERNEL))
1- concat_cmd will call split_args and pass the variable KERNEL and build_cmd to it:
define concat_cmd
$(call split_args,$(1),build_cmd)
endef
2- split_args will substitute the | with a space and call build_cmd,
define split_args
$(foreach data, \
$(subst |,$(space),\
$(subst $(space),^,$(1))), \
$(call $(2),$(strip $(subst ^,$(space),$(data)))))
endef
3- Finally , because KERNEL is defined as KERNEL := kernel-bin | patch-cmdline | lzma | uImage lzma, build_cmd will expand to Build/kernel-bin Build/ patch-cmdline ...
Related
I am working on a book. The chapters will be written in Markdown (.md), and then converted to both html and pdf (via LaTeX) versions using pandoc. Each chapter has a handful of associated Python scripts that generate some images and need to be run before the chapter is built. I am trying to write a makefile that will compile all the chapters to these two formats.
For now, the project is structured as follows:
project
|--- makefile
|--- chapters
| --- chapter1
| --- main.md
| --- genimage.py
| --- genanotherimage.py
| --- chapter2
|--- main.md
|--- otherimage.py
| --- output
| --- html
| --- chapter1.html
| --- chapter2.html
| --- pdf
| --- chapter1.pdf
| --- chapter2.pdf
I would like to type "make chapter1" (or similar) and have it refresh both output/html/chapter1.html and output/pdf/chapter1.pdf, re-running all the .py scripts in the corresponding directory if they have changed. Ideally I would have one rule that handles all the chapters in parallel rather than a separate one for each one. (The actual command generate the html/pdf is "pandoc -o output/html/chapter1.html chapter1/main.md" and so on.)
I am not very familiar with make and my attempts so far have been very unsuccessful. I can't manage to make a target where there are multiple files to update, and I have not managed to use patterns to handle each chapter with a single rule. I am happy to reorganize somewhat if it makes things easier.
Is this workflow possible with a makefile? I am grateful for any hints to get started; I'm at a loss and even just knowing the right things to look up in the manual would be very helpful.
The following is based on the project tree you show and assumes GNU make. It also assumes that you must run pandoc and your python scripts from the top level directory of the project. Pattern rules can probably help:
CHAPTERS := $(notdir $(wildcard chapters/chapter*))
.PHONY: all $(CHAPTERS)
all: $(CHAPTERS)
$(CHAPTERS): %: chapters/output/html/%.html chapters/output/pdf/%.pdf
chapters/output/html/%.html chapters/output/pdf/%.pdf: chapters/%/main.md
for python_script in $(wildcard $(<D)/*.py); do ./$$python_script; done
mkdir -p chapters/output/html chapters/output/pdf
pandoc -o chapters/output/html/$*.html <other-options> $<
pandoc -o chapters/output/pdf/$*.pdf <other-options> $<
The main subtlety is that when GNU make encounters a pattern rule with several targets it considers that one single execution of the recipe builds all targets. In our case the HTML and PDF outputs are produced by the same execution of the recipe.
Note: with recent versions of GNU make rules with grouped targets (&:) do the same.
This is not 100% perfect because a chapter will not be rebuilt if you modify or add python scripts. If you also need this we will need more sophisticated GNU make features like secondary expansion or eval.
Example with secondary expansion:
CHAPTERS := $(notdir $(wildcard chapters/chapter*))
.PHONY: all $(CHAPTERS)
all: $(CHAPTERS)
$(CHAPTERS): %: chapters/output/html/%.html chapters/output/pdf/%.pdf
.SECONDEXPANSION:
chapters/output/html/%.html chapters/output/pdf/%.pdf: chapters/%/main.md $$(wildcard chapters/$$*/*.py)
for python_script in $(wildcard $(<D)/*.py); do ./$$python_script; done
mkdir -p chapters/output/html chapters/output/pdf
pandoc -o chapters/output/html/$*.html $<
pandoc -o chapters/output/pdf/$*.pdf $<
To understand why $$ in $$(wildcard chapters/$$*/*.py) see the GNU make manual.
Example with eval:
CHAPTERS := $(notdir $(wildcard chapters/chapter*))
.PHONY: all $(CHAPTERS)
all: $(CHAPTERS)
$(CHAPTERS): %: chapters/output/html/%.html chapters/output/pdf/%.pdf
# $1: chapter
define CHAPTER_RULE
PYTHON_SCRIPTS_$1 := $$(wildcard chapters/$1/*.py)
chapters/output/html/$1.html chapters/output/pdf/$1.pdf: chapters/$1/main.md $$(PYTHON_SCRIPTS_$1)
for python_script in $$(PYTHON_SCRIPTS_$1); do ./$$$$python_script; done
mkdir -p chapters/output/html chapters/output/pdf
pandoc -o chapters/output/html/$1.html $$<
pandoc -o chapters/output/pdf/$1.pdf $$<
endef
$(foreach c,$(CHAPTERS),$(eval $(call CHAPTER_RULE,$c)))
To understand why $$ or $$$$ see the GNU make manual.
I have a Makefile with user-specified input files in the variable INPUT_FILES.
For each input file, I need to create an input file prime.
Some notes:
Each input file can have an arbitrary file location
It is reasonable to assume there aren't duplicate filenames
Each output file needs to go into $(OUTPUT_DIR)
My basic strategy has been to generate the set of targets based INPUT_FILES and then try to determine which input file is the actual dependency of the target.
A few variations I've tried:
# Create a list of targets
OUTPUT_FILES = $(foreach file,$(notdir $(INPUT_FILES)),$(OUTPUT_DIR)/$(file))
# This doesn't work, because all input files are dependencies of each output file
$(OUTPUT_FILES): $(INPUT FILES)
program --input $^ --output $#
# This doesn't work because $# hasn't been resolved yet
$(OUTPUT_FILES): $(filter,$(notdir $#),$(INPUT FILES))
program --input $^ --output $#
# This doesn't work, I think because $# is evaluated too late
.SECONDEXPANSION:
$(OUTPUT_FILES): $(filter,$(notdir $$#),$(INPUT FILES))
program --input $^ --output $#
# This doesn't work either
.SECONDEXPANSION:
$(OUTPUT_FILES): $$(filter,$(notdir $#),$(INPUT FILES))
program --input $^ --output $#
I've looked into static pattern rules as well, but I'm not sure if it can help with what I need.
In your case .SECONDEXPANSION: works because you can use make functions (filter) to compute the prerequisite of each output file. In other circumstances it could be impossible. But there is another GNU make feature that can be used in cases like yours: if you use GNU make you can programmatically instantiate make statements using foreach-eval-call. Just remember that the macro that is used as the statements pattern gets expanded twice, reason why you must double some $ signs (more on this later):
OUTPUT_DIR := dir
OUTPUT_FILES := $(addprefix $(OUTPUT_DIR)/,$(notdir $(INPUT_FILES)))
.PHONY: all
all: $(OUTPUT_FILES)
# The macro used as statements pattern where $(1) is the input file
define MY_RULE
$(1)-output-file := $(OUTPUT_DIR)/$$(notdir $(1))
$$($(1)-output-file): $(1)
#echo program --input $$^ --output $$#
endef
$(foreach i,$(INPUT_FILES),$(eval $(call MY_RULE,$(i))))
Demo:
$ mkdir -p a/a b
$ touch a/a/a b/b c
$ make INPUT_FILES="a/a/a b/b c"
program --input a/a/a --output dir/a
program --input b/b --output dir/b
program --input c --output dir/c
Explanation:
When make parses the Makefile it expands $(foreach ...): it iterates over all words of $(INPUT_FILES), for each it assigns the word to variable i and expands $(eval $(call MY_RULE,$(i))) in this context. So for word foo/bar/baz it expands $(eval $(call MY_RULE,$(i))) with i = foo/bar/baz.
$(eval PARAMETER) expands PARAMETER and instantiates the result as new make statements. So, for foo/bar/baz, make expands $(call MY_RULE,$(i)) with i = foo/bar/baz and considers the result as regular make statements. The expansion of $(eval ...) has no other effect, the result is the empty string. This is why in our case $(foreach ...) expands as the empty string. But it does something: create new make statements dynamically for each input file.
$(call NAME,PARAMETER) expands PARAMETER, assigns it to temporary variable 1 and expands the value of make variable NAME in this context. So, $(call MY_RULE,$(i)) with i = foo/bar/baz expands as the expanded value of variable MY_RULE with $(1) = foo/bar/baz:
foo/bar/baz-output-file := dir/$(notdir foo/bar/baz)
$(foo/bar/baz-output-file): foo/bar/baz
#echo program --input $^ --output $#
which is what is instantiated by eval as new make statements. Note that we had a first expansion here and the $$ became $. Note also that call can have more parameters: $(call NAME,P1,P2) will do the same with $(1) = P1 and $(2) = P2.
When make parses these new statements (as any other statements) it expands them (second expansion) and finally adds the following to its list of variables:
foo/bar/baz-output-file := dir/baz
and the following to its list of rules:
dir/baz: foo/bar/baz
#echo program --input $^ --output $#
This may look complicated but it is not if you remember that the make statements added by eval are expanded twice. First when $(eval ...) is parsed and expanded by make, and a second time when make parses and expands the added statements. This is why you frequently need to escape the first of these two expansions in your macro definition by using $$ instead of $.
And it is so powerful that it is good to know.
When asking for help please provide some kind of actual example names so we can understand more clearly what you have. It also helps us use terminology which is not confusing.
You really want to use $< in your recipes, not $^, I expect.
IF your "input files" are truly input-only (that is, they are not themselves generated by other make rules) then you can easily solve this problem with VPATH.
Just use this:
VPATH := $(sort $(dir $(INPUT_FILES)))
$(OUTPUT_DIR)/% : %
program --input $< --output $#
I finally found a permutation that works - I think the problem was forgetting that filter requires a % for matching patterns. The rule is:
.SECONDEXPANSION:
$(OUTPUT_FILES): $$(filter %$$(#F),$(INPUT_FILES))
program --input $^ --output $#
I also realized I can use #F (equivalent to $$(notdir $$#)) for cleaner syntax.
The rule gets the target's filename on its second expansion ($$(#F)) and then gets the input file (with path) that corresponds to it on second expansion ($$(filter %$$(#F),$(INPUT_FILES))).
Of course, the rule only works if filenames are unique. If someone has a cleaner solution, feel free to post.
In the following makefile for loop, how can I edit the string, that the i variable represents, with a pattern substitution in the middle of the string? In my case, I wish to replace any / character in the string with a _ character.
for i in $(MODULES:%.cpp=%); do \
g++ -c Sources/$$i.cpp -o Build/$$i.o; \
done
For example if MODULES = Directory/File.cpp then the inner line should expand to
g++ -c Sources/Directory/File.cpp -o Build/Directory_File.o
This answer is valid only with GNU make and bash.
Simple bash substitution (${parameter/pattern/string}) in the context of a make recipe (double $):
for i in $(MODULES:%.cpp=%); do \
g++ -c Sources/$$i.cpp -o Build/$${i//\//_}.o; \
done
Warning: this works only if the shell used by make is bash. So, add maybe a:
SHELL := bash
at the beginning of your Makefile.
Explanation:
${i/X/_} expands as the value of variable i in which the first occurrence of X is replaced by _.
${i//X/_} expands as the value of variable i in which all occurrences of X are replaced by _.
In your case X is the / character and it must be escaped (\/): ${i//\//_}.
Note that there is probably a less bash and more make way to do the same. Something like:
SRCS := $(shell find Sources -type f -name *.cpp)
OBJS :=
define OBJ_rule
obj := Build/$$(subst /,_,$$(patsubst Sources/%.cpp,%,$(1))).o
OBJS += $$(obj)
$$(obj): $(1)
g++ -c $$< -o $$#
endef
$(foreach s,$(SRCS),$(eval $(call OBJ_rule,$(s))))
.PHONY: objs
objs: $(OBJS)
Which instantiates one rule per module and should do the same... with the significant advantage that, when you type make objs, only the outdated object files are rebuilt. But it's a bit more tricky.
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"$
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.
I am getting make file error on line 139 below at $(eval $(RULES))
I am really inexperienced in make file syntax.
This is is error it is giving me when I enter make command.
common.mak:139: *** missing separator. Stop.
I tried to removed the tab by single space, \t nothing works.
Do you know what can be the reason?
Thanks
#
# common bits used by all libraries
#
# first so "all" becomes default target
all: all-yes
ifndef SUBDIR
ifndef V
Q = #
ECHO = printf "$(1)\t%s\n" $(2)
BRIEF = CC CXX HOSTCC HOSTLD AS YASM AR LD STRIP CP
SILENT = DEPCC DEPHOSTCC DEPAS DEPYASM RANLIB RM
MSG = $#
M = #$(call ECHO,$(TAG),$#);
$(foreach VAR,$(BRIEF), \
$(eval override $(VAR) = #$$(call ECHO,$(VAR),$$(MSG)); $($(VAR))))
$(foreach VAR,$(SILENT),$(eval override $(VAR) = #$($(VAR))))
$(eval INSTALL = #$(call ECHO,INSTALL,$$(^:$(SRC_DIR)/%=%)); $(INSTALL))
endif
ALLFFLIBS = avcodec avdevice avfilter avformat avresample avutil postproc swscale swresample
# NASM requires -I path terminated with /
IFLAGS := -I. -I$(SRC_PATH)/
CPPFLAGS := $(IFLAGS) $(CPPFLAGS)
CFLAGS += $(ECFLAGS)
CCFLAGS = $(CPPFLAGS) $(CFLAGS)
ASFLAGS := $(CPPFLAGS) $(ASFLAGS)
CXXFLAGS += $(CPPFLAGS) $(CFLAGS)
YASMFLAGS += $(IFLAGS:%=%/) -Pconfig.asm
HOSTCCFLAGS = $(IFLAGS) $(HOSTCPPFLAGS) $(HOSTCFLAGS)
LDFLAGS := $(ALLFFLIBS:%=$(LD_PATH)lib%) $(LDFLAGS)
define COMPILE
$(call $(1)DEP,$(1))
$($(1)) $($(1)FLAGS) $($(1)_DEPFLAGS) $($(1)_C) $($(1)_O) $<
endef
COMPILE_C = $(call COMPILE,CC)
COMPILE_CXX = $(call COMPILE,CXX)
COMPILE_S = $(call COMPILE,AS)
%.o: %.c
$(COMPILE_C)
%.o: %.cpp
$(COMPILE_CXX)
%.s: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -S -o $# $<
%.o: %.S
$(COMPILE_S)
%.i: %.c
$(CC) $(CCFLAGS) $(CC_E) $<
%.h.c:
$(Q)echo '#include "$*.h"' >$#
%.ver: %.v
$(Q)sed 's/$$MAJOR/$($(basename $(#F))_VERSION_MAJOR)/' $^ > $#
%.c %.h: TAG = GEN
# Dummy rule to stop make trying to rebuild removed or renamed headers
%.h:
#:
# Disable suffix rules. Most of the builtin rules are suffix rules,
# so this saves some time on slow systems.
.SUFFIXES:
# Do not delete intermediate files from chains of implicit rules
$(OBJS):
endif
include $(SRC_PATH)/arch.mak
OBJS += $(OBJS-yes)
FFLIBS := $(FFLIBS-yes) $(FFLIBS)
TESTPROGS += $(TESTPROGS-yes)
LDLIBS = $(FFLIBS:%=%$(BUILDSUF))
FFEXTRALIBS := $(LDLIBS:%=$(LD_LIB)) $(EXTRALIBS)
EXAMPLES := $(EXAMPLES:%=$(SUBDIR)%-example$(EXESUF))
OBJS := $(sort $(OBJS:%=$(SUBDIR)%))
TESTOBJS := $(TESTOBJS:%=$(SUBDIR)%) $(TESTPROGS:%=$(SUBDIR)%-test.o)
TESTPROGS := $(TESTPROGS:%=$(SUBDIR)%-test$(EXESUF))
HOSTOBJS := $(HOSTPROGS:%=$(SUBDIR)%.o)
HOSTPROGS := $(HOSTPROGS:%=$(SUBDIR)%$(HOSTEXESUF))
TOOLS += $(TOOLS-yes)
TOOLOBJS := $(TOOLS:%=tools/%.o)
TOOLS := $(TOOLS:%=tools/%$(EXESUF))
HEADERS += $(HEADERS-yes)
DEP_LIBS := $(foreach NAME,$(FFLIBS),lib$(NAME)/$($(CONFIG_SHARED:yes=S)LIBNAME))
SRC_DIR := $(SRC_PATH)/lib$(NAME)
ALLHEADERS := $(subst $(SRC_DIR)/,$(SUBDIR),$(wildcard $(SRC_DIR)/*.h $(SRC_DIR)/$(ARCH)/*.h))
SKIPHEADERS += $(ARCH_HEADERS:%=$(ARCH)/%) $(SKIPHEADERS-)
SKIPHEADERS := $(SKIPHEADERS:%=$(SUBDIR)%)
HOBJS = $(filter-out $(SKIPHEADERS:.h=.h.o),$(ALLHEADERS:.h=.h.o))
checkheaders: $(HOBJS)
.SECONDARY: $(HOBJS:.o=.c)
alltools: $(TOOLS)
$(HOSTOBJS): %.o: %.c
$(call COMPILE,HOSTCC)
$(HOSTPROGS): %$(HOSTEXESUF): %.o
$(HOSTLD) $(HOSTLDFLAGS) $(HOSTLD_O) $< $(HOSTLIBS)
$(OBJS): | $(sort $(dir $(OBJS)))
$(HOBJS): | $(sort $(dir $(HOBJS)))
$(HOSTOBJS): | $(sort $(dir $(HOSTOBJS)))
$(TESTOBJS): | $(sort $(dir $(TESTOBJS)))
$(TOOLOBJS): | tools
OBJDIRS := $(OBJDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(TESTOBJS))
CLEANSUFFIXES = *.d *.o *~ *.h.c *.map *.ver *.ho *.gcno *.gcda
DISTCLEANSUFFIXES = *.pc
LIBSUFFIXES = *.a *.lib *.so *.so.* *.dylib *.dll *.def *.dll.a
define RULES
clean::
$(RM) $(OBJS) $(OBJS:.o=.d)
$(RM) $(HOSTPROGS)
$(RM) $(TOOLS)
endef
$(eval $(RULES))
-include $(wildcard $(OBJS:.o=.d) $(HOSTOBJS:.o=.d) $(TESTOBJS:.o=.d) $(HOBJS:.o=.d))
I experienced that same issue when trying to configure ffmpeg for make.
With the current version of ffmpeg's master branch the issue occurs for common.mak at line 160.
To solve this issue I tried the following steps:
git config core.autocrlf false
delete all *.mak files
git reset --hard
These steps alone did not fully solve my problem. Based on the hints regarding the TAB (\t) characters I changed line 160 from
to
Note the arrow (indicating a TAB) at line 160 between $( and eval $(RULES)).
This TAB solved the problem for me. I had to make this change to a further *.mak file. There was the same error message for another file. By the way, Notepad++ is a great tool to insert a TAB as well as for changing the line endings.
Since ffmpeg takes a while for building I decided to share my solution...
I had this exact same issue - when also checking out FFMPEG on Windows but using git.
After running configure and when trying to run make I got the same line:
common.mak:139: *** missing separator. Stop.
As suggested by #MadScientist - Makefiles are particularly fussy not just about tab (\t) but also the choice of line ending (LF vs. CRLF).
This is down to the GNU make command which has to run them - which seems to only respect LF.
So a *nix version, such as this, will work:
And here is the same file under Windows, which won't work:
(Another giveaway is that it is also bigger with double the bytes at the end of each line!)
Bottom line (so to speak) is that you might have to reformat your files - perhaps by using the dos2unix command.
This would still be the case even if not directly cloning from git - but instead downloading a tar/zip that was itself created from a git clone. The end of lines would be preserved.
Or, if using Git (directly as I was) you have to tell it how to handle the end of line characters. When it checks-out/clones and when it commits.
There is a full description of what this means here: http://adaptivepatchwork.com/2012/03/01/mind-the-end-of-your-line/
And how it can be configured (for the old version of git) via the [core].eol setting.
This is also apparent on Windows, when if you run the installer (e.g. http://git-scm.com/downloads) you get a dialogue such as this:
Selecting the final option to "checkout as-is, commit as-is" fixed it for me. Not perhaps the most principled way, but it forced the LF endings to be preserved.
In makefiles, recipe lines MUST start with a TAB character (TAB must be the first character on the line). You cannot have one or more spaces at the beginning of the line, either with or without a following TAB.
I don't know what you mean by: I tried to removed the tab by single space, \t nothing works; that sentence doesn't make sense to me. Hopefully the above paragraph will help you understand what you need to do.
Be sure you're using a text editor (not a word processor) and that your editor doesn't try to "helpfully" change the formatting in your files.
In general, unless you're more experienced with makefiles I don't recommend using the eval function, which requires a pretty clear understanding of the rules make uses for expanding variables and functions to use correctly. I'm not really sure why you're using eval in the context of the RULES variable, anyway; why not just write the rule directly without eval?