How to have make fail on some warnings but not others - makefile

I have a make file that includes:
%.dat: %.txt
... PREPROCESSING OF TEXT FILE
tidy -o $*.html $<
... FURTHER PROCESSING
tidy produces lots of warnings that I can suppress with the flag --show-warnings false, but despite supressing the warnings, the exit status from tidy still 1 instead of 0, and so make fails part way through the recipe. How can I have make continue in the face of tidy giving exit status 1 while still allowing make to fail if any other recipe gives warnings?
I have looked at these two question (Have make fail if unit tests fail and gcc, make: how to disable fail on warning?) but neither seems to deal with this problem.
AFTER EDIT: In Make: how to continue after a command fails?, the question relates to how one gets make to continue after any non-zero exit status in executing a particular command, whereas in my case, I want an exit status of 2 from tidy indicating errors, to cause make to fail, but I want an exit status of 1 from tidy, indicating warningsto allowmake to continue`.

The simpliest solution:
tidy -o $*.html $< || true
So if tidy's exit code isn't zero the true produces zero exit code.
But check the tidy's exit codes:
Exit Status
0
All input files were processed successfully.
1
There were warnings.
2
There were errors.
Maybe you want skip only the error code 1. In this case:
tidy -o $*.html $< || [ $$? -eq 1 ] && true

Related

Makefile: exit on conditional

I want to check that an environment variable is set before executing some code in a Makefile. If it's not set I want to throw an error with a simple error message:
run:
[ -z "$(MY_APP)" ] && echo "MY_APP must be set" && exit 1
echo "MY_APP is set. Yay!"
echo "Let's continue on with the command..."
When MY_APP is not set I get the following error, which is desired:
[ -z "" ] && echo "MY_APP must be set" && exit 1
MY_APP must be set
make: *** [run] Error 1
However, when MY_APP is set I get the following error:
[ -z "EXAMPLE_NAME" ] && echo "MY_APP must be set" && exit 1
make: *** [run] Error 1
Any idea what I'm doing wrong? And is there a better way to do this?
Recall that the && condition require that all conditions must be TRUE to pass. Since the first condition fail, the whole command will return a status of 1 (-> false), effectively stopping the make
You can use the following, so that the test will fail only when MY_APP is missing.
Note that I'm using false instead of exit 1. Also better to use "${MY_APP}", which make it easier to copy/paste from Make to shell prompt/script.
run:
{ [ -z "$(MY_APP)" ] && echo "MY_APP must be set" && false } || true
...
# Or just if-Then-Else
if [ -z "${MY_APP}" ] ; then echo "MY_APP must be set" ; false ; fi
...
You can test environment variables with Makefile conditional syntax, like this:
sometarget:
ifndef MY_APP
#echo "MY_APP environment variable missing"
exit 1
endif
somecommand to_run_if_my_app_is_set
Note that ifndef/ifdef operate on the name of the variable, not the variable itself.
It seems that you are trying to use a Makefile to run commands which are not building targets (the target name run is a giveaway). You already got bitten by one of Makefile and shells caveats. Makefile caveat: exit status is inspected after each line and if not zero abort immediately. Shell caveat: the test command ([) returns a non zero exit status so the entire line returns non zero.
The rule of thumb is: a recipe of a rule should create a filename named like the target of the rule.
Here is a rule (to clarify the terms):
target:
recipe command lines
should create file named target
There are some exceptions to this rule of thumb. Most notably make clean and make install. Both typically do not create files named clean or install. One can argue that make run maybe also be an exception to this rule of thumb.
If your run is as simple as a typical clean then I might agree about making an exception. But usually commands are run with command line arguments. Before long you will want make run accept arguments. And making make accept custom command line arguments is not fun at all.
You tried to manipulate the behaviour using environment variables which is somewhat less problematic than command line arguments. But still problematic enough to make you trip over a caveat.
My suggestion for a fix:
Put complex recipes in a shell script. There you have all the power and flexibility of a shell script without the awkwardness of makefiles. For example as explained here: Basic if else statement in Makefile
In case of a typical run target write a wrapper shell script around the makefile which lets the makefile rebuild the target and then run the target. For exampe as explained here: Passing arguments to "make run"
You can conditionally exit the Makefile using error control function, at least in the GNU version.
This snippet is a helpful condition to put into the head of the Makefile. It exits with a message of help, if make was not called from within the directory of the Makefile.
MAKEFILE_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
ifneq (${MAKEFILE_DIR}, $(shell pwd))
INVALID_LOCATION:=`make` must be called from within ${MAKEFILE_DIR} (or with option -C ${MAKEFILE_DIR})
$(error ERROR: $(INVALID_LOCATION))
endif
See: https://www.gnu.org/software/make/manual/html_node/Make-Control-Functions.html
Useful in case your paths are relative to the Makefile and you don't want them to prefix with a base.

gnu make - force exit without deleting the target

I'm incrementally verifying my build output and I want to be able to exit after a given recipe is executed.
If the original recipe is
$(HEADER_BUILD)/mpversion.h: FORCE | $(HEADER_BUILD)
$(Q)$(PYTHON) $(PY_SRC)/makeversionhdr.py $#
I want to be able to add one line at the end like so
$(HEADER_BUILD)/mpversion.h: FORCE | $(HEADER_BUILD)
$(Q)$(PYTHON) $(PY_SRC)/makeversionhdr.py $#
some_command
and some_command should merely stop the execution of the makefile without interfering with the rest of the recipe.
If I set some_command as exit 1, I get
../py/py.mk:269: recipe for target 'build-gnu/genhdr/mpversion.h'
failed make: * [build-gnu/genhdr/mpversion.h] Error 1 make: *
Deleting file 'build-gnu/genhdr/mpversion.h'
If I set some_command as $(error), the recipe isn't even executed even though it's BEFORE the $(error)
Is there such a command that stops executing the makefile but doesn't delete the target?
UPDATE
I've found this hack: make .PRECIOUS depend on the target and add exit 1 as the last line in the recipe.
If the file you want to keep is an intermediate file (not mentioned as target or dependency of a rule - but possibly implied via a pattern rule), then you'll need to make it a dependency of .PRECIOUS.
Otherwise, it should be sufficient to temporarily remove or comment out the .DELETE_ON_ERROR: target that we all put in every Makefile.

How to abort makefile without error message

How can I abort makefile from continuing other targets, if certain condition is met in current target.
For example:
Step01:
## Do something
Step02: Step01_Output
## Check that Step01_output meet certain condition, otherwise, abort
Step03: Step02
## Do somethings (of course if did not abort in Step02)
# And so on
I tried using "exit" with status 0 ==> But it continues nevertheless!
I tried using "exit 1" or other exist status ==> It aborts, but gives error message at output.
I want to abort, but still not to give an error message at make calling shell.
I tried also to set env variable from Step02 and surround Step03 and after within if check like this:
ifneq ($(ToAbort),1)
Step03:
...
StepN
endif
Unfortunately, it seems that make did not even look at the condition or the variable value has not been transferred between targets.
Any ideas? May be through adding additional target or so?
I think make exits only when all the targets are created or any error arises.
By the way, commands are run in sub shells so that using`exit' will not cause make to exit.
Not sure your thinking is correct on this one.
Leave the culling of work up to make.
However,
you can express what you requested with a smattering of shell and recursive make (sorry).
You want to express "if a completes with/without error, then we are done, else carry on with b."
Step01:
command1
command2
command3 && ${MAKE} Step02
command4
Step02:
cmd5
cmd6 && ${MAKE} Step03
⋮
Note those ampersands.
if command3; then ${MAKE} Step02; fi does not do what you want.
If the make fails,
you do not want to continue into command4.
P.S. Don't forget to mark those steps as PHONY if they aren't real files.

