Makefile: print BUILD SUCCESSFUL or BUILD FAILED - makefile

I'm using Makefile for building my C++ project. It is a little bit annoying, that sometimes it is hard to find out if the build was successful or it was failed. I'd like to see a clear statement in the end of the build like in gradle.
If build passed:
BUILD SUCCESSFUL
If build failed:
BUILD FAILED
For positive case I've found this solution:
all: dependencies #every job is done in dependencies
echo "BUILD SUCCESSFUL"
What is the best way to do this?

A common principle of Unix (or any command-line, really) software is "if all is well, be quiet". Of course Make itself (and makefiles written in the usual ways) already violate that rule left and right, but it's still a nice guideline...
Unix command-line programs communicate success/fail using the exit status, so in terminal you can just do echo $? right after invoking Make. 0 is success, anything else is not.
Regardless of the aesthetic points above, getting Make to do something reliably in case of failure is hard, because it is not designed to do that. It's vastly easier to wrap the Make invocation with a shell script, along the lines of:
#!/bin/sh
if make "$#"; then
echo BUILD SUCCESSFUL
else
echo BUILD FAILED
fi

Related

How to produce a make build that is verbose only on failure

There are many ways to produce a verbose make command with cmake.
This has been described in many places. (basically cmake; make VERBOSE=1 or set the CMAKE_VERBOSE_MAKEFILE variable).
Verbose here refers to showing the invoked commands and other information on the steps taken by make.
This seems to be an all or nothing setting.
Either you see all the commands or none of the commands,
regardless of the whether the command succeed or not.
A related tool, ctest (for testing) has a very useful options --output-on-failure for which verbosity depends on the particular test being successful;
only showing the screen out for failing tests.
The question is whether cmake has a similar feature regarding giving details only on failure.
That is, for the most part I don't want to see make compilation commands, but when it fails I would like to see what is the exact command that failed with all the options on display.
That is, the question is if there is some setting or command-line option for make or cmake that, in the build step, will print the full issued command (and output) only for commands that failed.
The reason of course is that it gives the opportunity to see the actual compilation flags for the failing step and allows to reproduce the exact command interactively sometimes.
(I use C++, but the question is general I think)
This is not exactly an answer because you only mentioned make, but what you ask is the default behavior of Ninja. It only outputs the command that failed.
Sometimes, when I am too desperate and I cannot understand the error messages I do this:
make -j 10 -k || make VERBOSE=1
So it will compile fast, and if it fails it runs again serially in verbose mode. It is very likely that the first compilation is the one failing.

How to save and return exit code in makefile target

I have a make target that looks something like this:
.PHONY: run-my-test
run-my-test: all
run_test_suite.sh --all --log-to-file
post_process_logs.sh
If a test case fails, the exit code of run_test_suite.sh will cause Make to not continue with running post_process_logs.sh. This is a problem, because i want to get the processed logs even for failed tests. How should i update my target to do this?
I've thought of saving the exit code somehow and perhaps exit with it in the end of the target definition. Or do I split the calls up into separate targets?
I can add that I'm pretty much forced to do this from Make because of how our build system works. And I would prefer not having to add more targets as the make files tend to be cluttered with these as it is.
If you want the build to fail after running post_process_logs.sh, put both commands in the same entry.
.PHONY: run-my-test
run-my-test: all
run_test_suite.sh --all --log-to-file; \
e=$$?; \
post_process_logs.sh; \
exit $$e
The exit status of run_test_suite.sh is saved in the shell variable e, which is used as the argument to exit after post_process_logs.sh to set the exit status of the overall command.

How/When does Execute Shell mark a build as failure in Jenkins?

