Wie kann ich überprüfen, ob ein Programm von einem Makefile aus aufgerufen werden kann?
(Das heißt, das Programm sollte im Pfad vorhanden sein oder auf andere Weise aufgerufen werden können.)
Hiermit kann beispielsweise überprüft werden, welcher Compiler installiert ist.
ZB so etwas wie diese Frage , aber ohne anzunehmen, dass die zugrunde liegende Shell POSIX-kompatibel ist.
automake
Skript zu haben, das verschiedene Voraussetzungen überprüft und ein geeignetes Skript ausgibtMakefile
.Antworten:
Manchmal benötigen Sie ein Makefile, um auf verschiedenen Zielbetriebssystemen ausgeführt werden zu können, und Sie möchten, dass der Build frühzeitig fehlschlägt, wenn eine erforderliche ausführbare Datei nicht vorhanden ist,
PATH
anstatt möglicherweise lange vor dem Ausfall ausgeführt zu werden.Die hervorragende Lösung von Engineerchuan erfordert die Festlegung eines Ziels . Wenn Sie jedoch viele ausführbare Dateien testen müssen und Ihr Makefile viele unabhängige Ziele hat, für die jeweils Tests erforderlich sind, benötigt jedes Ziel das Testziel als Abhängigkeit. Dies bedeutet viel zusätzliche Eingabe- und Verarbeitungszeit, wenn Sie mehr als ein Ziel gleichzeitig erstellen.
Die von 0xf bereitgestellte Lösung kann auf eine ausführbare Datei testen, ohne ein Ziel zu erstellen . Dies spart viel Tipp- und Ausführungszeit, wenn mehrere Ziele separat oder zusammen erstellt werden können.
Meine Verbesserung gegenüber der letztgenannten Lösung besteht darin, die
which
ausführbare Datei (where
unter Windows) zu verwenden, anstatt sich darauf zu verlassen, dass--version
in jeder ausführbaren Datei direkt in der GNU Make-ifeq
Direktive eine Option vorhanden ist , anstatt eine neue Variable zu definieren und die GNU Make zu verwendenerror
Funktion zum Stoppen des Builds, wenn eine erforderliche ausführbare Datei nicht vorhanden ist${PATH}
. Zum Testen derlzop
ausführbaren Datei:Wenn Sie mehrere ausführbare Dateien überprüfen müssen, möchten Sie möglicherweise eine
foreach
Funktion mit derwhich
ausführbaren Datei verwenden:Beachten Sie die Verwendung des
:=
Zuweisungsoperators, der erforderlich ist, um eine sofortige Auswertung des RHS-Ausdrucks zu erzwingen. Wenn Ihr Makefile das ändertPATH
, benötigen Sie anstelle der letzten Zeile oben:Dies sollte eine Ausgabe ähnlich der folgenden ergeben:
quelle
where my_exe 2>NUL
anstelle vonwhich
.Bash
, müssen Sie keinen externen Anruf tätigenwhich
. Verwenden Siecommand -v
stattdessen die integrierte Funktion. Weitere Infos .Ich habe die Lösungen von @kenorb und @ 0xF gemischt und Folgendes erhalten:
Es funktioniert wunderbar, weil "Befehl -v" nichts druckt, wenn die ausführbare Datei nicht verfügbar ist, sodass die Variable DOT nie definiert wird und Sie sie einfach überprüfen können, wann immer Sie möchten. In diesem Beispiel wird ein Fehler ausgegeben, aber Sie könnten etwas Nützlicheres tun, wenn Sie möchten.
Wenn die Variable verfügbar ist, führt "Befehl -v" die kostengünstige Operation zum Drucken des Befehlspfads aus und definiert die DOT-Variable.
quelle
$(shell command -v dot)
scheitert mitmake: command: Command not found
. Um dies zu beheben, leiten Sie die stderr-Ausgabe nach / dev / null um :$(shell command -v dot 2> /dev/null)
. Erklärungcommand
Ist eine Bash-Funktion für mehr Portabilität in Betracht gezogenwhich
?command
Dienstprogramm wird von posix (einschließlich der-v
Option) benötigt. Andererseitswhich
hat es kein standardisiertes Verhalten (das ich kenne) und ist manchmal völlig unbrauchbarcommand -v
erfordert eine POSIX-ähnliche Shell-Umgebung. Dies funktioniert unter Windows ohne Cygwin oder eine ähnliche Emulation nicht.command
oft nicht funktioniert, liegt nicht in seiner Abwesenheit , sondern in einer besonderen Optimierung , die GNU Make vornimmt: Wenn ein Befehl "einfach genug" ist, umgeht er die Shell; Dies bedeutet leider, dass integrierte Funktionen manchmal nur funktionieren, wenn Sie den Befehl ein wenig entstellen.hast du das getan
Gutschrift an meinen Kollegen.
quelle
Verwenden Sie die
shell
Funktion, um Ihr Programm so aufzurufen, dass es etwas in die Standardausgabe druckt. Zum Beispiel bestehen--version
.GNU Make ignoriert den Exit-Status des an übergebenen Befehls
shell
. Um die mögliche Meldung "Befehl nicht gefunden" zu vermeiden, leiten Sie den Standardfehler an um/dev/null
.Dann können Sie das Ergebnis überprüfen verwenden
ifdef
,ifndef
,$(if)
usw.Als Bonus kann die Ausgabe (z. B. die Programmversion) in anderen Teilen Ihres Makefiles nützlich sein.
quelle
*** missing separator. Stop.
Wenn ich Tabulatoren in allen Zeilen hinzufüge, nachdemall:
ich Fehler erhaltemake: ifdef: Command not found
ifdef
wird wahr auswerten, auch wennyour_program
es nicht existiert gnu.org/software/make/manual/make.html#Conditional-Syntaxifdef
,else
,endif
Linien. Stellen Sie einfach sicher, dass die@echo
Zeilen mit Tabulatoren beginnen.ifdef
nach nicht leeren Variablenwerten gesucht wird. Wenn Ihre Variable nicht leer ist, wie wird sie ausgewertet?ifdef
oderifndef
(wie in der akzeptierten Antwort) nur, wenn die auszuwertende Variable sofort gesetzt wird (:=
) anstatt träge gesetzt wird (=
). Ein Nachteil der Verwendung von sofort gesetzten Variablen besteht jedoch darin, dass sie zur Deklarationszeit ausgewertet werden, während träge gesetzte Variablen beim Aufruf ausgewertet werden. Dies bedeutet, dass Sie Befehle für Variablen ausführen würden,:=
selbst wenn Make nur Regeln ausführt , die diese Variablen niemals verwenden! Sie können dies vermeiden, indem Sie ein=
withifneq ($(MY_PROG),)
Einige der vorhandenen Lösungen hier wurden bereinigt ...
Das
$(info ...)
können Sie ausschließen , wenn Sie diese leiser sein wollen.Dies wird schnell fehlschlagen . Kein Ziel erforderlich.
quelle
Meine Lösung beinhaltet ein kleines Hilfsskript 1 , das eine Flag-Datei platziert, wenn alle erforderlichen Befehle vorhanden sind. Dies hat den Vorteil, dass die Überprüfung auf die erforderlichen Befehle nur einmal und nicht bei jedem
make
Aufruf erfolgt.check_cmds.sh
Makefile
1 Mehr zur
command -v
Technik finden Sie hier .quelle
if
Anweisung ein "unerwartetes Dateiende" .Für mich basieren alle oben genannten Antworten auf Linux und funktionieren nicht mit Windows. Ich bin neu in der Entwicklung, daher ist mein Ansatz möglicherweise nicht ideal. Das vollständige Beispiel, das für mich sowohl unter Linux als auch unter Windows funktioniert, ist das folgende:
Optional kann ich Folgendes verwenden, wenn ich weitere Tools erkennen muss:
quelle
Sie können bash-erstellte Befehle wie
type foo
odercommand -v foo
wie folgt verwenden:Wo
foo
ist dein Programm / Befehl? Weiterleiten an,> /dev/null
wenn Sie möchten, dass es stumm geschaltet wird.quelle
Angenommen, Sie haben unterschiedliche Ziele und Builder, für die jeweils andere Tools erforderlich sind. Legen Sie eine Liste solcher Tools fest und betrachten Sie sie als Ziel, um die Überprüfung ihrer Verfügbarkeit zu erzwingen
Beispielsweise:
quelle
Ich persönlich definiere ein
require
Ziel, das vor allen anderen läuft. Dieses Ziel führt einfach die Versionsbefehle aller Anforderungen einzeln aus und druckt die entsprechenden Fehlermeldungen, wenn der Befehl ungültig ist.Die Ausgabe des folgenden Skripts lautet
quelle
Gelöst durch Kompilieren eines speziellen kleinen Programms in einem anderen Makefile-Ziel, dessen einziger Zweck darin besteht, nach den gewünschten Laufzeitsachen zu suchen.
Dann habe ich dieses Programm in einem weiteren Makefile-Ziel aufgerufen.
Es war so etwas, wenn ich mich richtig erinnere:
quelle
Die Lösungen, die auf
STDERR
Ausgabe von prüfen,--version
funktionieren nicht für Programme, die ihre VersionSTDOUT
anstelle von druckenSTDERR
. Anstatt ihre Ausgabe anSTDERR
oder zuSTDOUT
überprüfen, suchen Sie nach dem Programmrückgabecode. Wenn das Programm nicht existiert, ist sein Exit-Code immer ungleich Null.quelle