Проверить, существует ли программа из файла Makefile


Как я могу проверить, если программа вызывается из файла Makefile?

(то есть программа должна существовать в пути или иным образом быть вызываемой.)

Он может быть использован для проверки, для которого установлен компилятор, например.

например, что-то вроде этого вопроса, но без предположения, что базовая оболочка совместима с POSIX.

9 67

9 ответов:

иногда вам нужен Makefile, чтобы иметь возможность работать на разных целевых ОС, и вы хотите, чтобы сборка завершилась неудачей раньше, если требуемый исполняемый файл не находится в PATH вместо того чтобы работать на возможно продолжительное время перед сбоем.

превосходное разрешение обеспеченное engineerchuan требует цель. Однако, если у вас есть много исполняемых файлов для тестирования и ваш makefile имеет много независимых целевых объектов, каждый из которых требует тестов, то каждый целевой объект требует тестовый объект в качестве зависимости. Это делает для много дополнительного ввода, а также время обработки, когда вы делаете более одной цели за один раз.

решение предусмотренных 0xf можно проверить исполняемый файл без создания цели. Это экономит много времени ввода и выполнения, когда есть несколько целей, которые могут быть построены либо отдельно, либо вместе.

мое улучшение к последнему решению заключается в использовании which исполняемый файл (where в Windows), а не полагаться на нет --version опция в каждом исполняемом файле, непосредственно в GNU Make ifeq директива, а не определять новую переменную, и использовать GNU Make error функция для остановки сборки, если требуемый исполняемый файл не находится в ${PATH}. Например, чтобы проверить для lzop исполняемый файл:

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

если у вас есть несколько исполняемых файлов для проверки, то вы можете использовать

я смешал решения от @kenorb и @0xF и получил это:

DOT := $(shell command -v dot 2> /dev/null)

all:
ifndef DOT
    $(error "dot is not available please install graphviz")
endif
    dot -Tpdf -o pres.pdf pres.dot 

Он прекрасно работает, потому что" command-v " ничего не печатает, если исполняемый файл недоступен, поэтому переменная DOT никогда не определяется, и вы можете просто проверить ее, когда захотите в своем коде. В этом примере я бросаю ошибку, но вы можете сделать что-то более полезное, если хотите.

если переменная доступна, "command-v" выполняет недорогую операцию печати путь команды, определяющий переменную точки.

это то, что ты сделал?

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

кредит моему коллеге.

использовать shell функция для вызова вашей программы таким образом, что он печатает что-то на стандартный вывод. Например, передают --version.

GNU Make игнорирует состояние выхода команды, переданной в shell. Чтобы избежать потенциального сообщения "команда не найдена", перенаправьте стандартную ошибку на /dev/null.

затем вы можете проверить результат с помощью 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

в качестве бонуса, вывод (например, версия программы) может быть полезен в другие части вашего файла Makefile.

мое решение включает в себя небольшой вспомогательный скрипт1 что помещает файл-флаг, если все необходимые команды существуют. Это имеет то преимущество, что проверка необходимых команд выполняется только один раз, а не на каждом make ссылка.

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 подробнее о command -v техника может быть найдена здесь.

очистить некоторые из существующих решений...

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 ...) можно исключить, если вы хотите, чтобы это было спокойнее.

Это не быстро. Никакой цели не требуется.

для меня все вышеперечисленные ответы основаны на linux и не работают с windows. Я новичок, чтобы сделать так что мой подход не может быть идеальным. Но полный пример, который работает для меня на Linux и Windows это:

# detect what shell is used
ifeq ($(findstring cmd.exe,$(SHELL)),cmd.exe)
$(info "shell Windows cmd.exe")
DEVNUL := NUL
WHICH := where
else
$(info "shell Bash")
DEVNUL := /dev/null
WHICH := which
endif

# detect platform independently if gcc is installed
ifeq ($(shell ${WHICH} gcc 2>${DEVNUL}),)
$(error "gcc is not in your system PATH")
else
$(info "gcc found")
endif

необязательно, когда мне нужно обнаружить больше инструментов, которые я могу использовать:

EXECUTABLES = ls dd 
K := $(foreach myTestCommand,$(EXECUTABLES),\
        $(if $(shell ${WHICH} $(myTestCommand) 2>${DEVNUL} ),\
            $(myTestCommand) found,\
            $(error "No $(myTestCommand) in PATH)))
$(info ${K})        

решается путем компиляции специальной маленькой программы в другой целевой файл makefile, единственная цель которой-проверить все, что я искал во время выполнения.

затем я вызвал эту программу в еще одной цели makefile.

Это было что-то вроде этого, если я правильно помню:

real: checker real.c
    cc -o real real.c `./checker`

checker: checker.c
    cc -o checker checker.c

вы можете использовать встроенные команды bash, такие как type foo или command -v foo, как показано ниже:

SHELL := /bin/bash
all: check

check:
        @type foo

здесь foo - Это ваша программа/Команда. Перенаправление на > /dev/null если вы хотите, чтобы он молчал.