Check if a program exists from a Makefile

2019-01-21 18:05发布

How can I check if a program is callable from a Makefile?

(That is, the program should exist in the path or otherwise be callable.)

It could be used to check for which compiler is installed, for instance.

E.g. something like this question, but without assuming the underlying shell is POSIX compatible.

10条回答
乱世女痞
2楼-- · 2019-01-21 18:38

is this what you did?

check: PYTHON-exists
PYTHON-exists: ; @which python > /dev/null
mytarget: check
.PHONY: check PYTHON-exists

credit to my coworker.

查看更多
萌系小妹纸
3楼-- · 2019-01-21 18:39

Assume you have different targets and builders, each requires another set of tools. Set a list of such tools and consider them as target to force checking their availability

For example:

make_tools := gcc md5sum gzip

$(make_tools):  
    @which $@ > /dev/null

file.txt.gz: file.txt gzip
    gzip -c file.txt > file.txt.gz 
查看更多
The star\"
4楼-- · 2019-01-21 18:40

Use the shell function to call your program in a way that it prints something to standard output. For example, pass --version.

GNU Make ignores the exit status of the command passed to shell. To avoid the potential "command not found" message, redirect standard error to /dev/null.

Then you may check the result using ifdef, ifndef, $(if) etc.

YOUR_PROGRAM_VERSION := $(shell your_program --version 2>/dev/null)

all:
ifdef YOUR_PROGRAM_VERSION
    @echo "Found version $(YOUR_PROGRAM_VERSION)"
else
    @echo Not found
endif

As a bonus, the output (such as program version) might be useful in other parts of your Makefile.

查看更多
成全新的幸福
5楼-- · 2019-01-21 18:41

You can use bash built commands such as type foo or command -v foo, as below:

SHELL := /bin/bash
all: check

check:
        @type foo

Where foo is your program/command. Redirect to > /dev/null if you want it silent.

查看更多
Evening l夕情丶
6楼-- · 2019-01-21 18:43

Cleaned up some of the existing solutions here...

REQUIRED_BINS := composer npm node php npm-shrinkwrap
$(foreach bin,$(REQUIRED_BINS),\
    $(if $(shell command -v $(bin) 2> /dev/null),$(info Found `$(bin)`),$(error Please install `$(bin)`)))

The $(info ...) you can exclude if you want this to be quieter.

This will fail fast. No target required.

查看更多
甜甜的少女心
7楼-- · 2019-01-21 18:46

My solution involves a little helper script1 that places a flag file if all required commands exist. This comes with the advantage that the check for the required commands is only done once and not on every make invocation.

check_cmds.sh

#!/bin/bash

NEEDED_COMMANDS="jlex byaccj ant javac"

for cmd in ${NEEDED_COMMANDS} ; do
    if ! command -v ${cmd} &> /dev/null ; then
        echo Please install ${cmd}!
        exit 1
    fi
done

touch .cmd_ok

Makefile

.cmd_ok:
    ./check_cmds.sh

build: .cmd_ok target1 target2

1 More about the command -v technique can be found here.

查看更多
登录 后发表回答