The horror stories I found while searching for an answer for this one...
OK, I have a .sh script which pretty much does everything Jenkins supposed to do:
checks out sources from SVN
build the project
deploys the project
cleans after itself
So in Jenkins I only have to 'build' the project by running the script in an Execute Shell command.
The script is ran (the sources are downloaded, the project is build/deploy) but then it marks the build as a failure:
Build step 'Execute shell' marked build as failure
Even if the script was successfully ran! I tried closing the script with:
exit 0 (still marks it as failure)
exit 1 (marks it as failure, as expected)
no exit command at all (marks it as failure)
When, how and why does Execute Shell mark my build as a failure?
First things first, hover the mouse over the grey area below. Not part of the answer, but absolutely has to be said:
If you have a shell script that does "checkout, build, deploy" all by itself, then why are you using Jenkins? You are foregoing all the features of Jenkins that make it what it is. You might as well have a cron or an SVN post-commit hook call the script directly. Jenkins performing the SVN checkout itself is crucial. It allows the builds to be triggered only when there are changes (or on timer, or manual, if you prefer). It keeps track of changes between builds. It shows those changes, so you can see which build was for which set of changes. It emails committers when their changes caused successful or failed build (again, as configured as you prefer). It will email committers when their fixes fixed the failing build. And more and more. Jenkins archiving the artifacts also makes them available, per build, straight off Jenkins. While not as crucial as the SVN checkout, this is once again an integral part of what makes it Jenkins. Same with deploying. Unless you have a single environment, deployment usually happens to multiple environments. Jenkins can keep track of which environment a specific build (with specific set of SVN changes) is deployed it, through the use of Promotions. You are foregoing all of this. It sounds like you are told "you have to use Jenkins" but you don't really want to, and you are doing it just to get your bosses off your back, just to put a checkmark "yes, I've used Jenkins"
The short answer is: the exit code of last command of the Jenkin's Execute Shell build step is what determines the success/failure of the Build Step. 0 - success, anything else - failure.
Note, this is determining the success/failure of the build step, not the whole job run. The success/failure of the whole job run can further be affected by multiple build steps, and post-build actions and plugins.
You've mentioned Build step 'Execute shell' marked build as failure, so we will focus just on a single build step. If your Execute shell build step only has a single line that calls your shell script, then the exit code of your shell script will determine the success/failure of the build step. If you have more lines, after your shell script execution, then carefully review them, as they are the ones that could be causing failure.
Finally, have a read here Jenkins Build Script exits after Google Test execution. It is not directly related to your question, but note that part about Jenkins launching the Execute Shell build step, as a shell script with /bin/sh -xe
The -e means that the shell script will exit with failure, even if just 1 command fails, even if you do error checking for that command (because the script exits before it gets to your error checking). This is contrary to normal execution of shell scripts, which usually print the error message for the failed command (or redirect it to null and handle it by other means), and continue.
To circumvent this, add set +e to the top of your shell script.
Since you say your script does all it is supposed to do, chances are the failing command is somewhere at the end of the script. Maybe a final echo? Or copy of artifacts somewhere? Without seeing the full console output, we are just guessing.
Please post the job run's console output, and preferably the shell script itself too, and then we could tell you exactly which line is failing.
Simple and short answer to your question is
Please add following line into your "Execute shell" Build step.
#!/bin/sh
Now let me explain you the reason why we require this line for "Execute Shell" build job.
By default Jenkins take /bin/sh -xe and this means -x will print each and every command.And the other option -e, which causes shell to stop running a script immediately when any command exits with non-zero (when any command fails) exit code.
So by adding the #!/bin/sh will allow you to execute with no option.
In my opinion, turning off the -e option to your shell is a really bad idea. Eventually one of the commands in your script will fail due to transient conditions like out of disk space or network errors. Without -e Jenkins won't notice and will continue along happily. If you've got Jenkins set up to do deployment, that may result in bad code getting pushed and bringing down your site.
If you have a line in your script where failure is expected, like a grep or a find, then just add || true to the end of that line. That ensures that line will always return success.
If you need to use that exit code, you can either hoist the command into your if statement:
grep foo bar; if [ $? == 0 ]; then ... --> if grep foo bar; then ...
Or you can capture the return code in your || clause:
grep foo bar || ret=$?
I 've tried all mentioned options (even changing sh to bash without -xe params), the only one option worked for me is:
<command-which-returns-not-zero> || exit 0
Plain and simple:
If Jenkins sees the build step (which is a script too) exits with non-zero code, the build is marked with a red ball (= failed).
Why exactly that happens depends on your build script.
I wrote something similar from another point-of-view but maybe it will help to read it anyway:
Why does Jenkins think my build succeeded?
So by adding the #!/bin/sh will allow you to execute with no option.
It also helped me in fixing an issue where I was executing bash script from Jenkins master on my Linux slave. By just adding #!/bin/bash above my actual script in "Execute Shell" block it fixed my issue as otherwise it was executing windows git provided version of bash shell that was giving an error.
Try and always find where exactly its failing by adding the following line into your "Execute shell" Build step.
#!/bin/sh -xe
By adding the -x you will print each and every command that ran (including the lines from embedded scripts) and that will help in spotting the root cause.
Removing the -e option i.e. running #!/bin/sh will allow you to execute with no option, which is really a bad idea as Bryan explained well in one of the answers.
The problem is with no option Jenkins will ignore errors and continue execution of subsequent steps (if there are any) which will leave your process in an consistent state. If this is for a production build or deployment, that may have a bad impact.
Once you find the problem area, run the same failing command from the directory as jenkins-user manually, to get to the exact error/rootcause.
In Jenkins ver. 1.635, it is impossible to show a native environment variable like this:
$BUILD_NUMBER or ${BUILD_NUMBER}
In this case, you have to set it in an other variable.
set BUILDNO = $BUILD_NUMBER
$BUILDNO

invoke make from build

