Reputation: 4572
I would like to create a Makefile that recognizes if a given program exists in the system and run another target (or commands) if not. Please, read my post scriptum (P.S.) at the end of the question before mark it as duplicated.
In summary, I would like do something like the following pseudocode:
if (myProgram.exists()):
myProgram arg0 arg1 arg2
else:
otherProgram arg0 arg1 arg2 #suppose that otherProgram will always exists
I've tried some solutions following the best answer of this SO question, that tells me to do something like that:
check: ; @which myProgram > /dev/null
mytarget: check
myProgram arg0 arg1 arg2
The solution actually works, but this aborts the program instead of executing another makefile target / command. I tried a lot of different implementations, but none solved my issue.
P.S: this question isn't a duplicated question from "Check if a program exists from a Makefile" because the latter aims to stop execution if the program doesn't exist, while the former aims to run another target if the program doesn't exist.
Upvotes: 7
Views: 6992
Reputation: 189799
You can put arbitrary pieces of shell script in your code. It makes sense to define the command only once, though.
COMMAND:=$(shell type -p foo || echo bar)
will set COMMAND
to foo
if it exists, otherwise to bar
.
Similar snippets can be embedded in a target if you like, but you probably will want to avoid code duplication.
target: prerequisites
{ type -p foo && foo $^ || bar $^; } >$@
As you probably already know, ack && ick || poo
is shorthand for if ack; then ick; else poo; fi
Upvotes: 7
Reputation: 4572
It's pretty easy to do something like that in a Makefile (for simple problems; complex problems demands more attention and maybe another solution).
For your example, the following code will do the trick:
run: check
myProgram arg0 arg1 arg2
check:
@type myProgram >/dev/null 2>&1 || otherProgram arg0 arg1 arg2
Of course, you should modify it for your problem. In order to help you, following you can read a real use case from a project of mine.
Now let's see a real use case taken from this small graph implementation in Python. I've write some tests with unittest
in a way that (a) I can execute it directly from Python or (b) can execute it from nose. The latter has more verbosity, so it's better for testing purposes.
To run (a) I need something like python mytest.py
. For (b) I need something like nosetests -v mytest.py
. Take a look at my makefile
:
all: run_tests
run_tests: check
nosetests -v test_digraph.py
nosetests -v test_not_digraph.py
check:
@type nosetests >/dev/null 2>&1 || /usr/bin/env python test_digraph.py
@type nosetests >/dev/null 2>&1 || /usr/bin/env python test_not_digraph.py
This makefile will check if nosetests
exists, if not it will execute the tests directly from Python (using /usr/bin/env python test_digraph.py
). If nosetests
exists, then it will execute the instructions from run_tests
target (in other words, nosetests -v test_digraph.py
and nosetests -v test_not_digraph.py
).
Hope it helps!
Upvotes: 6