Wrapping GNU makefile with another makefile - linux

This is following question.
I have Makefile.real (Makefile from prev question):
all: a b
a:
echo a
exit 1
b:
echo b start
sleep 1
echo b end
Now I want to create Makefile that is simple wrap of Makefile.real:
It calls make with Makefile.real with the same args as it was called
It should print error message id Makefile.real fails
This is my goal - print error message in the end of parallel make
(see question)
Therefore following commands should terminate with error message:
make -j1 a b (1)
make -j2 a b (2)
I suspect Makefile should be something close to:
%:
$(MAKE) -f Makefile.real $(MAKECMDGOALS); \
res=$$?; if [ $$res != 0 ]; then echo "Failed!!!"; fi; exit $$res
The problem is that target '%' will be called twice for a and b for (2).
Any ideas?

This is the solution I ended with
ifneq ($(REAL_MAKE),1)
# run_make will be called once (it's .PHONY target),
# even if make is called with several targets
%: run_make
#:
.PHONY: run_make
run_make:
$(MAKE) $(MAKECMDGOALS) REAL_MAKE=1; \
if [ $$? -ne 0 ]; then \
echo "*** Error ***" >&2; \
exit 1; \
fi
else # REAL_MAKE defined (actual makefile)
### HERE comes original make we want to wrap ###
endif # # REAL_MAKE defined (actual makefile)

Related

How to pass a Makefile target to another

so I have a large Makefile that runs all of my tests for my particular project. Each target is a different group of tests. The script will run the target, store its output into a temporary file.
Currently the target looks like this:
count:
# USE: make count test=<name of test to run>
# Save output to target
$(MAKE) $(test) > last_output.txt
cat last_output.txt
# Print Passed
#cat last_output.txt | { grep -E -w "SUCCESS|RELAX-PASS" || true; }
# Print Failed
#cat last_output.txt | { grep -E -w "FAILED" || true; }
# Failed Count
#echo "\e[1;31mFAILED:\e[1;37m"
#cat last_output.txt | { grep -c "FAILED" || true; }
# Passed Count
#echo "\e[1;32mPASSED:\e[1;37m"
#cat last_output.txt | grep -E -c "SUCCESS|RELAX-PASS"
# Count all
#echo "TOTAL: "
#cat last_output.txt | { grep -E -c "FAILED|SUCCESS|RELAX-PASS" || true; }
And the instruction to execute it looks like:
make count test=add
What I was wondering was if I could not specify test= when I'm running the command so that it would look like this:
make count add
and then the add target will execute which looks like:
add:
clear && run.pl add_0.asm
clear && run.pl add_1.asm
clear && run.pl add_2.asm
clear && run.pl add_3.asm
ect.
Every command line argument to make is either an option, a variable assignment, or a target. There's no possible way to treat an argument as anything else. So when you run make check add, the add will be a target that make will attempt to build and there's no way to have it be considered any other way.
As #Beta suggests if you are willing to embed to the test name into the target, like make count_add, then you can do this:
SHOW = \
cat last_output.txt; \
grep -E -w "SUCCESS|RELAX-PASS" < last_output.txt; \
grep -E -w "FAILED" < last_output.txt; \
echo "\e[1;31mFAILED:\e[1;37m"; \
grep -c "FAILED" < last_output.txt; \
echo "\e[1;32mPASSED:\e[1;37m"; \
grep -E -c "SUCCESS|RELAX-PASS" < last_output.txt; \
echo "TOTAL: "; \
grep -E -c "FAILED|SUCCESS|RELAX-PASS" < last_output.txt;
true
count:
$(MAKE) $(test) > last_output.txt
#$(SHOW)
count_%:
$(MAKE) $* > last_output.txt
#$(SHOW)
If you don't want to do that, the only possible solution is to use ifeq combined with $(MAKECMDGOALS) to break your makefile up into two sections: one that has a .DEFAULT target that does nothing (to ignore the extra targets like add etc.) and a second that runs those targets.

Makefile not executing the commands as expected

I'm using the following Makefile, which should check whether the files are in some directory *.rpm, if the files hasn't been found i'm going to execute some command (run a script or make the rpm)
Here's a snippet from my Makefile
include /home/user/workspace/test/exec_recipe.mk
export BUILD_LOGS_DIR = $(CURDIR)/build_logs
.PHONY: my_rpm
libpdutil_rpm:
#echo "Making target 'libpdutil_rpm'. Time: $$(date +%T)"
cd /home/user/workspace/test/build/test && $(call exec_recipe,$(ls /home/user/workspace/test/build/test/rpmbuild/RPMS/x86_64d/*.rpm) || $(./test.sh),test.log,)
#echo "Finished making target 'my_rpm'. Time: $$(date +%T)"
And here's the exec_recipe.mk
SHELL:=/bin/bash
exec_recipe = \
echo "The logs dir is: $$BUILD_LOGS_DIR"; \
log_name="$(2)"; \
echo "The log name is $$log_name"; \
cmd="$(1)"; \
eval "$$cmd" 2>&1 | tee -a "$$BUILD_LOGS_DIR/$$log_name"; rc="$${PIPESTATUS[0]}"; \
if [ $$rc = 0 ]; then \
res="PASS"; \
else \
res="FAIL"; \
fi; \
flock $(SUMMARY) echo "Making target '$#': $$res" >> $(SUMMARY); \
exit $$rc
So the problem is when it's reaching the execution of the exec_recipe.mk it giving me some errors:
/bin/bash: eval: line 0: syntax error near unexpected token||'
/bin/bash: eval: line 0: || '
I'm sure that i'm doing something wrong..
I need the helper make file, because i'm using it for other purposes as well
You have to escape all the dollar signs that you don't want make to interpret. You've forgotten to escape the dollar signs in the arguments to $(call exec_recipe,...):
cd /home/user/workspace/test/build/test && $(call exec_recipe,$$(ls /home/user/workspace/test/build/test/rpmbuild/RPMS/x86_64d/*.rpm) || $$(./test.sh),test.log,)
I'm not sure what the final comma is for but whatever.

Simple bash script

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

Linux make file: How to exit for loop early with error message

I am setting up a makefile to run a test that involves diffing a list of generated files against their counterparts in a master directory. I can get the loop to work and to exit if the diff fails but I haven't figured out how to include a failure message and still exit the for loop (and the make process) immediately.
Here is the core of what I have:
OUTFILE = $(patsubst $(MASTER_DIR1)/%,$(OUTDIR1)/%,$$file)
default: test
$(OUTDIR1):
$(MKDIR) $(OUTDIR1)
test: $(OUTDIR)
#for file in $(MASTER_LIST1); do \
echo $$file; \
diff $(IGNORE_OPT) \
$$file \
$(OUTFILE) \
&& exit 1; \
done
This exits on fail but doesn't inform the user as to why. I tried changing the && exit 1; line to:
&& (echo "Diff failed"; exit 1; ); \
That displayed the error message but no longer exited.
How do I add an error message and still exit right away?
TIA!
Based on the help provided by Etan Reisner in his comment to the original question, this is the solution that worked:
test: $(OUTDIR)
#for file in $(MASTER_LIST1); do \
echo $$file; \
diff $(IGNORE_OPT) \
$$file \
$(OUTFILE) \
&& { echo "Diff failed"; exit 1; }; \
done

How to get exit status of a shell command used in GNU Makefile?

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

Resources