Jak mogę sprawdzić, czy program można wywołać z pliku Makefile?
(Oznacza to, że program powinien istnieć w ścieżce lub być w inny sposób wywoływalny).
Można go użyć 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 kompatybilna z POSIX.
automake
skryptu, który sprawdza różne wymagania wstępne i wypisuje odpowiedni plikMakefile
.Odpowiedzi:
Czasami potrzebujesz Makefile, aby móc działać na różnych docelowych systemach operacyjnych i chcesz, aby kompilacja zakończyła się niepowodzeniem, jeśli nie ma wymaganego pliku wykonywalnego,
PATH
zamiast działać przez możliwie długi czas, zanim ulegnie awarii.Doskonałe rozwiązanie dostarczone przez inżyniera wymaga wyznaczenia 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 celu testowego jako zależności. To powoduje dużo dodatkowego pisania, a także czas przetwarzania, gdy tworzysz więcej niż jeden cel naraz.
Rozwiązanie dostarczone przez 0xf może testować plik wykonywalny bez tworzenia celu. Oszczędza to dużo czasu na pisanie i wykonywanie, gdy istnieje wiele celów, które można zbudować oddzielnie lub razem.
Moim ulepszeniem tego ostatniego rozwiązania jest użycie
which
pliku wykonywalnego (where
w systemie Windows), zamiast polegać na--version
opcji w każdym pliku wykonywalnym, bezpośrednio wifeq
dyrektywie GNU Make , zamiast definiować nową zmienną i używać GNU Makeerror
funkcji, aby zatrzymać kompilację, jeśli nie ma wymaganego pliku wykonywalnego${PATH}
. Na przykład, aby przetestowaćlzop
plik wykonywalny:Jeśli masz kilka plików wykonywalnych do sprawdzenia, możesz chcieć użyć
foreach
funkcji zwhich
plikiem wykonywalnym:Zwróć uwagę na użycie
:=
operatora przypisania, który jest wymagany w celu wymuszenia natychmiastowej oceny wyrażenia RHS. Jeśli twój plik Makefile zmieniPATH
, to zamiast ostatniej linii powyżej będziesz potrzebować:Powinno to dać wynik podobny do:
źródło
where my_exe 2>NUL
zamiastwhich
.Bash
, nie musisz wykonywać połączenia zewnętrznegowhich
.command -v
Zamiast tego użyj wbudowanego . Więcej info .Zmieszałem rozwiązania z @kenorb i @ 0xF i otrzymałem to:
Działa pięknie, ponieważ "polecenie -v" nie drukuje niczego, jeśli plik wykonywalny nie jest dostępny, więc zmienna DOT nigdy nie jest definiowana i możesz ją po prostu sprawdzić, kiedy chcesz w swoim kodzie. W tym przykładzie zgłaszam błąd, ale jeśli chcesz, możesz zrobić coś bardziej użytecznego.
Jeśli zmienna jest dostępna, "polecenie -v" wykonuje niedrogą operację drukowania ścieżki poleceń, definiując zmienną DOT.
źródło
$(shell command -v dot)
nie udaje sięmake: command: Command not found
. Aby rozwiązać ten problem, przekierowywać wyjście stderr do / dev / null:$(shell command -v dot 2> /dev/null)
. Wyjaśnieniecommand
czy bash jest wbudowany, dla większej przenośności, rozważ użyciewhich
?command
narzędzie jest wymagane przez posix (łącznie z-v
opcją). Z drugiej stronywhich
nie ma standardowego zachowania (o którym wiem) i czasami jest po prostu bezużytecznecommand -v
wymaga środowiska powłoki podobnego do POSIX. To nie zadziała w systemie Windows bez emulacji cygwin lub podobnej.command
często nie działa, nie jest jego brak , ale szczególna optymalizacja, którą wykonuje GNU Make: jeśli polecenie jest „wystarczająco proste”, ominie powłokę; niestety oznacza to, że wbudowane czasami nie będą działać, chyba że trochę zmienisz polecenie.czy to właśnie zrobiłeś?
kredyt dla mojego współpracownika.
źródło
Użyj tej
shell
funkcji, aby wywołać swój program w taki sposób, że wypisze coś na standardowe wyjście. Na przykład pass--version
.GNU Make ignoruje kod zakończenia polecenia przekazanego do
shell
. Aby uniknąć potencjalnego komunikatu „nie znaleziono polecenia”, przekieruj standardowy błąd do/dev/null
.Następnie można sprawdzić wyniki za pomocą
ifdef
,ifndef
,$(if)
itd.Jako bonus, dane wyjściowe (takie jak wersja programu) mogą być przydatne w innych częściach pliku Makefile.
źródło
*** missing separator. Stop.
Jeśli dodam karty we wszystkich wierszach poall:
otrzymaniu błędumake: ifdef: Command not found
ifdef
oceni prawdę, nawet jeśliyour_program
nie istnieje gnu.org/software/make/manual/make.html#Conditional-Syntaxifdef
,else
,endif
linie. Tylko upewnij się, że@echo
linie zaczynają się od tabulatorów.ifdef
sprawdza niepustą wartość zmiennej. Jeśli zmienna nie jest pusta, do czego się to oblicza?ifdef
lubifndef
(jak w zaakceptowanej odpowiedzi) działa tylko wtedy, gdy oceniana zmienna jest natychmiast ustawiana (:=
) zamiast leniwie set (=
). Jednak wadą używania natychmiast ustawianych zmiennych jest to, że są one oceniane w czasie deklaracji, podczas gdy zmienne ustawiane leniwie są oceniane, gdy są wywoływane. Oznacza to, że wykonywałbyś polecenia dla zmiennych:=
nawet wtedy, gdy Make uruchamia tylko reguły, które nigdy nie używają tych zmiennych! Możesz tego uniknąć, używając=
withifneq ($(MY_PROG),)
Wyczyszczono niektóre z istniejących rozwiązań tutaj ...
$(info ...)
Można wykluczyć, jeśli chcesz to być ciszej.To szybko się nie powiedzie . Nie jest wymagany cel.
źródło
Moje rozwiązanie obejmuje mały skrypt pomocniczy 1, który umieszcza plik flag, jeśli istnieją wszystkie wymagane polecenia. Ma to tę zaletę, że sprawdzenie wymaganych poleceń jest wykonywane tylko raz i nie przy każdym
make
wywołaniu.check_cmds.sh
Makefile
1 Więcej o tej
command -v
technice można znaleźć tutaj .źródło
if
stwierdzeniu pojawia się komunikat „nieoczekiwany koniec pliku” .Dla mnie wszystkie powyższe odpowiedzi oparte są na Linuksie i nie działają z Windows. Jestem nowy, więc moje podejście może nie być idealne. Ale kompletny przykład, który działa dla mnie zarówno w systemie Linux, jak i Windows, jest następujący:
opcjonalnie, gdy potrzebuję znaleźć więcej narzędzi, których mogę użyć:
źródło
Możesz użyć poleceń wbudowanych w bash, takich jak
type foo
lubcommand -v foo
, jak poniżej:Gdzie
foo
jest twój program / polecenie. Przekieruj do,> /dev/null
jeśli chcesz, aby było cicho.źródło
Załóżmy, że masz różne cele i konstruktorów, każdy wymaga innego zestawu narzędzi. Ustaw listę takich narzędzi i potraktuj je jako cel, aby wymusić sprawdzenie ich dostępności
Na przykład:
źródło
Osobiście określam
require
cel, który wyprzedza wszystkie inne. Ten cel po prostu uruchamia polecenia wersji wszystkich wymagań pojedynczo i wyświetla odpowiednie komunikaty o błędach, jeśli polecenie jest niepoprawne.Wynik poniższego skryptu to
źródło
Rozwiązany przez skompilowanie specjalnego małego programu w innym docelowym pliku makefile, którego jedynym celem jest sprawdzenie wszelkich elementów środowiska wykonawczego, których szukałem.
Następnie nazwałem ten program kolejnym celem makefile.
To było coś takiego, jeśli dobrze pamiętam:
źródło
Rozwiązania sprawdzające
STDERR
wyjście programu--version
nie działają w przypadku programów, które wypisują swoją wersjęSTDOUT
zamiastSTDERR
. Zamiast sprawdzać ich wyjście doSTDERR
lubSTDOUT
, sprawdź kod powrotu programu. Jeśli program nie istnieje, jego kod zakończenia będzie zawsze różny od zera.źródło