getting "*** missing separator. Stop." from makefile, already checked for tabs - makefile

Here is the makefile, the error is coming from line 5 ifeq($(PROD),all)
APP=all
LOC=en_US
html: loc
ifeq($(APP),all)
#for app in apps/*; do echo "Building $app"; grunt --prod $app --loc $(LOC); done
else
#grunt --prod $(APP) --loc $(LOC)
endif
loc:
ifeq($(LOC),en_US)
#echo "Building $(LOC)"
else ifeq($(LOC),zh_CN)
#echo "Building $(LOC)"
else
#echo "Invalid LOC $(LOC)" && exit 1;
endif
From what I can tell from other stackexchange answers, this issue usually occurs when there are missing tabs, but I have checked that there are tabs for all of the sh code that needs running

Found it, there have to be spaces after ifeq statements.
html: loc
ifeq ($APP,all)

Related

Makefile Argument string comparision

I am passing an argument to makefile target. I want to do string compare of the argument. This is my code,
mode = p
install:
#echo mode is $(mode)
ifeq ($(mode),"p")
#echo mode is production
else
#echo mode is development
endif
I get the following error as,
mode is d
ifeq (d,"p")
/bin/sh: 1: Syntax error: word unexpected (expecting ")")
What is the error and what is General rule for comparing strings in bash scripts?
You are using pure make syntax (ifeq) as a recipe (the line starts with a tab). Try this, instead:
mode = p
install:
#echo mode is $(mode)
ifeq ($(mode),p)
#echo mode is production
else
#echo mode is development
endif

Bad comportement while check error during makefile

I want to make automatically the documentation of my project with my makefile.
I also create a target doc (and a variable DOC_DIRECTORY = ../doc) to specify the directory of the documentation. In my doxygen file, I added a log file name "doxyLog.log" in the ../doc/ directory.
Here is my target definition :
#Creation of the Doxygen documentation
doc: $(DOC_DIRECTORY)/path_finder_doc
doxygen $(DOC_DIRECTORY)/path_finder_doc
#echo $(shell test -s ../doc/doxyLog.log; echo $$?)
ifeq ($(shell test -s ../doc/doxyLog.log; echo $$?),1)
#echo "Generation of the doxygen documentation done"
else
#echo "Error during the creation of the documentation, please check $(DOC_DIRECTORY)/doxyLog.log"
endif
To test if my check is working, I manually introduce an error in my documentation (a bad command like \retufjdkshrn instead of \return). But, when I launch the make doc, this error appears after the second time :
First make doc (with an error in the doc ) --> Generation of the doxygen documentation done
Second make doc (always the error in the doc) --> Error during the creation of the documentation, please check ../doc/doxyLog.log
I don't understand why, can someone help me please?
There appear to be two things wrong here, so parts of this answer must be guesswork.
First:
ifeq ($(shell test -s ../doc/doxyLog.log; echo $$?),1)
#echo "Generation of the doxygen documentation done"
As I understand test, it will return 0 if the file exists and 1 if the file does not exist. I suspect that you didn't test this before putting it into your makefile.
Second, you are confusing shell commands with Make commands. This:
ifeq ($(shell test -s ../doc/doxyLog.log; echo $$?),1)
#echo "Generation of the doxygen documentation done"
else
#echo "Error..."
endif
is a Make conditional. Make will evaluate it before running any rule. Since the log file does not yet exist, the shell command will return 1 (see First), the conditional will evaluate to true and the entire if-then-else statement will become
#echo "Generation of the doxygen documentation done"
This will become part of the rule before the rule is executed. On the next pass, the file already exists, the shell command returns 0 and the the statement becomes
#echo "Error..."
This explains why you're getting strange results.
If you want Make to report on the results of the attempt it's just made, you must put a shell conditional in a command in the rule:
doc: $(DOC_DIRECTORY)/path_finder_doc
doxygen $(DOC_DIRECTORY)/path_finder_doc
#if [ -s ../doc/doxyLog.log ]; then echo Log done; else echo error...; fi

Makefile conditional error

I am attempting to do a make statement to check the architecture. I am very close to getting it to work:
test:
ifeq ("$(shell arch)", "armv7l")
echo "This is an arm system"
else
echo "This is not an arm system."
endif
I have one issue: although this seems to resolve to ifeq ("i386", "armv7l") which should be false, I get the following error:
$ make
ifeq ("i386", "armv7l")
/bin/sh: -c: line 0: syntax error near unexpected token `"i386",'
/bin/sh: -c: line 0: `ifeq ("i386", "armv7l")'
make: *** [test] Error 2
So, it is resolving to two strings comparing to each other, but there is a syntax error. What's wrong here?
You cannot use make statements like ifeq inside a recipe. Recipes (the lines that begin with TAB) are passed to the shell. The shell doesn't understand ifeq; that's a make construct.
You'll have to use shell if-statements inside a recipe. And, you don't have to use $(shell ...) in a recipe, because you're already in a shell.
test:
if [ `arch` = armv7l ]; then \
echo "This is an arm system"; \
else \
echo "This is not an arm system."; \
fi
This is likely not the best way to handle this, but since you didn't provide any info on what you're really trying to do with this it's all we can say.
As MadScientist said, make is passing the ifeq lines to the shell, but if you write it properly, you can definitely mix make constructs like ifeq with commands within a recipe. You just need to understand how make parses a Makefile:
If a line begins with a TAB, it is considered a command for the shell regardless of where the line is within the file.
If it doesn't begin with a TAB, make interprets it as part of its own language.
So, to fix your file, just avoid starting the make conditionals with a TAB:
test:
ifeq ("$(shell arch)", "armv7l")
echo "This is an arm system"
else
echo "This is not an arm system."
endif

