问题
Is there a way to exit with an error condition if a file does not exist? I am currently doing something like this:
all: foo
foo:
test -s /opt/local/bin/gsort || echo "GNU sort does not exist! Exiting..." && exit
Running make
runs the all
target, which runs foo
.
The expectation is that if the test -s
conditional fails, then the echo/exit
statements are executed.
However, even if /usr/bin/gsort
exists, I get the result of the echo
statement but the exit
command does not run. This is the opposite of what I am hoping to accomplish.
What is the correct way to do something like the above?
回答1:
exit alone returns the status of the last command executed. In this case, it returns zero, which means everything is ok.
This is, because ||
and &&
have equal precedence, and the shell interprets the command as if it were written
( test ... || echo ... ) && exit
If you want to signal failure you must exit with a non zero value, e.g. exit 1
.
And if you want to echo and exit, just put the commands in sequence separated by ;
all: foo
foo:
test -s /opt/local/bin/gsort || { echo "GNU sort does not exist! Exiting..."; exit 1; }
回答2:
I realize this is a bit old at this point, but you don't need to even use a subshell to test if a file exists in Make.
It also depends on how you want/expect it to run.
Using the wildcard function, like so:
all: foo
foo:
ifeq (,$(wildcard /opt/local/bin/gsort))
$(error GNU Sort does not exist!)
endif
is one good way to do it. Note here that the ifeq clause is not indented because it is evaluated before the target itself.
If you want this to happen unconditionally for every target, you can just move it outside of a target:
ifeq (,$(wildcard /opt/local/bin/gsort))
$(error GNU Sort does not exist!)
endif
回答3:
Every command line in make runs in its own sub-shell. So running exit
just exits that sub-shell--not the makefile as a whole. By default, make
execution will stop if any sub-shell returns an unsuccessful exit status (by convention, 0 means success, so anything else will halt execution). The simplest method would be just to use the exit status of the test
command:
all: foo
foo:
test -s /opt/local/bin/gsort
Printing a diagnostic message complicates things slightly because commands like echo
will return an exit status of 0, causing make
to think everything is fine. To work around this, you need to run a command after it that will give the sub-shell a non-zero exit status:
all: foo
foo:
test -s /opt/local/bin/gsort || { echo "GNU sort does not exist! Exiting..."; exit 1; }
or even just
all: foo
foo:
test -s /opt/local/bin/gsort || { echo "GNU sort does not exist! Exiting..."; false; }
回答4:
Since you're checking whether gsort
executable file exists, you can use which
or type
shell command for that, e.g.:
all: foo
:
foo:
which gsort || exit 1
# or
type gsort || exit 1
You don't need an error message, since it'll automatically print:
/bin/sh: line 0: type:
gsort
: not found
which is obvious.
Alternatively use test
or [
(see: help test
/help [
for syntax), e.g.
test -x /opt/local/bin/gsort || { echo Error msg; exit 1; }
which checks if given file exists and it's executable, otherwise show the message and exit. The parenthesis are important to override the normal precedence of operators (left to right) by grouping the commands (see Compound Commands
section in man bash
for further info).
Another way is to use the rule's targets to check if the file exists and add as dependency to all
, e.g.
all: /opt/local/bin/gsort
@echo Success.
/opt/local/bin/gsort:
@echo "GNU sort does not exist! Exiting..."
exit 1
Result:
$ make
GNU sort does not exist! Exiting...
exit 1
make: *** [/opt/local/bin/gsort] Error 1
回答5:
Simply do:
all: /opt/local/bin/gsort
and if /opt/local/bin/gsort
is missing, you will get a "no rule to make target `/opt/local/bin/gsort'" error message.
But if you also want some nice explanation with it do:
/opt/local/bin/gsort:
echo "GNU sort does not exist! Exiting..."
false
In GNU/Make if the target is not declared .PHONEY
and doesn't have any dependencies, the rule will be invoked if a file matching that target does not exist.
The code above will trigger the false
command only when /opt/local/bin/gsort
does not exist, will return a non 0 value, and make will fail.
来源:https://stackoverflow.com/questions/14348741/testing-if-a-file-exists-in-makefile-target-and-quitting-if-not-present