make error: "make[1]: *** [directories] Error 1"

When I try to run "make all" on a makefile with some complexity I get this errors:
C:\BITCLOUD\BitCloud_PS_SAM3S_EK_1_10_0\BitCloud_PS_SAM3S_EK_1_10_0\Applications\ZAppSi\Dem o\SEDevice>make all
make -C makefiles/PC -f Makefile_PC_Gcc all APP_NAME=DemoSE
make[1]: Entering directory
'C:/BITCLOUD/BitCloud_PS_SAM3S_EK_1_10_0/BitCloud_PS_SAM3S_EK_1_10_0/Applications/ZAppSi/Demo/SEDevice/makefiles/PC'
A sintaxe do comando está incorrecta.
make[1]: *** [directories] Error 1
make[1]: Leaving directory
'C:/BITCLOUD/BitCloud_PS_SAM3S_EK_1_10_0/BitCloud_PS_SAM3S_EK_1_10_0/Applications/ZAppSi/Demo/SEDevice/makefiles/PC'
make: *** [all] Error 2
where the line
A sintaxe do comando está incorrecta.
translated to english means: "The syntax of the command is incorrect"
I already tried to change the project to different directories, check spaces in file names, using GNU make and also use MinGW make (mingw32-make) and the result is the same with both "make". I also checked for all files that are included in the makefile and they correspond.
Im not an expert in makefiles, so Im asking for help.
What is the main problem that occurs when make throws this type of error?
It is likely not make that throws this error, but a command executed by make returns with a nonzero exit status, in this case with status 1 (due to Error 1); then the top level make stops with Error 2. Note that make by default stops as soon as a command fails.
Since the output doesn't show what command was executed, there is no way to tell what went wrong exactly.
EDIT: from the GNU make manual:
-d Print debugging information in addition to normal processing.
The debugging information says which files are being considered
for remaking, which file-times are being compared and with what
results, which files actually need to be remade, which implicit
rules are considered and which are applied---everything inter‐
esting about how make decides what to do.
--debug[=FLAGS]
Print debugging information in addition to normal processing.
If the FLAGS are omitted, then the behavior is the same as if -d
was specified. FLAGS may be a for all debugging output (same as
using -d), b for basic debugging, v for more verbose basic
debugging, i for showing implicit rules, j for details on invo‐
cation of commands, and m for debugging while remaking make‐
files.
I suggest running make --debug=j to see the commands.

Leaving directory.....?

When I am compiling my code with makefiles (I have 12 makefiles) there is an error telling
make.exe[1]: Leaving directory Error 2 what is the reason for this?
Also what does the "Error 2 or Error 1 " mean?
When make prints "Error 2" in this context it just means that there was an error in a recursive make invocation. You have to look at the error messages preceeding that message to determine what the real problem was, in the submake. For example, given a Makefile like this:
all:
$(MAKE) -f sub.mk
... and a sub.mk like this:
all:
#exit 1
When I run GNU make, it prints the following:
gmake -f sub.mk
gmake[1]: Entering directory `/tmp/foo'
gmake[1]: *** [all] Error 1
gmake[1]: Leaving directory `/tmp/foo'
gmake: *** [all] Error 2
Error 2 tells me that there was an error of some sort in the submake. I have to look above that message, to the Error 1 message from the submake itself. There I can see that some command invoked while trying to build all exited with exit code 1. Unfortunately there's not really a standard that defines exit codes for applications, beyond the trivial "exit code 0 means OK". You have to look at the particular command that failed and check its documentation to determine what the specific exit code means.
These error messages have nothing to do with Unix errno values as others have stated. The outermost "2" is just the error code that make itself assigns when a submake has an error; the inner "1" is just the exit code of a failed command. It could just as easily be "7" or "11" or "42".

Resources