Проверить, существует ли программа из файла Makefile
Как я могу проверить, если программа вызывается из файла Makefile?
(то есть программа должна существовать в пути или иным образом быть вызываемой.)
Он может быть использован для проверки, для которого установлен компилятор, например.
например, что-то вроде этого вопроса, но без предположения, что базовая оболочка совместима с POSIX.
9 ответов:
иногда вам нужен Makefile, чтобы иметь возможность работать на разных целевых ОС, и вы хотите, чтобы сборка завершилась неудачей раньше, если требуемый исполняемый файл не находится в
PATH
вместо того чтобы работать на возможно продолжительное время перед сбоем.превосходное разрешение обеспеченное engineerchuan требует цель. Однако, если у вас есть много исполняемых файлов для тестирования и ваш makefile имеет много независимых целевых объектов, каждый из которых требует тестов, то каждый целевой объект требует тестовый объект в качестве зависимости. Это делает для много дополнительного ввода, а также время обработки, когда вы делаете более одной цели за один раз.
решение предусмотренных 0xf можно проверить исполняемый файл без создания цели. Это экономит много времени ввода и выполнения, когда есть несколько целей, которые могут быть построены либо отдельно, либо вместе.
мое улучшение к последнему решению заключается в использовании
which
исполняемый файл (where
в Windows), а не полагаться на нет--version
опция в каждом исполняемом файле, непосредственно в GNU Makeifeq
директива, а не определять новую переменную, и использовать GNU Makeerror
функция для остановки сборки, если требуемый исполняемый файл не находится в${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