How to compare two string variables in Makefile - makefile

I have the following code:
LOCAL_VERSION := $(shell some_binary -v | head -n 1)
REMOTE_VERSION := $(shell curl -s https://example.com/key)
all:
ifeq($(REMOTE_VERSION), $(LOCAL_VERSION))
#echo yes
endfi
But I am getting this:
user:tmp user$ make
ifeq(v0.11.1, v0.11.1)
/bin/sh: -c: line 0: syntax error near unexpected token `v0.11.1,'
/bin/sh: -c: line 0: `ifeq(v0.11.1, v0.11.1)'
make: *** [all] Error
I am on Mac OSX, but it's using GNU Make anyway.

ifeq should not be indented, e.g.
LOCAL_VERSION := $(shell some_binary -v | head -n 1)
REMOTE_VERSION := $(shell curl -s https://example.com/key)
all:
ifeq ($(REMOTE_VERSION), $(LOCAL_VERSION))
#echo yes
else
#echo NO
endif

The issue is not that ifeq is indented in the recipe, the problem is that it was indented using a tab. If you indent using space, the code runs as expected.
From Make manual:
5.1 Recipe Syntax
Each line in the recipe must start with a tab (or the first character in the value of the .RECIPEPREFIX variable; see Special Variables), except that the first recipe line may be attached to the target-and-prerequisites line with a semicolon in between. Any line in the makefile that begins with a tab and appears in a “rule context” (that is, after a rule has been started until another rule or variable definition) will be considered part of a recipe for that rule. Blank lines and lines of just comments may appear among the recipe lines; they are ignored.

Related

Running expressions (without compilation of files) in Makefile without targets?

I wanted to test some expressions of the ifeq kind that run a shell command that I read somewhere, so I wrote this tiny mymakefile (all lines being indented with a tab):
ifeq ($(shell echo test 2>/dev/null; echo $$?),0)
$(info I am inside)
endif
... and I tried to run it:
$ make -f mymakefile
make: *** No targets. Stop.
How could I test expressions like this inside their own makefile? Do I need to define a default target, or not? And how should the commands be formatted (indented with a tab, or space, or not indented at all?)
Well, I got somewhere - apparently, one must specify a target; but since I'm a make noob, I would love to see a more qualified answer.
I found this link https://www.gnu.org/software/make/manual/html_node/Conditional-Example.html that gave me a hint.. Anyways, this is mymakefile now:
.PHONY: default
default: mytarget;
ifeq ($(shell echo test 2>/dev/null; echo $$?),0)
$(info I am inside)
else
$(info I am outside)
endif
mytarget:
\t (TAB) echo A
So, the mytarget here is just a dummy, which simply does an echo A; running this prints:
$ make -f mymakefile
I am outside
echo A
A
If you don't want the echo A printed, suppress it with at sign: #echo A.
The echo A line has to be indented with a TAB - else error "mymakefile:11: *** missing separator. Stop.".
Strangely, if I indent the two $(info... lines with a TAB, then "I am outside" is printed last (?!), but when they are not indented (or indented with spaces), then it is printed first (as per the order in the file).

using `date` in Makefile variable

Using GNU Make 4.1, in my Makefile I can create a timestamp log file with this::
flush_log:
#echo "==> flush logs"
cat file > file_`date +%FT%T%Z`.log
But who to put:
file_`date +%FT%T%Z`.log
in a var inside the Makefile e.g to make a wc on it ?
I've try (with no success):
flush_log:
#echo "==> flush logs"
logfile:=file_$(shell date +%FT%T%Z).log
cat my_log > $(logfile)
echo `wc -l $(logfile)`
I get this error:
$ make flush_log
==> flush logs
logfile:=file_2016-12-24T20:09:52CET.log
/bin/sh: 1: logfile:=file_2016-12-24T20:09:52CET.log: not found
Makefile:7: recipe for target 'flush_log' failed
make: *** [flush_log] Error 127
$
I was following recommendation from https://stackoverflow.com/a/14939434/3313834 and Simply expanded variables https://www.gnu.org/software/make/manual/html_node/Flavors.html#Flavors
Every line in a makefile (that appears after a rule statement) that is indented with a TAB character is part of the rule's recipe. Lines in the rule's recipe are passed to the shell for handling, they're not parsed by make (except to expand variable/function references).
So your line logfile:=file... is being passed to the shell and being interpreted by the shell... and there is no valid := operator in the shell, so the shell thinks that entire line is a single word and tries to run a program with that name, which obviously doesn't exist.
You probably want to create a make variable, which must be done outside of the recipe, like this:
logfile := file_$(shell date +%FT%T%Z).log
flush_log:
#echo "==> flush logs"
cat my_log > $(logfile)
echo `wc -l $(logfile)`

Missing right parenthesis in shell command?

I'm trying to add a warning message to my makefile. Make is having trouble locating a right parenthesis.
The following is from my GNUmakefile:
341 ALIGNED_ACCESS = $(shell cat config.h | $(EGREP) -c "^#define NO_UNALIGNED_DATA_ACCESS")
342 ifeq ($(ALIGNED_ACCESS),0)
343 $(info WARNING: NO_UNALIGNED_DATA_ACCESS is not defined in config.h)
344 endif
Make complains:
$ make
GNUmakefile:341: *** unterminated call to function 'shell': missing ')'. Stop.
I literally shell out 25 other times in the makefile, so I'm not sure why it can't find the right parenthesis for the shell above.
I also moved the command to line 1 to test it, and I got the same message (modulo the line number change). And for fun, I added an unbalanced right parenthesis, but I got the same message.
Why can't make find the right parenthesis?
How can I coerce make into executing the command?
You have to escape the # in the makefile as this starts a comment ...
ALIGNED_ACCESS = $(shell cat config.h | $(EGREP) -c "^\#define NO_UNALIGNED_DATA_ACCESS")
Note the '\' before '#'

ifeq issue I try to understand

is my first question here and first time I manage GNU Make so I want to explain my problem.perhaps you could help me to find a light at the end of this tunnel.
That thing Im trying to do is to check a word into my path and do something after check path
I've got that code on make:
WORD=GNUMAKE; \
FOUND=1; \
echo "$$FOUND"; \
PWD=$(PWD); \
ifeq ($(findstring $$WORD,$$PWD),) \
$(warning list contains "$$WORD") \
endif
but when I run $make I get this error, for me so strange and can't find a solution
could you please help me?
/bin/sh: syntax error at line 1: `ifeq' unexpected
make: *** [all] Error 2
Thank you
Gnu make treats lines joined with \ as a single line. ifeq et. al. need to be on their own line, rather like #ifdef in C (if that's any help to you).
You seem rather confused over what make does.
Make executes a makefile in three distinct phases:
It reads in the Makefile, building a graph in memory, saving macros/expanding macros as necessary.
It looks at what you asked it to make, and decides how to walk the graph.
It walks the graph, expanding the shell recipes before passing the manufactured string to the shell.
You can get make to do your bidding as it reads the makefile
WORD = GNUMAKE
FOUND = 1
$(warning ${FOUND})
ifneq ($(findstring ${WORD},${CURDIR}),)
$(warning list contains "${WORD}")
endif
Or you can get make to do this just as it is making the command to pass to the shell (i.e., before the shell is executed):
.PHONY: target
target:
$(if $(findstring ${WORD},${CURDIR}),$(warning list contains "${WORD}"))echo Shell command here
Or indeed get the shell to do it.
You are messing make commands with shell commands. ifeq is apparently belongs to make but got into shell somehow.
This will find occurance of GNUMAKE word in current path, i.e. it will be one of parent directories. Put this into Makefile and call make.
INPUT := $(shell pwd | tr -s "/" " ")
WORD=GNUMAKE
ifneq ($(filter $(WORD),$(INPUT)),)
$(warning list contains $(WORD))
endif
WORD = GNUMAKE
FOUND = 0
$(warning $$FOUND)
ifneq ($(findstring $$WORD,$(PWD)),)
$(warning list contains $$WORD)
endif
that is exactly what I have been set
hope it helps

Make error for ifeq: syntax error near unexpected token

I'm writing a Makefile that does string matching at one place, the code is like:
if test ...; \
then \
shell scripts... \
fi
ifeq ($(DIST_TYPE),nightly)
shell scripts ...
endif
Here the first if is shell script, the second ifeq is GNU Make's conditional. However the following error generates:
ifeq (nightly,nightly)
/bin/sh: -c: line 0: syntax error near unexpected token `nightly,nightly'
/bin/sh: -c: line 0: `ifeq (nightly,nightly)'
What's happening here? It seems that Make is trying to call the shell.
I played around the code and found that the conditional statements should be written without indentation, and this solved my problem.
If there is no indentation, Make will treat it as a directive for itself; otherwise, it's regarded as a shell script.
Example code
Wrong:
target:
ifeq (foo, bar)
...
endif
Correct:
target:
ifeq (foo, bar)
...
endif
In addition, if the conditional statements is used in define functions, like:
define myFunc
ifeq (foo, bar)
...
endif
endef
In this case, Make will also treat it as a shell script.
This problem can be solved by using if-function instead:
define myFunc
$(if condition,then-part[,else-part])
endef

Resources