Using conditional rules in a makefile

I capture the intent of the Makefile in pseudo code, then indicate the issues I have. I'm looking for a Makefile which is more user friendly in a test environment. The correct usage of the Makefile is one of the below.
make CATEGORY=parser TEST=basic.
make ALL
If a user gives "JUST" the commands as indicated below, it should print a message saying "CATEGORY defined TEST undefined" and vice-versa
make CATEGORY=parser
make TEST=basic
I tried writing the Makefile in following ways, but it errors out:
help:
echo"Usage: make CATEGORY=<advanced|basic> TEST=<test-case>
echo" make ALL
ifdef CATEGORY
ifdef TEST
CATEGORY_TEST_DEFINED = 1
else
echo "TEST not defined"
else
echo "CATEGORY not defined"
endif
ifeq ($(CATEGORY_TEST_DEFINED), 1)
$(CATEGORY):
cd $(PROJ)/$(CATEGORY)
make -f test.mk $(TEST)
endif
ifdef ALL
$(ALL):
for i in `ls`
cd $$(i)
make all
endif
The questions I have are:
Whether the rules in a Makefile can be selective (using ifdef to select the rules and targets).
echo doesn't work. echo should help the user with correct usage.
The problem is that echo belongs to the shell; Make can pass it to the shell in a command, but Make cannot execute it. Use info instead:
ifdef CATEGORY
$(info CATEGORY defined)
else
$(info CATEGORY undefined)
endif
If you want the rules to be conditional:
ifdef CATEGORY
ifdef TEST
$(CATEGORY):
whatever
else
$(info TEST not defined)
else
$(info CATEGORY not defined)
endif
The biggest issue here is that all ifdef/ifndef/ifeq/... statements must be at column 0 or they it will results in an error. The echo is a minor issue compared with the indentation issue.
These lines are dubious:
help:
echo"Usage: make CATEGORY=<advanced|basic> TEST=<test-case>
echo" make ALL
You need a space between echo and the string, and the string needs to be terminated:
help:
echo "Usage: make CATEGORY=<advanced|basic> TEST=<test-case>"
echo " make ALL"
These lines are dubious:
ifdef CATEGORY
ifdef TEST
CATEGORY_TEST_DEFINED = 1
else
echo "TEST not defined"
else
echo "CATEGORY not defined"
endif
Surely you need an endif before the second else? (Even if it is not syntactically mandatory, I'd recommend it.)
ifdef CATEGORY
ifdef TEST
CATEGORY_TEST_DEFINED = 1
else
echo "TEST not defined"
endif
else
echo "CATEGORY not defined"
endif
Additionally, make only executes commands such as echo is supposed to be when processing a target (rule). It won't execute echo there; it will simply object that you cannot define commands without them being actions for a target. Despite everything that GNU Make adds to a makefile, the language in a makefile is a declarative language and not a procedural language.
Another way of handling this is to define default values for the macros:
CATEGORY = advanced
TEST = all
Define default values that do something semi-reasonable; let the user override the default if they want to. You can have a rule such as:
${CATEGORY}/${TEST}: ...dependencies...
...actions...
You can leave help as the first rule. I have some directories where the first rule is:
null:
#echo "You must specify a target with this makefile!"
This is equivalent to what you have (except that make does not echo the command before running it, so I only see the message instead of the echo command line and the message; that's the # at work). The makefile this comes from also has a rule all which is otherwise usually the most sensible first (default) rule.

Conditional statements depending on successful compilation within a Makefile

For a makefile, I am trying to make it run a block of code in case of successful compilation, or an else block otherwise.
I have tried something like this
default:
ifeq ($(gcc -obuild main.c), 0)
echo "successful"
else
echo "you fail lol"
endif
But I cannot get the compilation command to be evaluated as my code suggests that I want. I thought that it could work like Bash but it seems that not, or I am missing something I dont know.
How can I accomplish this task?
Do it with the shell, not with Make:
default:
if gcc -obuild main.c ; then \
echo "sucessful" ; \
else echo "you fail" ; fi
Note that only the first line of the commands (if...) starts with a tab.

Resources