Paladini
Paladini

Reputation: 4572

Check if a program exists from a Makefile, otherwise run command

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.

How can I achieve something like that in a Makefile?

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

Answers (2)

tripleee
tripleee

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

Paladini
Paladini

Reputation: 4572

A general use case:

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.


A real use case:

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

Related Questions