I am getting the following error when try to run make:
Makefile:1: *** missing separator. Stop.
Looks like I need to use tab on my first line.
However, first 3 lines of my Makefile is like this.
[ -z "${PROJ_DIR}" ] && PROJ_DIR=/home/my_directory
[ -z "${BASE_DIR}" ] && BASE_DIR=/home/my_directory
[ -z "${TOOLCHAIN}" ] && TOOLCHAIN=${BASE_DIR}/mips-4.3
There is no where for any space modification.
I am lost to what the error could be.
That's not even close to correct makefile syntax.
PROJ_DIR ?= /home/my_directory
BASE_DIR ?= /home/my_directory
TOOLCHAIN ?= $(BASE_DIR)/mips-4.3
Related
Having this simple makefile rule:
exe:
for i in *; do [ -x "$$i" ] && echo "$$i"; done
Will output:
for i in *; do [ -x "$i" ] && echo "$i"; done
executablefile
make: *** [makefile:6: exe] Error 1
So it does, what I want, but even then, error with no other message. But not only for this particular example (which I still do not get), I would like to know, how to get some more info from bugs in makefile (is there a makefile debugger?). From makefile manual the *** is for fatal error, which ends compilation, but yet it outputs the executablefile (so it did compiled to that point). Apart from fatal error, - warnings give more info, so why do not do fatal errors as well?
explanation of this example
some advices how to debug makefile scripts
This is not an error from make, that's why there's no other information.
Make runs a shell and gives the shell your recipe to invoke. If the shell exits with success (exit code 0) then make assumes that the command it ran worked. If the shell exits with failure (any exit code other than 0), then make assumes the command it ran failed. Make doesn't know why it failed, make assumes that whatever command failed will have printed some information about why. All make knows is the exit code, so that's all make can tell you:
make: *** [makefile:6: exe] Error 1
This means that make ran the recipe for target exe at makefile line number 6, and that command exited with an error code 1 (which is not 0, hence a failure).
Why did this happen? Let's look at your shell script:
for i in *; do [ -x "$$i" ] && echo "$$i"; done
Let's suppose the last file matching * (so the last time we go through the loop) the file is not executable. That means the test of the last file [ -x "$$i" ] will fail. Since that's the last command that the shell runs before it exits, that will be the exit code of the shell, and you have a failure.
You need to be sure that the shell exits with success. One way to do that is ensure the last command the shell runs is always success; maybe something like this:
for i in *; do [ -x "$$i" ] && echo "$$i"; done; true
I am trying to use rm command in ifeq condition in a makefile, but I was encountering error saying missing separator. May I pls know if we can't use rm command in makefile if it's a non-target.
To avoid removing work/*.elf manually, I tried adding the below highlighted line in cfg.mk, however I was getting ‘missing separator error’ (at that highlighted line)
ifeq ($(EN_DBG_MSGS),1)
rm $(CFG_DIR)/work/*.elf #throws error
export CARGS += -DDBG_MSGS_FLAG
endif
I even tried below line but unsuccessful.
if [ -a $(CFG_DIR)/work/$(TEST).elf ]; then rm -r $(CFG_DIR)/work/$(TEST).elf; fi
May I pls know if I am missing anything here.
rgds
Kishore
I found that I can use ifneq in makefile and I tried to compare 0 and the output of command stat:
#for f in `find $(PATH_PAGES) -name *.hbs`; do \
ifneq "`stat -c '%Y' $$f`" "0";
//some code here
endif
done
But in terminal I've got an error: ifneq: command not found
Is there a different way to compare this or maybe I'm doing something wrong?
In this case you don't want to use Make's ifneq, because it does text substitution before handing over the command to the shell, but you have a shell loop that needs to do different things in each iteration depending on the output of a shell command.
Use the shell if instead:
if [ "`stat -c '%Y' $$f`" != "0" ]; then
//some code here
fi
If you want to use makefile's if condition then there should not be [TAB] before the if statement because if you specify [TAB] then it is treated as shell command thats why you are getting error that ifneq:command not found its not there in shell.
May be this Conditionals in Makefile: missing separator error?
can help in getting better understanding with makefiles
I found that I needed to prepend the if with a #, and backslashes proved to be necessary as well -
#if [ "`stat -c '%Y' $$f`" != "0" ]; then\
echo hello world;\
fi
I googled for this, but I can't figure out why Bash complains with the following code to check if a directory exists:
test.mk
#!/bin/bash
MYDIR="dl"
all:
if [ ! -d $MYDIR ]; then
#if [ ! -d "${MYDIR}" ]; then
#if [ ! -d ${MYDIR} ]; then
#Here
fi
make -f test.mk
if [ ! -d YDIR ]; then
/bin/sh: Syntax error: end of file unexpected
make: *** [all] Error 2
Does someone know why it fails? And why does it call /bin/sh instead of /bin/bash? Thank you.
Edit: unlike Bash, make doesn't support multi-line block. Here's working code:
MYDIR="dl"
all:
if [ ! -d ${MYDIR} ]; then\
echo "Here";\
else\
echo "There";\
fi
The #!/bin/bash shebang that you inserted at top is useless, and it is treated by make as a comment.
make sends by default commands to /bin/sh. To specify a different shell, use the macro SHELL = /bin/bash.
Moreover, you need to escape your variable:
if [ ! -d ${MYDIR} ]
I'm not sure if make can handle multi-line statements, so try to put all the if block in a line.
if [ ! -d ${MYDIR} ]; then DO_SOMETHING; DO_SOMETHING_ELSE; fi
You're feeding test.mk to make, not to bash. Then make sends individual lines to the shell, not whole blocks.
make uses its SHELL macro to determine which shell to use. You can override it to make it use bash.
The reason why you're getting YDIR is that make has silly rules about variable interpolation. Write $(MYDIR), not $MYDIR.
try bracing your variable:
${MYDIR}
It is hard to believe, but it seems to me that the common Makefile idiom "> $#" is wrong. In particular, a target whose rule has a command that fails but uses this redirection will fail the first time around but not subsequent times. This is because even though the command fails, the redirection "succeeds" in the sense of creating an up-to-date (albeit zero-length) target.
It seems to me that the correct thing to do is to redirect to a temporary and on success rename this temporary to the target.
Here's and example Makefile:
bad-target:
command-that-will-fail > $#
good-target:
command-that-will-fail > $#.tmp || ( rm $#.tmp; false )
mv $#.tmp $#
clean:
rm -f bad-target good-target
And here's a sequence of commands illustrating the problem and its solution:
$ make clean
rm -f bad-target good-target
$ make bad-target
command-that-will-fail > bad-target
/bin/sh: command-that-will-fail: not found
make: *** [bad-target] Error 127
$ make bad-target
make: `bad-target' is up to date.
$ make good-target
command-that-will-fail > good-target.tmp || ( rm good-target.tmp; false )
/bin/sh: command-that-will-fail: not found
make: *** [good-target] Error 1
$ make good-target
command-that-will-fail > good-target.tmp || ( rm good-target.tmp; false )
/bin/sh: command-that-will-fail: not found
make: *** [good-target] Error 1
If you're using GNU make, you may also add the .DELETE_ON_ERROR special target to your makefile. This will cause make to delete the output file if there is an error during execution of the commands for that file:
all: foo.o
foo.o:
echo bogus! > $#
exit 1
.DELETE_ON_ERROR:
Here's an example of this makefile in action:
$ gmake
echo bogus! > foo.o
exit 1
gmake: *** [foo.o] Error 1
gmake: *** Deleting file `foo.o'
This is easier to use than your version, since you need not modify every rule in the makefile.
Perhaps this is an obvious solution, but many common commands provide a -o flag or similar. So instead of output redirection, you should use the rule:
target: target.dep
some_command target.dep -o $#
If the command fails, the output file will not be created. I haven't had many occasions to use output redirection in makefiles.
Yes, this is definitely something to bear in mind.
But sometimes you're OK with the command failing and you don't want to retry it, because the error would only repeat itself.
In that case leaving an empty result is OK. Just don't make subsequent processing count on there being meaningful content in that file.