This a Makefile:
all:
ifeq (0,0)
echo hello
endif
Note: there is a tab before if, echo, and endif.
Giving make I get:
ifeq (0,0)
/bin/sh: -c: line 0: syntax error near unexpected token `0,0'
/bin/sh: -c: line 0: `ifeq (0,0)'
make: *** [Makefile:2: all] Error 1
Why is it so?
The trouble is that each line in a recipe runs in its own subshell, so the entire conditional must be in one line or it won't work. I'm not sure which shell you're using, but I presume you've tested this conditional on the command line and it works:
ifeq (0,0)
echo hello
endif
Without the right shell I can't test it, but I think you could also do something like this:
ifeq (0,0); echo hello; endif
If so, then it will also work in the makefile:
all:
ifeq (0,0); echo hello; endif
The lines can then be wrapped using backslashes:
all:
ifeq (0,0);\
echo hello;\
endif
(Note that the only TAB needed is before the ifeq.)
Related
I have a Makefile with command like this:
#Makefile
hello:
echo 'hello'
echo $(TAG)
ifdef TAG
$(warning MYWARNING)
else
$(error MYERROR)
endif
I use it like:
# make TAG='1.0' hello
I expect that command performs echo 'hello', then echo $(TAG) and $(warning MYWARNING) but I get:
Makefile:17: MYWARNING
Makefile:19: *** MYERROR. Stop.
What is wrong?
Let's try some simpler cases(*).
hello:
echo hello
$(error MYERROR)
This produces:
Makefile:3: *** MYERROR. Stop.
Notice that the error blocks the echo, even thought it comes afterward.
Now let's try something silly:
hello:
ifdef TAG
The result is:
ifdef TAG
make: ifdef: No such file or directory
"ifdef TAG", interpreted as a shell command, makes no sense. And it is interpreted as a shell command because it's in a recipe and preceded by a TAB.
Now let's combine them:
hello:
ifdef TAG
$(error MYERROR)
The result is Makefile:3: *** MYERROR. Stop. So the error obscures the fact that the ifdef... was incorrect.
Do we want a shell conditional, or a Make conditional? If we want to Make to act on it (with error or warning), then it must be a Make conditional, so we must not preceded it with a TAB:
hello:
ifdef TAG
$(warning MYWARNING)
else
$(error MYERROR)
endif
This works as intended.
(*) as you ought to have tried before you posted.
Is there a way to conditionally include a sub-Makefile based on the result of a an ifeq test as suggested below
CC = g++
CENTOS_VERSION := $(shell rpm -E %{rhel})
TARGET = main
$(TARGET): $(TARGET).cpp
ifeq ($(CENTOS_VERSION),6)
#echo "Building on CentOS 6"
include(CentOS6_Makefile.mk)
else
#echo "Building on CentOS 7"
include(CentOS7_Makefile.mk)
endif
$(CC) $(CFLAGS) -o $(TARGET) $(TARGET).cpp
This does not work and generates the error message
Building on CentOS 6
include(CentOS6_Makefile.mk)
/bin/sh: -c: line 0: syntax error near unexpected token `CentOS6_Makefile.mk'
/bin/sh: -c: line 0: `include(CentOS6_Makefile.mk)'
make: *** [main] Error 1
Based on the answer by #MadScientist the solution to my problem boils down to just 2 lines
CENTOS_VERSION := $(shell rpm -E %{rhel})
include CentOS$(CENTOS_VERSION)_Makefile.mk
Your problem is not related to ifeq; if you remove the ifeq and always include one or the other you'll see the same problem.
First, your syntax for including files is wrong. There are no parentheses around filenames in make's include directive. It should just be:
include CentOS6_Makefile.mk
Second, you cannot use makefile processor commands like include as part of a recipe (that is, indented by a TAB). In a make recipe ALL lines that indented by TAB are passed to the shell as commands to run to build the target, they are not interpreted by make (except to expand macros). Also, you cannot include some other makefile in the middle of a recipe: once make starts to include a new makefile that's the end of any recipe that is currently being defined.
You can do this:
CENTOS_VERSION := $(shell rpm -E %{rhel})
ifneq ($(CENTOS_VERSION),6)
CENTOS_VERSION := 7
endif
include CentOS$(CENTOS_VERSION)_Makefile.mk
$(TARGET): $(TARGET).cpp
#echo "Building on CentOS $(CENTOS_VERSION)"
$(CC) $(CFLAGS) -o $(TARGET) $(TARGET).cpp
I have a rule like below just for test
test:
ifeq (1,1)
$(info --)
endif
echo kkk
when I run make test, it shows
makefile:41: *** commands commence before first target. Stop.
What is wrong?
edit
according to Florian Weimer, we should indent the $(info --) line. But If I write
test:
ifeq (1,1)
$(info --)
endif
echo kkk
test2:
ifeq (1,1)
$(info --)
endif
echo kkk
then make test will complain that
makefile:11: *** commands commence before first target. Stop.
So doesn't make always scan the whole makefile? It seems that it doesn't stop after rule test is finished
You need to tab-indent the $(info --) line, so that it does not terminate the recipe, like this:
test:
ifeq (1,1)
$(info --)
endif
echo kkk
(Obviously, you need to use tabs here.)
EDIT The make documentation of conditional blocks consistently uses tab indentation within recipes, and spaces or no indentation outside of recipes. This is why there are both styles.
The full example works for me if I indent both $(info --) lines.
I'm picking up some old code that is out of my norm and running into some issues over something that is hopefully very simple to explain.
I'm working on a makefile that runs a number of SQL files then generates .done files to track the progress. After one specific SQL file, I need to be able to run a shell script to do some additional processing.
# this is the rule the describes how to execute a SQL script
%.done: %.sql
#echo "+==============================================================================+"
#echo "building $#"
#echo "...from $<"
#echo "building $<"
#$(PSQL_WRAPPER) -f $<
#ifeq ($(#),mysqlfile.done)
#echo "Executing Shell Script"
#../path/to/script/myscript.sh
endif
I added the ifeq portion, everything else was there before and works as expected.
Here's the output I'm getting. I'm really stuck and have been trying different little syntax tweaks, but there's clearly something else I'm just not understanding.
+==============================================================================+
building mysqlfile.done
...from ../..//path/to/file/mysqlfile.sql
building ../..//path/to/file/mysqlfile.sql
/bin/bash: -c: line 0: syntax error near unexpected token `mysqlfile.done,mysqlfile.done'
/bin/bash: -c: line 0: `ifeq (mysqlfile.done,mysqlfile.done)'
make: *** [mysqlfile.done] Error 1
Command exited with non-zero status 2
From the error message, it looks like I have two equal values. I'm really not sure what the unexpected token would be.
ifeq is a GNU Make directive,
for conditionally including or excluding a part of a parsed makefile. It is not a shell command.
You are using it in one of the lines of the %.done: %.sql recipe.
All lines of a recipe must be shell commands. Just use shell:
%.done: %.sql
#echo "+==============================================================================+"
#echo "building $#"
#echo "...from $<"
#echo "building $<"
#$(PSQL_WRAPPER) -f $<
#if [ "$#" = "mysqlfile.done" ]; then \
echo "Executing Shell Script"; \
../path/to/script/myscript.sh; \
fi
You cannot conditionally exclude the special-case processing from the recipe itself,
like:
%.done: %.sql
#echo "+==============================================================================+"
#echo "building $#"
#echo "...from $<"
#echo "building $<"
#$(PSQL_WRAPPER) -f $<
ifeq ($(#),mysqlfile.done)
#echo "Executing Shell Script"
#../path/to/script/myscript.sh
endif
because the target $(#) of the rule is only defined within the recipe.
I still get error when i try run this
OS=$(shell uname -s)
#################################################################
printVar:
ifeq ($(OS),Darwin)
#echo $(OS)
endif
all:
make -j3 -f $(MAKEFILE)
terminal
$ make printVar
ifeq (Darwin,Darwin)
/bin/sh: -c: line 0: syntax error near unexpected token `Darwin,Darwin'
/bin/sh: -c: line 0: `ifeq (Darwin,Darwin)'
make: *** [printVar] Error 2
You don't want a tab before ifeq/endif as they are not commands:
OS=$(shell uname -s)
#################################################################
printVar:
ifeq ($(OS),Darwin)
#echo $(OS)
endif
all:
make -j3 -f $(MAKEFILE)