I'd like to simplify the workflow so that rather than issuing these commands
$ make program_unittest
... output of $MAKE ...
$ ./program_unittest args
I could have my program automatically attempt to compile itself (if the source has been updated) when it is run, so that I do not have to go back and run make myself.
Here's what I'm thinking: My unit test build should first check if there is a makefile in the directory it's in, and if so, fork and exec make with the target corresponding to itself. If make determines "nothing to be done", it will continue on its way (running the unit-tests). However, if make actually performs a compilation, one of two things may happen. gcc (invoked by make) might be able to overwrite the build (an older version of which is already running) during compilation, in which case I can then perhaps exec it. If my system does not permit gcc to overwrite the program which is in use, then I have to quit the program before running make.
So this has become quite involved already. Are there perhaps more elegant solutions? Maybe I could use a bash script? How do I ascertain if make issued compilation commands or not?
Why not have make run the unit tests?

Is there a smarter alternative to "watch make"?

I ran into this useful tip that if you're working on files a lot and you want them to build automatically you run:
watch make
And it re-runs make every couple seconds and things get built.
However ... it seems to swallow all the output all the time. I think it could be smarter - perhaps show a stream of output but suppress Nothing to be done for 'all' so that if nothing is built the output doesn't scroll.
A few shell script approaches come to mind using a loop and grep ... but perhaps something more elegant is out there? Has anyone seen something?
Using classic gnu make and inotifywait, without interval-based polling:
watch:
while true; do \
$(MAKE) $(WATCHMAKE); \
inotifywait -qre close_write .; \
done
This way make is triggered on every file write in the current directory tree. You can specify the target by running
make watch WATCHMAKE=foo
This one-liner should do it:
while true; do make --silent; sleep 1; done
It'll run make once every second, and it will only print output when it actually does something.
Here is a one-liner:
while true; do make -q || make; sleep 0.5; done
Using make -q || make instead of just make will only run the build if there is something to be done and will not output any messages otherwise.
You can add this as a rule to your project's Makefile:
watch:
while true; do $(MAKE) -q || $(MAKE); sleep 0.5; done
And then use make watch to invoke it.
This technique will prevent Make from filling a terminal with "make: Nothing to be done for TARGET" messages.
It also does not retain a bunch of open file descriptors like some file-watcher solutions, which can lead to ulimit errors.
How about
# In the makefile:
.PHONY: continuously
continuously:
while true; do make 1>/dev/null; sleep 3; done
?
This way you can run
make continuously
and only get output if something is wrong.
Twitter Bootstrap uses the watchr ruby gem for this.
https://github.com/twbs/bootstrap/blob/v2.3.2/Makefile
https://github.com/mynyml/watchr
Edit:
After two years the watchr project seems not to be maintained anymore. Please look for another solution among the answers. Personally, if the goal is only to have a better output, i would recommend the answer from wch here
I do it this way in my Makefile:
watch:
(while true; do make build.log; sleep 1; done) | grep -v 'make\[1\]'
build.log: ./src/*
thecompiler | tee build.log
So, it will only build when my source code is newer than my build.log, and the "grep -v" stuff removes some unnecessary make output.
This shell script uses make itself to detect changes with the -q flag, and then does a full rebuild if and only if there are changes.
#!/bin/sh
while true;
do
if ! make -q "$#";
then
echo "#-> Starting build: `date`"
make "$#";
echo "#-> Build complete."
fi
sleep 0.5;
done
It does not have any dependencies apart from make.
You can pass normal make arguments (such as -C mydir) to it as they are passed on to the make command.
As requested in the question it is silent if there is nothing to build but does not swallow output when there is.
You can keep this script handy as e.g. ~/bin/watch-make to use across multiple projects.
There are several automatic build systems that do this and more - basically when you check a change into version control they will make/build - look for Continuous Integration
Simple ones are TeamCity and Hudson
#Dobes Vandermeer -- I have a script named "mkall" that runs make in every subdirectory. I could assign that script as a cron job to run every five minutes, or one minute, or thirty seconds. Then, to see the output, I'd redirect gcc results (in each individual makefile) to a log in each subdirectory.
Could something like that work for you?
It could be pretty elaborate so as to avoid makes that do nothing. For example, the script could save the modify time of each source file and do the make when that guy changes.
You could try using something like inotify-tools. It will let you watch a directory and run a command when a file is changed or saved or any of the other events that inotify can watch for. A simple script that does a watch for save and kicks off a make when a file is saved would probably be useful.
You could change your make file to output a growl (OS X) or notify-send (Linux) notification. For me in Ubuntu, that would show a notification bubble in the upper-right corner of my screen.
Then you'd only notice the build when it fails.
You'd probably want to set watch to only cycle as fast as those notifications can display (so they don't pile up).
Bit of archaeology, but I still find this question useful. Here is a modified version of #otto's answer, using fswatch (for the mac):
TARGET ?= foo
all:
#fswatch -1 . | read i && make $(TARGET)
#make -ski TARGET=$(TARGET)
%: %.go
#go build $<
#./$#

Resources