Подтвердить что ты не робот

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

Как проверить, может ли программа быть вызвана из Makefile?

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

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

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

4b9b3361

Ответ 1

Иногда вам нужен 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

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

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

Обратите внимание на использование оператора присваивания := который необходим для немедленной оценки выражения RHS. Если ваш Makefile изменяет PATH, то вместо последней строки выше вам понадобится:

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

Это должно дать вам вывод, похожий на:

ads$ make
Makefile:5: *** "No dudu in PATH.  Stop.

Ответ 2

Я смешал решения из @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 

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

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

Ответ 3

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

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

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

Ответ 4

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

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

Затем вы можете проверить результат с помощью ifdef, ifndef, $(if) и т.д.

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.

Ответ 5

Мое решение включает в себя небольшой помощник script 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 можно найти здесь.

Ответ 6

Убрал некоторые из существующих решений здесь...

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)`)))

$(info ...) вы можете исключить, если вы хотите, чтобы это было тише.

Это будет быстро сбой. Не требуется цель.

Ответ 7

Для меня все приведенные выше ответы основаны на Linux и не работают с окнами. Я новичок, поэтому мой подход может быть не идеальным. Но полный пример, который работает для меня как для 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})        

Ответ 8

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

SHELL := /bin/bash
all: check

check:
        @type foo

Где foo - ваша программа/команда. Переадресация на > /dev/null, если вы хотите, чтобы он молчал.

Ответ 9

Предположим, у вас есть разные цели и строители, каждый из которых требует другого набора инструментов. Установите список таких инструментов и рассмотрите их как цель, чтобы заставить проверить их доступность

Например:

make_tools := gcc md5sum gzip

$(make_tools):  
    @which [email protected] > /dev/null

file.txt.gz: file.txt gzip
    gzip -c file.txt > file.txt.gz 

Ответ 10

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

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

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

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

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

Ответ 11

Проверка решений для вывода STDERR из --version не работает для программ, которые печатают свою версию в STDOUT вместо STDERR. Вместо проверки их вывода в STDERR или STDOUT, проверьте код возврата программы. Если программа не существует, ее код выхода всегда будет отличным от нуля.

#!/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}

Ответ 12

Я лично определяю цель require, которая работает раньше всех остальных. Эта цель просто запускает команды версий всех требований по одному и печатает соответствующие сообщения об ошибках, если команда недействительна.

all: require validate test etc

require:
    @echo "Checking the programs required for the build are installed..."
    @shellcheck --version >/dev/null 2>&1 || (echo "ERROR: shellcheck is required."; exit 1)
    @derplerp --version >/dev/null 2>&1 || (echo "ERROR: derplerp is required."; exit 1) 

# And the rest of your makefile below.

Результат приведенного ниже сценария:

Checking the programs required for the build are installed...
ERROR: derplerp is required.
makefile:X: recipe for target 'prerequisites' failed
make: *** [prerequisites] Error 1