Unexpected token in ifeq makefile - makefile

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.

Related

Makefile variable value not available during ifeq

I have the following Makefile
SHELL=/bin/bash
.SHELLFLAGS=-O extglob -o errexit -o pipefail -o nounset -c
.PHONY: testing
define getFileContents
$(shell cat ./test.txt)
endef
TEST_STATIC=dummy
deploy:
$(eval TEST=$(getFileContents))
#echo "$(TEST)"
ifeq ($(TEST),dummy)
#echo "$(TEST) is FAILED"
else
#echo "$(TEST) is PASS"
endif
ifneq (,$(findstring dummy,$(TEST)))
#echo "$(TEST) is FAILED"
else
#echo "$(TEST) is PASS"
endif
ifeq ($(TEST_STATIC),dummy)
#echo "$(TEST) is FAILED"
else
#echo "$(TEST) is PASS"
endif
ifneq (,$(findstring dummy,$(TEST_STATIC)))
#echo "$(TEST) is FAILED"
else
#echo "$(TEST) is PASS"
endif
No matter what value I put in ./test.txt, I always go into PASS in both the ifeq & the findstring conditions but the variable's values show up properly in the echo statements. So the value is not available during the evaluation of ifeq
However, the if-else behaves properly for the TEST_STATIC variable.
Any help would be appreciated. Thanks.
ifeq is parsed while the makefile is read in. Even if it looks like it's part of a recipe, it isn't. You can tell that it isn't, because it isn't indented with a TAB character. Anything not indented by TAB, is part of the makefile not part of the recipe, and is parsed when the makefile is read in, not when the rule is run.
So by the time your rule is running and it gets to your eval, all the ifeq statements have long been expanded and dealt with.
In general, it's virtually never a good idea to use eval inside a recipe. It will almost never do what you're hoping for.
If you need to test some value inside a recipe then you have to write shell code to do it, not makefile code, and indent the shell code with a TAB so it's passed to the shell.

If comparison in make file

I have a makefile. I need to check the exit status of a command and the performing comparison, if exit status is 0 then perform some display action. But i am getting the same message if its success or failure for both the scenario.
Please find the below code and Help me what is the right way to do this:-
FILES = test1.sh test2.sh
manoj: $(FILES)
ls $(FILES)
$(eval exitstatus="$(shell echo $$?)")
#echo $(exitstatus)
ifeq (0,$(exitstatus))
$(error something going wrong..........)
endif
clean: pwd
Getting same output as :
testmake.mk:4: *** something going wrong........... Stop.
for both ifeq ifeq (0,$(exitstatus)) and ifneq ifeq (0,$(exitstatus))
I want to perform some action if the condition is success otherwise nothing want to do.
In the recipe shell commands are used, not make directives.
And when target's recipe is executed that means all its prerequisites do exist:
manoj: $(FILES)
#echo "$(FILES) do exist at this point."

Restart udev on Makefile

I've made a simple Makefile for an application and after install I need to restart udev rules.
INSTALLDIR=/pkt/bin
OS:=$(shell uname -v)
LBITS:=$(shell getconf LONG_BIT)
LIBDIR=/usr/lib
ifeq ($(LBITS),64)
LIBDIR64=/usr/lib64
else
LIBDIR64=/usr/lib
endif
all: usbupdater
configuracion.o: configuracion.cpp
g++ -c configuracion.cpp
main.o: main.cpp
g++ -c main.cpp
usbupdater: main.o configuracion.o
#echo "$(PATH)"
#echo "$(LIBDIR)"
g++ main.o configuracion.o $(LIBDIR)/libReadINI.a $(LIBDIR64)/chilkat/li
bchilkat-9.4.1.a -lpthread -lresolv -o usbupdater
clean:
rm -rf *.o *.cgh $(INSTALLDIR)/usbupdater
install:
mv usbupdater $(INSTALLDIR)/usbupdater
cp -rf 99-persistent-usb.rules /etc/udev/rules.d/99-persistent-usb.rules
postinstall:
#echo "$(OS)"
ifeq ($(findstring Debian,$(OS)),Debian) \
#echo "Estoy dentro del if"
$(shell '/etc/init.d/udev' restart) \
else \
#echo "Estoy dentro del else"
$(shell ls -l) \
endif
The problem is that when I type make postinstall is shows me this error:
#1 SMP Debian 3.2.46-1+deb7u1
ifeq (Debian,Debian) \
#echo "Estoy dentro del if"
/bin/sh: 1: Syntax error: word unexpected (expecting ")")
make: *** [postinstall] Error 2
I don't know where the problem is. I compare the result of uname -v with Debian to perform udev restart or udevcontrol reload_rules if it is an Opensuse OS.
Thanks in advance and sorry for my English.
ifeq is a make command. All lines in the makefile (in a recipe context) are passed to the shell. So make is passing ifeq to the shell and the shell is telling you that it has no idea what you're talking about.
You should write this using shell syntax, not make syntax.
Also it's rarely useful to use $(shell ...) functions inside a make recipe. The make recipe will be run by the shell, so when you use $(shell ...) you're just doubling the amount of shells that are running. Plus a command like $(shell ls -l) is not going to work, because $(shell ...) is like backtick and replaces the function with the stdout of the command. That'll be an error in this situation.
I would write it as:
postinstall:
#echo "$(OS)"
#case '$(OS)' in \
(*Debian*) \
echo "Estoy dentro del if"; \
/etc/init.d/udev restart ;; \
(*) \
echo "Estoy dentro del else"; \
ls -l ;; \
esac
You can't use make internal commands (like ifeq) within rule definition block. Use either shell's if or use ifeq outside of rule to generate some variables values, like
ifeq($(blah-blah), blah)
BUILD_CMD:=foo
endif
Also worth noting that else statement isn't exactly standard and may be missing in some versions of make.
Why do you want this, btw? I'd consider really bad practice if make install does something other then just installing (copying) files.

