Check if a program exists from a Makefile

后端 未结 12 1082
时光取名叫无心
时光取名叫无心 2020-12-12 20:20

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 chec

相关标签:
12条回答
  • 2020-12-12 20:36

    Sometimes you need a Makefile to be able to run on different target OS's and you want the build to fail early if a required executable is not in PATH rather than to run for a possibly long time before failing.

    The excellent solution provided by engineerchuan requires making a target. However, if you have many executables to test and your Makefile has many independent targets, each of which requires the tests, then each target requires the test target as a dependency. That makes for a lot of extra typing as well as processing time when you make more than one target at a time.

    The solution provided by 0xf can test for an executable without making a target. That saves a lot of typing and execution time when there are multiple targets that can be built either separately or together.

    My improvement to the latter solution is to use the which executable (where in Windows), rather than to rely on there being a --version option in each executable, directly in the GNU Make ifeq directive, rather than to define a new variable, and to use the GNU Make error function to stop the build if a required executable is not in ${PATH}. For example, to test for the lzop executable:

     ifeq (, $(shell which lzop))
     $(error "No lzop in $(PATH), consider doing apt-get install lzop")
     endif
    

    If you have several executables to check, then you might want to use a foreach function with the which executable:

    EXECUTABLES = ls dd dudu lxop
    K := $(foreach exec,$(EXECUTABLES),\
            $(if $(shell which $(exec)),some string,$(error "No $(exec) in PATH")))
    

    Note the use of the := assignment operator that is required in order to force immediate evaluation of the RHS expression. If your Makefile changes the PATH, then instead of the last line above you will need:

            $(if $(shell PATH=$(PATH) which $(exec)),some string,$(error "No $(exec) in PATH")))
    

    This should give you output similar to:

    ads$ make
    Makefile:5: *** "No dudu in PATH.  Stop.
    
    0 讨论(0)
  • 2020-12-12 20:36

    The solutions checking for STDERR output of --version does not work for programs which print their version to STDOUT instead of STDERR. Instead of checking their output to STDERR or STDOUT, check for the program return code. If the program does not exist, its exit code will always be non zero.

    #!/usr/bin/make -f
    # https://stackoverflow.com/questions/7123241/makefile-as-an-executable-script-with-shebang
    ECHOCMD:=/bin/echo -e
    SHELL := /bin/bash
    
    RESULT := $(shell python --version >/dev/null 2>&1 || (echo "Your command failed with $$?"))
    
    ifeq (,${RESULT})
        EXISTS := true
    else
        EXISTS := false
    endif
    
    all:
        echo EXISTS: ${EXISTS}
        echo RESULT: ${RESULT}
    
    0 讨论(0)
  • 2020-12-12 20:38

    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.

    0 讨论(0)
  • 2020-12-12 20:43

    Solved by compiling a special little program in another makefile target, whose sole purpose is to check for whatever runtime stuff I was looking for.

    Then, I called this program in yet another makefile target.

    It was something like this if I recall correctly:

    real: checker real.c
        cc -o real real.c `./checker`
    
    checker: checker.c
        cc -o checker checker.c
    
    0 讨论(0)
  • 2020-12-12 20:46

    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 
    
    0 讨论(0)
  • 2020-12-12 20:47

    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.

    0 讨论(0)
提交回复
热议问题