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.

Author: Community, 2011-04-11

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.
 34
Author: Jonathan Ben-Avraham,
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.

 34
Author: mentatkgs,
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.
 30
Author: engineerchuan,
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.

 16
Author: 0xF,
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 .

 8
Author: Flow,
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.

 6
Author: mpen,
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})        
 4
Author: Vit Bernatik,
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
 2
Author: Prof. Falken,
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.

 2
Author: kenorb,
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