Makefile ifeq: when are they evaluated?

The following is a very simple makefile that does not seem to work properly.
TEST=ON
buildbegin:
ifeq ($(TEST),ON)
#echo TEST PASSED
else
#echo TEST FAILED
endif
No matter what I set the TEST variable to, my ifeq statement passes. I always see TEST PASSED. Anyone see what I am doing wrong here?
EDIT:
ok. my example was not exactly accurate. What I actually have is this:
SHELL = /bin/sh
DEFAULT_TARGS:= all all_debug
DEBUG_TARGS:= all_debug
ALL_TARGS:= $(DEFAULT_TARGS) $(DEBUG_TARGS)
.PHONY: $(ALL_TARGS)
.PHONY: buildbegin
$(ALL_TARGS): buildbegin
TEST=ON
$(DEBUG_TARGS): TEST=OFF
buildbegin:
#echo $(TEST)
ifeq ($(TEST),ON)
#echo PASSED
else
#echo FAILED
endif
Running either make all or make all_debug will result in "PASSED" being printed. If I echo $(TEST) before the condition, it looks as if my rules are changing the variable, but the ifeq only ever sees whatever the default value is.
make evaluates conditionals when it reads a makefile (as you know it uses 2 passes), see: Conditional Parts of Makefiles. You can simply check this by using warning (which is good thing to debug makefiles):
buildbegin:
#echo $(TEST)
$(warning now we reached ifeq TEST=$(TEST))
ifeq ($(TEST),ON)
#echo PASSED
else
#echo FAILED
endif
You should use shell commands instead and include them in rule:
buildbegin:
#if [ "$(TEST)" = "ON" ]; then echo "PASSED"; else echo "FAILED"; fi
Here's a cleaner (I think, anyway) way to do what you want:
all:
$(MAKE) TEST=ON buildbegin
all_debug:
$(MAKE) TEST=OFF buildbegin
buildbegin:
#echo $(TEST)
ifeq ($(TEST),ON)
#echo PASSED
else
#echo FAILED
endif
Parameterise the shell command using make variables. This avoids recursive make and even the shell (make will fork the command directly and not go via a shell if the command contains no shell metacharacters (<>"&; and the like)).
Something like:
result<ON> := PASSED
result<OFF> := FAILED
buildbegin:
#echo ${result-<${TEST}>}
The <...> is simply a convention to indicate some sort of indirection.
Although the question is old, I want to share a simpler way.
It is to use MAKECMDGOALSvariable that represents the list of targets.
In your case, a solution maybe:
buildbegin:
#echo $(MAKECMDGOALS)
ifeq ($(MAKECMDGOALS),all)
#echo PASSED
else ifeq ($(MAKECMDGOALS),debug_all)
#echo FAILED
endif
debug_all: buildbegin
all: buildbegin
Usage: make debug_all or make all

Getting Quiet Make to echo command lines on error

I have a Makefile building many C files with long long command lines and we've cleaned up the output by having rules such as:
.c${MT}.doj:
#echo "Compiling $<";\
$(COMPILER) $(COPTS) -c -o $# $<
Now this is great as the # suppresses the compilation line being emitted.
But when we get an error, all we get is the error message, no command line.
Can anyone think of a "neat" way to emit the command line?
All I can think of doing is echoing it to a file and have a higher level make catch the error and cat the file. Hacky I know.
Tested and it worked (GNU make in Linux):
.c${MT}.doj:
#echo "Compiling $<";\
$(COMPILER) $(COPTS) -c -o $# $< \
|| echo "Error in command: $(COMPILER) $(COPTS) -c -o $# $<" \
&& false
This question is pretty old, but for those of you Googling, I think what I’ll do in this situation is alias make to make -s (silent mode) in my shell, and only put the # prefix before lines where echo or other diagnostic commands are being invoked. When I want the full output from make, I will override my alias by calling it as \make.
Also note that in this situation that you’ll need to do the typical thing and put the #echo on its own line, with the actual rule commands on separate lines and without #’s.
A simple solution would be to use a simple script abc like the following:
#!/bin/bash
$#
code=$?
if (( code )); then
echo error running $#
fi
exit $code
Then you can write abc $(COMPILER) $(COPTS) -c -o $# $< in your Makefile. Do note that this does not work when you have pipes or redirects (as they will be applied to abc instead of the command you want to run).
You can also just put similar code directly in the Makefile if that's preferable.
I recently used a utility called logtext for the likes of tracking what output had occurred during the course of a bat file executing. Check it out, you may find this pretty useful if you want to know what error occurred where.

Resources