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
Related
I am attempting to use an inheritance hack (which is already working) along with checking a file date to create a sort of reusable, auto-updating base makefile from which multiple projects can inherit; and which will update the parent Makefile using a git pull, but (and this is where I'm stuck) I only want it to try the git pull once per day, so that it doesn't add up to a lot of wasted time waiting on a git pull when the chance of updates being available is almost nothing.
The basic idea is this:
baseMakefilePath=../../baseMakefile
do_some_work: .check-for-update
#echo "working..."
.check-for-update:
# is the file > 24 hours old?
ifeq ( $(find . -mtime +24h -name '.check-makefile-update'), ./.check-makefile-update )
#make .update
else
# if the file doesn't exist at all yet, pull the update
ifeq ( $(find . -name '.check-makefile-update'), '' )
#make .update
else
#echo "last update was recent, not updating..."
endif
endif
.update:
cd $(baseMakefilePath) && git pull
touch .check-makefile-update
My theory is that by updating the modified timestamp on the .check-makefile-update file using touch it should only run the git pull once per day.
However, I can't even get a dirt simple ifeq() conditional to work:
test:
ifeq (a, a)
#echo "a basic test works"
else
#echo "idunno"
endif
With this basic Makefile (note: this is the ONLY contents of the Makefile when I test it), I get this error:
$ make test
ifeq (a, a)
/bin/sh: -c: line 0: syntax error near unexpected token `a,'
/bin/sh: -c: line 0: `ifeq (a, a)'
make: *** [test] Error 2
I get the same result if I try to run the first Makefile:
$ make do_some_work
# is the file > 24 hours old?
ifeq ( , ./.check-makefile-update )
/bin/sh: -c: line 0: syntax error near unexpected token `,'
/bin/sh: -c: line 0: `ifeq ( , ./.check-makefile-update )'
make: *** [.check-for-update] Error 2
I think the stripped down example shows that there's something funky going on (or my understanding of ifeq is fundamentally flawed) but for what it's worth, I also tried quoting various combinations of the ifeq arguments, with both single and double quotes.
I'm out of ideas, but I feel like I'm sooo close to a working solution! What am I doing wrong?
If it matters, I'm on OSX 10.14.5, and my primary shell is zsh. It is not an absolute requirement but would be good if the solution can also run on modern versions of Windows (with WSL), too.
Remember that there are Make conditionals, and shell conditionals.
Here:
test:
ifeq (a, a)
#echo "a basic test works"
else
#echo "idunno"
endif
I assume you're trying to use a Make conditional, but if those whitespace margins are TABs, then you're inadvertantly telling Make that those lines are shell commands which it should pass to the shell as they are. The shell tries to interpret ifeq (a, a) and complains of a syntax error.
Remove some of the TABs (leaving the ones in front of the actual shell commands):
test:
ifeq (a, a)
#echo "a basic test works"
else
#echo "idunno"
endif
and it works.
Your understanding of ifeq is fundamentally flawed :)
A makefile is a combination of two different syntaxes: the makefile itself is written in make syntax, and the recipes are written in shell syntax.
Those two syntaxes are not in any way compatible: you can't use make syntax when you are writing recipes and you can't use shell syntax when you are writing makefiles.
How do you know which is which? The simplest way to think about it is that if the first character on your line is indented with a TAB character, it's shell syntax and if it's not, it's make syntax. The reality is more subtle but that rule is always true.
I'm sure you can now see what's wrong with your makefile AND also why you get the errors you do:
test:
ifeq (a, a)
#echo "a basic test works"
else
#echo "idunno"
endif
you are trying to pass make syntax to the shell.
I've been given a makefile for ubuntu, and I'm trying to use it with nmake on Windows 10.
nmake doesn't seem to recognize the filter-out keyword such as in the following line:
OBJS_TEST = $(filter-out $(EXE_OBJ), $(OBJS))
Does nmake have a keyword with the same functionality?
For completeness, the lines from the beginning of the file before the above line (and a few lines below) are as follows:
EXE = main
TEST = test
OBJS_DIR = .objs
###############################################
### THE LINE IN QUESTION IS BELOW #############
OBJS_TEST = $(filter-out $(EXE_OBJ), $(OBJS))
###############################################
CPP_TEST = $(wildcard tests/*.cpp)
# CPP_TEST += uiuc/catch/catchmain.cpp
# The above line doesn't work with the "+=" extension in nmake; replace with below.
CPP_TEST = $(CPP_TEST) $(wildcard tests/*.cpp)
The error reported is:
fatal error U1001: syntax error : illegal character '-' in macro
As far as I'm aware there is no equivalent to filter-out in nmake. Also, nmake does not support the wildcard function so you'll have to deal with that. And, I'm suspicious that your replacement for += won't work; in most versions of POSIX make FOO = $(FOO) is illegal as it gives an infinite loop of variable lookup. Maybe nmake works differently, though.
nmake is SO different from POSIX make and GNU make that you will either have to rewrite the makefile from scratch, or else just go get a version of GNU make for Windows (or build it yourself). GNU make is quite portable and runs well on Windows. That would be a LOT less work.
I have a very simple makefile as follows
FRUIT = apple orange
all : $(FRUIT)
$(FRUIT) :
ifeq ($(#),apple)
#echo "APPLE!"
else
#echo "ORANGE!"
endif
When I execute
make all
I see
ORANGE!
ORANGE!
I have checked my tabbing and I believe my spacing on ifeq is correct. What have I missed?
The ifeq is evaluated when the Makefile is first parsed, not when the individual recipe is executed. At that point, $(#) is always the empty string.
You can perform the same logic in shell script in the recipe itelf.
$(FRUIT):
case $# in apple) echo "APPLE!";; *) echo "ORANGE!";; asac
Conditional directives are expanded as soon as make reads them, long before the recipe is executed. $#expands to the empty string when make parses that line so you always end up with the else part of the conditional.
Just use something like the following instead:
FRUIT = apple orange
all: $(FRUIT)
$(FRUIT):
#echo "$#!"
If you need separate recipes then write them
apple:
#echo "APPLE!"
orange:
#echo "ORANGE!"
I have attached the sample of the make file.
# SELECT TARGET OPERATING SYSTEM
override OS = LINUX
#OS = WINDOWS
CC = gcc
SRC_DIR = src
INC_DIR = inc
OBJ_DIR = obj
CFLAGS = -c -Wall -I$(INC_DIR)
# CONDITIONAL COMPILATION
ifeq ($(OS), "WINDOWS")
SERIAL = Winsrcfile
CLEAR = cls
endif
ifeq ($(OS), "LINUX")
SERIAL = Linsrcfile
CLEAR = clear
endif
I am trying to achieve this...
make OS=WINDOWS // compile for windows
or
make OS=LINUX // compile for linux
from linux shell or windows command prompt and want default to be linux, if OS is not specified while executing 'make'. But the ifeq returns false in both cases, generating an error 'No rule to make target'. I read override directive & conditional syntax but it seems i havent got a clear idea of it. I have tried every alternate syntax of conditional syntax. But get error 'invalid syntax in conditional. Stop'
Make doesn't distinguish quotation marks. What you should do instead is:
ifeq ($(OS),LINUX)
# do stuff
endif
What's actually done here is that the arguments are expanded and then compared literally. $(OS) expands to the value of the variable and LINUX expands to LINUX. Your example would for example require make OS='"Linux"' in order to work
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