Sprawdź, czy program istnieje z pliku Makefile
Jak mogę sprawdzić, czy program można wywołać z Makefile?
(tzn. program powinien istnieć w ścieżce lub w inny sposób być wywołany.)
Może być użyty na przykład do sprawdzenia, dla którego kompilatora jest zainstalowany.
Np. coś w rodzaju tego pytania , ale bez zakładania, że podstawowa powłoka jest zgodna z POSIX.
9 answers
Czasami potrzebujesz pliku Makefile, aby móc działać na różnych systemach operacyjnych i chcesz, aby kompilacja zawierała się wcześniej, jeśli wymagany plik wykonywalny nie znajduje się w PATH
, zamiast działać przez prawdopodobnie długi czas przed niepowodzeniem.
Doskonałe rozwiązanie dostarczone przez engineerchuan wymaga wykonania celu . Jeśli jednak masz wiele plików wykonywalnych do przetestowania, a Twój plik makefile ma wiele niezależnych celów, z których każdy wymaga testów, to każdy cel wymaga testu cel jako zależność. To sprawia, że dużo dodatkowego pisania, a także Czas Przetwarzania, gdy robisz więcej niż jeden cel na raz.
Rozwiązanie dostarczone przez 0xf może testować dla pliku wykonywalnego bez tworzenia celu. Pozwala to zaoszczędzić dużo czasu pisania i wykonywania, gdy istnieje wiele celów, które można zbudować osobno lub razem.
Moim ulepszeniem do tego ostatniego rozwiązania jest użycie which
wykonywalnego (where
W Windows), a nie poleganie na tym jest opcją --version
w każdym pliku wykonywalnym, bezpośrednio w dyrektywie GNU Make ifeq
, zamiast definiować nową zmienną i używać funkcji GNU Make error
do zatrzymania kompilacji, jeśli wymagany plik wykonywalny nie znajduje się w ${PATH}
. Na przykład, aby przetestować dla pliku wykonywalnego lzop
:
ifeq (, $(shell which lzop))
$(error "No lzop in $(PATH), consider doing apt-get install lzop")
endif
Jeśli masz kilka plików wykonywalnych do sprawdzenia, możesz użyć funkcji foreach
z which
wykonywalnym:
EXECUTABLES = ls dd dudu lxop
K := $(foreach exec,$(EXECUTABLES),\
$(if $(shell which $(exec)),some string,$(error "No $(exec) in PATH)))
Zwróć uwagę na użycie :=
operatora przypisania, który jest wymagany w celu wymusić natychmiastową ocenę ekspresji RHS. Jeśli Twój plik Makefile zmieni PATH
, to zamiast ostatniej linii powyżej będziesz potrzebował:
$(if $(shell PATH=$(PATH) which $(exec)),some string,$(error "No $(exec) in PATH)))
To powinno dać wynik podobny do:
ads$ make
Makefile:5: *** "No dudu in PATH. Stop.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:29
Zmieszałem rozwiązania z @ kenorb i @0XF i dostałem to:
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
To działa pięknie, ponieważ "command-v" nie wyświetla niczego, jeśli plik wykonywalny nie jest dostępny, więc zmienna DOT nigdy nie zostanie zdefiniowana i możesz ją po prostu sprawdzić, kiedy tylko chcesz w kodzie. W tym przykładzie rzucam błąd, ale możesz zrobić coś bardziej użytecznego, jeśli chcesz.
Jeśli zmienna jest dostępna, "command-v" wykonuje niedrogą operację wypisania ścieżki polecenia, definiowanie zmiennej DOT.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-03 14:49:18
To właśnie zrobiłeś?
check: PYTHON-exists
PYTHON-exists: ; @which python > /dev/null
mytarget: check
.PHONY: check PYTHON-exists
Podziękowania dla mojego współpracownika.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-30 09:48:13
Użyj funkcji shell
, aby wywołać program w taki sposób, aby wydrukował coś na standardowe wyjście. Na przykład, pass --version
.
GNU Make ignoruje status zakończenia polecenia przekazanego do shell
. Aby uniknąć potencjalnego komunikatu "command not found", przekieruj standardowy błąd na /dev/null
.
Następnie możesz sprawdzić wynik za pomocą ifdef
, ifndef
, $(if)
itd.
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
Jako bonus, wyjście (takie jak wersja programu) może być przydatne w innych częściach pliku Makefile.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-08 14:04:38
Moje rozwiązanie polega na małym skrypcie pomocniczym1 umieszcza plik flagi, jeśli istnieją wszystkie wymagane polecenia. Ma to tę zaletę, że sprawdzanie wymaganych poleceń odbywa się tylko raz, a nie przy każdym wywołaniu 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 więcej o technice command -v
można znaleźć tutaj .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:02
Wyczyściłem niektóre z istniejących rozwiązań tutaj...
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 ...)
możesz wykluczyć, jeśli chcesz, aby było ciszej.
To szybko się nie powiedzie . Cel nie jest potrzebny.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-12 21:41:29
Dla mnie wszystkie powyższe odpowiedzi są oparte na Linuksie i nie działają z Windowsem. Jestem nowy, więc moje podejście może nie być idealne. Ale kompletny przykład, który działa dla mnie zarówno na Linuksie, jak i windows jest taki:
# 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
Opcjonalnie, gdy muszę wykryć więcej narzędzi, których mogę użyć:
EXECUTABLES = ls dd
K := $(foreach myTestCommand,$(EXECUTABLES),\
$(if $(shell ${WHICH} $(myTestCommand) 2>${DEVNUL} ),\
$(myTestCommand) found,\
$(error "No $(myTestCommand) in PATH)))
$(info ${K})
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-22 20:31:14
Rozwiązany przez kompilację specjalnego małego programu w innym pliku docelowym makefile, którego jedynym celem jest sprawdzenie, czy nie ma tego, czego szukałem.
Potem wywołałem ten program w kolejnym celu makefile.
To było coś takiego o ile dobrze pamiętam:
real: checker real.c
cc -o real real.c `./checker`
checker: checker.c
cc -o checker checker.c
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-04 11:24:45
Możesz używać wbudowanych poleceń bash, takich jak type foo
lub command -v foo
, Jak poniżej:
SHELL := /bin/bash
all: check
check:
@type foo
Gdzie foo
jest Twoim programem / poleceniem. Przekieruj na > /dev/null
, Jeśli chcesz, żeby było cicho.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-24 16:02:50