I've got this makefile target:
doc:
#cd doku; \
make clean > /dev/null 2>/dev/null; \
make > /dev/null 2>/dev/null
If the make inside this target is ok, it ends normaly, but if make inside target doc returns an error, it stays "stuck". After I pressing enter, it ends normally with:
make: *** [doc] Error 2
Is there any option to end make without pressing the Enter key?
You should always use $(MAKE) when invoking sub-makes, not make. This is really a shell question, not a make question, but if you don't want the process to read input you can redirect stdin from /dev/null:
make >/dev/null 2>&1 </dev/null
Related
Given a Makefile that's often times run with the -j flag for parallel builds. I want it to terminate with a result message. I would like this message to say if the build failed, and if it failed, what the error was. It doesn't have to say anything if the build succeeded (although it could) but it must warn the user when a target failed to build and why.
This behavior is already there during sequential builds, but not during parallel builds. Parallel builds interweaves the output and an error message is often overlooked because output from other targets might push the failed target's error off screen. A careless developer might see no errors on his/her screen and assume the build succeeded.
It's quite an intuitive feature and I've searched for an answer, but it doesn't seem like there's any straight forward solutions. Any ideas?
You basically run
make -j 8 2> >(tee /tmp/error.log)
test $? -ne 0 && echo "build errors:"
cat /tmp/error.log
and you get all of stderr after the build finishes.
-- EDIT --
Updating to use tee, to output on stdout and into file:
Make returns non-zero if one of its recipe's fails so you could do something like this from the command line (assuming bash shell):
make 2>&1 | tee build.log
[ ${PIPESTATUS}[0] -eq 0 ] || ( echo "MAKE FAILED!"; grep --color build.log "Error:" )
The ${PIPESTATUS}[0] gives you the exit code of the first command (make 2>&1) as opposed to the exit status of the entire command (which would the exit status of tee if the make failed). It is bash specific, so it won't work in zsh for example.
Alternatively you could add the same logic as the top level target of a recursive make.
ifndef IN_RECURSION
export IN_RECURSION:=1
$(info At top level -- defining default target)
_default:
#echo "doing recursive call of make"
#$(MAKE) $(MAKECMDGOALS) IN_RECURSION=1 2>&1 | tee build.log; \
[ ${PIPESTATUS}[0] -eq 0 ] || ( echo "MAKE FAILED!"; grep --color "Error:" build.log )
.PHONY: _default
endif
all:
....
Note that in this case the \ used to catinate the two recipe lines is crucial, as the second command must run in the same shell instance as the first.
My first jab at writing a shell script that would run my makefile, run the executable, and then remove the executable looked like:
make
if [ -e a.out ]; then
./a.out
rm a.out
fi
after realizing that the script didn't clean up a.out when I pressed ^C, I tried modifying it like so:
onintr foo
make
if [ -e a.out ]; then
./a.out
rm a.out
fi
foo:
rm a.out
but it did not solve my problem. If any of you know how I can accomplish what I'm trying to do that would be very helpful.
Add an infinite loop at the top of your script, print out a line in your onintr routine and test that you hit it when you break the loop with Ctrl-C. Remove the extra ouput and the infinite loop. Read your man pages on make, you probably don't have much control over what happens when it gets interrupted. That's why so many make files have a Clean target in them, so you can rerun make to clean-up all of its outputs.
I'm trying to use entr to recompile as soon as I change a C file with the following command:
$ echo ex8.c | entr make ex8 && ./ex8
When I run it I get the cc output but then nothing happends
$ echo ex8.c | entr make ex8 && ./ex8
cc -Wall -g ex8.c -o ex8
If I just write it manually it works great
$ make ex8 && ./ex8
How should I write it with entr for it to work?
The man page wasn't quite detailed enough, but I installed it and tried it. Note your command is actually three distinct shell commands: echo ex8.c, entr make ex8, and ./ex8. These are connected by a pipe (the first two) and the && operator (the final two). The two commands in the pipeline are both started together in parallel. The final command will not be invoked until the pipeline completes, then if the exit code is success it be run.
This means that the final command ./ex8 will not be started until after the entr make ex8 command finishes. But, entr does not exit after it runs make one time: its entire point is to continue to watch the source file and run make every time it changes. That's why the final command is never invoked: entr never exits.
There are multiple ways to fix this but the simplest way is to add a rule to your makefile that will build AND RUN the command, then call that with make; add this to your makefile:
.PHONY: run-ex8
run-ex8: ex8
./$<
Now use entr like this:
echo ex8.c | entr make run-ex8
I'm trying to pipe to the output of the compiler to the tee command in windows, but I've ran into an issue where if the compiler fails within make it'll continue compiling the next file when I want to it to stop. Is there a way to have the exit status of the first command be the exit status of the second command?
$(ODIR)/%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS) 2>&1 | tee build_log.txt
First off, I would leave any logging to the caller of make. Second off, this sort of piping is untidy in make. Third off, not a fan of losing the stderr stream inside make.
That said, this is a shell question. If you are using bash then see pipefail in the manual. Unfortunately I think it's quite tricky to turn on. (Yeah, I know you said windows, but I assume you aren't using the execrable cmd.)
SHELL := /bin/bash
passes:
(exit 1) |& cat
fails:
bash -c 'set -o pipefail; (exit 1) |& cat'
After Struggling a lot, I came to this solution ...
.ONESHELL:
$(ODIR)/%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS) 2> temp_err_file
set EXIT_STATUS=%ERRORLEVEL%
type temp_err_file >> build_log.txt
type temp_err_file 1>&2
del /q temp_err_file
exit /b %EXIT_STATUS%
Here .ONESHELL allows make to run entire recipe in the single shell command instead of running each line in separate cmd and collect return status of each separately. Overall exit status depends on the main compilation command so in end it is necessary to exit with the status of compilation.
I know its not a clean solution involving the temp_err_file and if something goes wrong after compilation command, make would not be able to catch it but this I think is the best I can find to work with windows without losing stderr stream and logging.
A method that is shell independent and may be feasible in some cases is the following:
assume you have a recipe:
target:
try_making_target |& tee target.log
What I did was convert it to:
target:
(try_making_target || rm -f $#) |& tee target.log
test -e $#
The the piped command fails, the "fallback" (command after ||) will delete the goal file, and the final test will fail. Note that this example assumes the OS is Linux ('rm' for deletions) and that your shell supports the || operator.
This assumes that you are not interested in partial results when try_making_target fails. If you want to keep partial result in 'target', you can use other "marker" files to designate the success or failure of try_making_target. Something like this may work:
target:
touch $#.succeeded # Assume success
(try_making_target || rm -f $#.succeeded) |& tee target.log # Delete to mark failure
test -e $#.succeeded # Fail if marker
rm $#.succeeded # Remove unneeded marker
This last code would also work for phony goals, although you really should minimize the use of these (I try only using them as mnemonics for real files, which may have longish names).
Criteria: Makefile is a GNU Make Makefile - I'm not interested in makepp, qmake, cmake, etc. They're all nice (especially cmake), but this is for work and at work we use GNU Make. The optimal solution is a pure Makefile solution rather than a shell script that parses make for you.
I also don't want to do a 'continue on failure' solution - if it's broken, it's broken and needs to be fixed.
The situation is this, I've got a makefile that builds several directories in parallel - if one of them fails, of course the whole build fails, but not until all the running makes run to completion (or failure). This means that the reason why make actually failed is buried somewhere arbitrarily far from the end of make's output.
Here's an example of what I've got:
all: $(SUBDIRS)
SUBDIRS = \
apple \
orange \
banana \
pineapple \
lemon \
watermelon \
grapefruit
$(SUBDIRS):
cd $# && $(MAKE) $(MFLAGS) 2>&1 | sed -e "s/^/$(notdir $(#)): /g"
If I run 'make -j 5' and 'orange' happens to fail - I'd like to see a table like this at the end
of the make process
apple - passed
orange - FAILED
banana - passed
pineapple - passed
lemon - passed
I've considered having an && echo "passed" >.result || echo "FAILED" >.result, but make still needs some sort of TRAP or __onexit() cleanup command to print at them on exit.
Any Makefile ninjas out there have a pure-makefile solution for this?
un-edit - my solution wasn't actually working the way I had hoped.. STYMIED!
When you want make to abort at the first failure, end immediately and kill all in-flight jobs instead of waiting for them to finish, you need to patch GNU Make like this
http://lists.gnu.org/archive/html/bug-make/2009-01/msg00035.html
Then you need to set a trap for every shell that make invokes (as well as set -o pipefail if you use a pipe), as described in this post http://lists.gnu.org/archive/html/help-make/2009-02/msg00011.html
In a nutshell:
target1:
trap 'kill $$(jobs -p)'; command && something || something-else
target2:
trap 'kill $$(jobs -p)'; set -o pipefail; command | sed '...'
The only way I see is self-execution with a sub-make:
all : subdirs
subdirs :
$(MAKE) -f $(lastword $(MAKEFILE_LIST)) subdirs-recursive || cat log
subdirs-recursive: $(SUBDIRS)