I want to include some conditional statement into a makefile:
SHELL=/bin/bash
all:
$(g++ -Wall main.cpp othersrc.cpp -o hello)
#if [[ $? -ne -1 ]]; then \
echo "Compile failed!"; \
exit 1; \
fi
But get an error:
/bin/bash: -c: line 0: conditional binary operator expected /bin/bash:
-c: line 0: syntax error near -1' /bin/bash: -c: line 0:if [[ -ne -1 ]]; then \' makefile:3: recipe for target 'all' failed make: *** [all] Error 1
How to fix it?
Note that each line of a makefile recipe runs in a different shell, so that $? of the previous line is unavailable, unless you use .ONESHELL option.
A fix without .ONESHELL:
all: hello
.PHONY: all
hello: main.cpp othersrc.cpp
g++ -o $# -Wall main.cpp othersrc.cpp && echo "Compile succeeded." || (echo "Compile failed!"; false)
With .ONESHELL:
all: hello
.PHONY: all
SHELL:=/bin/bash
.ONESHELL:
hello:
#echo "g++ -o $# -Wall main.cpp othersrc.cpp"
g++ -o $# -Wall main.cpp othersrc.cpp
if [[ $$? -eq 0 ]]; then
echo "Compile succeded!"
else
echo "Compile failed!"
exit 1
fi
When $ needs to be passed into a shell command it must be quoted as $$ in the makefile (make charges you a dollar for passing one dollar, basically). Hence $$?.
Related
I'm trying to build a Freetz firmware for my Fritzbox. I'm trying to do this on Ubuntu running in Parallels on my M1 MBP.
After eliminating all other issues (mainly dependencies), I end up with the following error:
cc: error: unrecognized command-line option ‘-m32’
The full dialog is:
parallels#ubuntu-linux-22-04-desktop:~/Downloads/freetz-ng$ make
Freetz-NG 20037-37d64c4f7 trunk 2022-07-08
cmd() { make -j3 "$#" || { [ "2" = "0" ] && echo && cat .build.log 2>/dev/null; kill $$ 2>/dev/null || kill $$$$ 2>/dev/null; printf "\n\\033[33m%s\\033[m\n" "ERROR: Build failed."; exit 1; } }; mkdir -p source; [ -n "" ] && step="/" || step=""; [ -n "" ] && step="$step/"; case "" in BIN) echo -n "package/" >source/.echo_item_tmp ;; LIB) echo -n "library/" >source/.echo_item_tmp ;; HTL) echo -n "tools/" >source/.echo_item_tmp ;; KTC) echo -n "toolchain/kernel$step" >source/.echo_item_tmp ;; TTC) echo -n "toolchain/target$step" >source/.echo_item_tmp ;; KRN) echo -n "kernel" >source/.echo_item_tmp ;; esac; if ! diff -q source/.echo_item_tmp source/.echo_item_new >/dev/null 2>&1 || [ ! -e source/.echo_item_1st ]; then if [ -e source/.echo_item_end -a -e source/.echo_item_new -a -e source/.echo_item_1st ]; then echo -e "\e[48;5;26mdone\e[49m."; rm -f source/.echo_item_end source/.echo_item_1st; fi; [ -s source/.echo_item_tmp ] && cat source/.echo_item_tmp > source/.echo_item_new 2>/dev/null; [ -s source/.echo_item_new ] || cat source/.echo_item_old > source/.echo_item_new 2>/dev/null; if [ -s "source/.echo_item_new" ]; then echo -ne "\e[48;5;90m---> "; cat source/.echo_item_new 2>/dev/null | tee source/.echo_item_old; echo -ne "\e[49m ... "; [ "2" != "0" ] && echo; touch source/.echo_item_end; touch source/.echo_item_1st; fi; fi; echo -ne "\e[48;5;56mbuilding\e[49m ... "; cmd -C /home/parallels/Downloads/freetz-ng/source/host-tools/pseudo-0cda3ba5f94aed8d50652a99ee9c502975aa2926/arch install-lib
---> tools/pseudo-host ...
building ... cc -fno-strict-aliasing -pipe -std=gnu99 -Wall -W -Wextra -Wno-deprecated-declarations -fPIC -D_LARGEFILE64_SOURCE -D_ATFILE_SOURCE -Wno-cast-function-type -Wno-nonnull-compare -fcommon -m32 -DPSEUDO_PREFIX='"/home/parallels/Downloads/freetz-ng/tools/build"' -DPSEUDO_SUFFIX='""' -DPSEUDO_BINDIR='"bin"' -DPSEUDO_LIBDIR='"lib"' -DPSEUDO_LOCALSTATEDIR='"var/pseudo"' -DPSEUDO_VERSION='"1.9.0"' -DUSE_MEMORY_DB -DPSEUDO_PASSWD_FALLBACK='""' -O2 -g -D_GNU_SOURCE -c -o pseudo_wrappers.o pseudo_wrappers.c
cc -c -pipe -std=gnu99 -Wall -W -Wextra -Wno-deprecated-declarations -fPIC -D_LARGEFILE64_SOURCE -D_ATFILE_SOURCE -Wno-cast-function-type -Wno-nonnull-compare -fcommon -m32 -DPSEUDO_PREFIX='"/home/parallels/Downloads/freetz-ng/tools/build"' -DPSEUDO_SUFFIX='""' -DPSEUDO_BINDIR='"bin"' -DPSEUDO_LIBDIR='"lib"' -DPSEUDO_LOCALSTATEDIR='"var/pseudo"' -DPSEUDO_VERSION='"1.9.0"' -DUSE_MEMORY_DB -DPSEUDO_PASSWD_FALLBACK='""' -O2 -g pseudo_client.c
cc -c -pipe -std=gnu99 -Wall -W -Wextra -Wno-deprecated-declarations -fPIC -D_LARGEFILE64_SOURCE -D_ATFILE_SOURCE -Wno-cast-function-type -Wno-nonnull-compare -fcommon -m32 -DPSEUDO_PREFIX='"/home/parallels/Downloads/freetz-ng/tools/build"' -DPSEUDO_SUFFIX='""' -DPSEUDO_BINDIR='"bin"' -DPSEUDO_LIBDIR='"lib"' -DPSEUDO_LOCALSTATEDIR='"var/pseudo"' -DPSEUDO_VERSION='"1.9.0"' -DUSE_MEMORY_DB -DPSEUDO_PASSWD_FALLBACK='""' -O2 -g pseudo_ipc.c
cc: error: unrecognized command-line option ‘-m32’
make[2]: *** [Makefile:158: pseudo_wrappers.o] Error 1
make[2]: *** Waiting for unfinished jobs....
cc: error: unrecognized command-line option ‘-m32’
make[2]: *** [Makefile:131: pseudo_client.o] Error 1
cc: error: unrecognized command-line option ‘-m32’
make[2]: *** [Makefile:131: pseudo_ipc.o] Error 1
make[1]: *** [tools/make/pseudo-host/pseudo-host.mk:57: /home/parallels/Downloads/freetz-ng/tools/build/lib/libpseudo.so] Terminated
make: *** [Makefile:46: envira] Terminated
Any ideas?
I tried
make MACHINE=arm
as I read in another discussion that I might be an architecture issue. But it doesn't seem to be.
I have read this, which suggests the following compilation check:
installCheck () {
if g++ check_opencv.cpp -o check_opencv; then
return 1
else
rm check_opencv
return 0
fi
}
if installCheck $0; then
echo "OpenCV already installed, skipping"
exit 0
fi
However, running this script gives:
check_opencv.cpp:2:33: fatal error: opencv2/core/core.hpp: No such file or directory
compilation terminated.
rm: check_opencv: No such file or directory
OpenCV already installed, skipping
which is wrong. Then I change to this:
installCheck () {
g++ check_opencv.cpp -o check_opencv
if [[ $? -ne 0 ]]; then
and it works fine:
check_opencv.cpp:2:33: fatal error: opencv2/core/core.hpp: No such file or directory
compilation terminated.
Cloning into 'opencv-2.4.9'...
Why is that? Because of some behavior of [[ or g++?
Someone in this says that "Sadly as it turns out make returns 0 weather or not it fails." Shouldn't g++ always return non-zero value when it fails? Maybe I miss something obvious, so please clarify for me. Thank you very much!
Update: it turns out that I understand bash wrongly. A return value of 0 evaluates to true in bash, which is contradictory to what I thought before. This helps.
if g++ check_opencv.cpp -o check_opencv; then
return 1
will return failure (1) if the compilation succeeds. Apparently, you wanted to return failure if the compilation failed, which would be:
if ! g++ check_opencv.cpp -o check_opencv; then
return 1
Or you could just put the true and false branches in the correct order:
installCheck () {
if g++ check_opencv.cpp -o check_opencv; then
rm check_opencv
return 0
else
return 1
fi
}
I don't see anywhere in the linked question where it suggests the code which you proposed.
I suppose that your intention was to avoid contaminating the filesystem if the compilation succeeds, since the compilation itself is the only test needed. You could also achieve this with:
installCheck () {
g++ check_opencv.cpp -o check_opencv
local rv=$?
rm -f check_opencv
return rv
}
if cmd; ... is "true" if cmd is successful i.e. exit status of cmd is 0 - it is logically equivalent to cmd; if [[ $? -eq 0 ]]; ...
im new to bash scripting and tring to make a script
goal: reciving 2 names (1 - logfilename 2- program name) the program should compile the program
and send both outputs to a log
if success then write "compile V" and return 0 else compile X and return number
i tried
#!/bin/bash
gcc {$2}.c -Wall -g -o $2> $1 2>&1
exit
and i have no idea how to check if it did or didnt success and the to echo V or X
edit:
thx for you guys, i got this
#!/bin/bash
gcc {$2}.c -Wall -g -o ${2}>${1} 2>&1
if (($?==0));then
echo Compile V
[else
echo compile X]
fi
exit
but all the if parts are still not working...
You can check exit status gcc like this:
#!/bin/bash
# execute gcc command
gcc "$2".c -Wall -g -o "$2"> "$1" 2>&1
# grab exit status of gcc
ret=$?
# write appropriate message as per return status value
((ret == 0)) && echo "compile V" || echo "compile X"
# return the exit status of gcc
exit $ret
You can check the success of a program in bash by command $? if echo $? = 0 then success else fail.
this code should work :
#!/bin/bash
gcc -v ${2}.c -Wall -g -o ${2}>${1} 2>&1
exit
Try this out:
#!/bin/bash
gcc "$2"".c" -Wall -g -o "$2" 2>&1 >"$1"
#check for error of previous command
if $? ; then echo compile V >>"$1"
else echo compile X >>"$1"; fi
exit
Makefile:
a b:
if [ -f s ];then
echo aaa
fi
command:make b
if [ -f s ];then
/bin/sh: -c: line 1: syntax error: unexpected end of file
make: *** [b] Error 2
Could anyone tell me why?
You should not be mixing shell scripting and make scripting. Try the below
a b:
#if test -f s; then \
echo "aaa";\
fi
I have a makefile rule in while I am executing a linux tool. I need to check the exit status of the tool command, and if that command fails the make has to be aborted.
I tried checking with $?, $$? \$? etc in the makefile. But they gives me syntax error when makefile runs.
What is the right way to do this ?
Here is the relevant rule in Makefile
mycommand \
if [ $$? -ne 0 ]; \
then \
echo "mycommand failed"; \
false; \
fi
In the makefile-:
mycommand || (echo "mycommand failed $$?"; exit 1)
Each line in the makefile action invokes a new shell - the error must be checked in the action line where the command failed.
If mycommand fails the logic branches to the echo statement then exits.
Here are a couple of other approaches:
shell & .SHELLSTATUS
some_recipe:
#echo $(shell echo 'doing stuff'; exit 123)
#echo 'command exited with $(.SHELLSTATUS)'
#exit $(.SHELLSTATUS)
Output:
$ make some_recipe
doing stuff
command exited with 123
make: *** [Makefile:4: some_recipe] Error 123
It does have the caveat that the shell command output isn't streamed, so you just end up with a dump to stdout when it finishes.
$?
some_recipe:
#echo 'doing stuff'; sh -c 'exit 123';\
EXIT_CODE=$$?;\
echo "command exited with $$EXIT_CODE";\
exit $$EXIT_CODE
Or, a bit easier to read:
.ONESHELL:
some_recipe:
#echo 'doing stuff'; sh -c 'exit 123'
#EXIT_CODE=$$?
#echo "command exited with $$EXIT_CODE"
#exit $$EXIT_CODE
Output:
$ make some_recipe
doing stuff
command exited with 123
make: *** [Makefile:2: some_recipe] Error 123
It's essentially one string of commands, executed in the same shell.
If all you want is for the make to be aborted iff the tool exits with a nonzero status, make will already do that by default.
Example Makefile:
a: b
#echo making $#
b:
#echo making $#
#false
#echo already failed
.
This is what happens with my make:
$ make
making b
make: *** [Makefile:6: b] Error 1
Make sure partially or wholly created targets are removed in case you fail.
For instance, this
a: b
#gena $+ > $#
b:
#genb > $#
is incorrect: if on the first try, genb fails, it will probably leave an incorrect b, which, on the second try, make will assume is correct. So you need to do something like
a: b
#gena $+ > $# || { rm $#; exit 1; }
b:
#genb > $#
To those who can't still fix it, the original snippet in the question missed a semicolon after mycommand. So, the working example is:
mycommand; \ # <<== here's the missing semicolon
if [ $$? -ne 0 ]; \
then \
echo "mycommand failed"; \
false; \
fi