Wie kann ein Makefile erkennen, ob ein Befehl auf dem lokalen Computer verfügbar ist?

11

Ich begann den Org-Modus zu verwenden, um meine Aufgaben im GTD- Stil zu planen . Wenn ich alle Organisationsdateien in einem Verzeichnis eines Dropbox- Ordners ablege, führe ich Emacs aus, um diese Dateien auf drei verschiedenen lokalen Computern zu bearbeiten / verwalten: Cygwin, Mac OS X und Debian. Da ich auch MobileOrg verwende, um von meinem iPad aus auf diese Organisationsdateien zuzugreifen, checksums.datmuss eine Datei auf dem neuesten Stand gehalten werden, wenn Änderungen vorgenommen werden. Dies kann durch Ausführen erfolgen md5sum *.org > checksums.dat.

Das Problem ist, dass es drei verschiedene Befehle für md5sumBefehle gibt: md5sum.exein Cygwin, md5in Mac OS X und md5sumin Debian. Die idealste Situation ist ein Makefile, das in einem Dropbox-Ordner gespeichert ist, erkennt, welcher Befehl auf dem aktuellen Computer verfügbar ist, und führt diesen Befehl aus, um die md5-Prüfsummenoperation auszuführen.

Federico Magallanez
quelle
gnuautotools
Kevin
1
@ Kevin Das klingt nach einem Overkill. Ich möchte kein Programm auf drei verschiedenen Systemen installieren. In jedem System kann auf einen Dropbox-Ordner als lokales Verzeichnis zugegriffen werden. Wenn ich make checksumzur Generierung von Prüfsummen-Daten in einem Dropbox-Ordner ausgeführt werde, möchte ich, dass das Makefile einen geeigneten Befehl verwendet, nachdem festgestellt wurde, welcher Prüfsummenbefehl auf dem aktuellen Computer verfügbar ist.
Federico Magallanez
Wenn Sie eine erhebliche Menge an Skripten erstellen möchten und das Projekt klein ist, würde ich Scons vorschlagen.
Faheem Mitha

Antworten:

7

Mögliche Befehle zum Generieren einer Prüfsumme

Leider gibt es kein Standarddienstprogramm zum Generieren einer kryptografischen Prüfsumme. Es gibt ein Standarddienstprogramm zum Generieren eines CRC : cksum; Dies kann ausreichen, um Änderungen in einer nicht feindlichen Umgebung zu erkennen.

Ich würde empfehlen, SHA1 anstelle von MD5 zu verwenden. Es gibt nicht viele Systeme mit einem MD5-Dienstprogramm, aber ohne SHA1. Wenn Sie kryptografische Prüfsummen verwenden, können Sie auch einen Algorithmus ohne bekannte Methode zum Auffinden von Kollisionen verwenden (vorausgesetzt, Sie überprüfen auch die Größe).

Ein Tool, das nicht Standard ist, aber häufig verwendet wird und Digests berechnen kann, ist OpenSSL . Es ist für Cygwin, Debian und OSX verfügbar, aber leider nicht Teil der Standardinstallation unter OSX.

openssl dgst -sha1

Unter OSX 10.6 gibt es ein shasumDienstprogramm, das auch unter Debian vorhanden ist (es ist Teil desperl Pakets) vorhanden ist, und ich glaube auch unter Cygwin. Dies ist ein Perl-Skript. Auf den meisten Unix-Systemen ist Perl installiert, sodass Sie dieses Skript neben Ihrem Makefile bündeln können, wenn Sie befürchten, dass dieses Skript nicht überall verfügbar ist.

Auswahl des richtigen Befehls für Ihr System

Angenommen, Sie können wirklich keinen Befehl finden, der überall funktioniert.

In der Schale

Verwenden Sie die typeintegrierte Funktion, um festzustellen, ob ein Befehl verfügbar ist.

sum=
for x in sha1sum sha1 shasum 'openssl dgst -sha1'; do
  if type "${x%% *}" >/dev/null 2>/dev/null; then sum=$x; break; fi
done
if [ -z "$sum" ]; then echo 1>&2 "Unable to find a SHA1 utility"; exit 2; fi
$sum *.org

GNU machen

Mit der shellFunktion können Sie beim Laden des Makefiles ein Shell-Snippet ausführen und die Ausgabe in einer Variablen speichern.

sum := $(shell { command -v sha1sum || command -v sha1 || command -v shasum; } 2>/dev/null)
%.sum: %
        $(sum) $< >$@

Portable (POSIX) machen

Sie können Shell-Befehle nur in Regeln ausführen, daher muss jede Regel, die eine Prüfsumme berechnet, den Suchcode enthalten. Sie können das Snippet in eine Variable einfügen. Denken Sie daran, dass separate Zeilen in Regeln unabhängig voneinander ausgewertet werden. Denken Sie auch daran, dass $Zeichen, die an die Shell übergeben werden sollen, maskiert werden müssen $$.

determine_sum = \
        sum=; \
        for x in sha1sum sha1 shasum 'openssl dgst -sha1'; do \
          if type "$${x%% *}" >/dev/null 2>/dev/null; then sum=$$x; break; fi; \
        done; \
        if [ -z "$$sum" ]; then echo 1>&2 "Unable to find a SHA1 utility"; exit 2; fi

checksums.dat: FORCE
    $(determine_sum); \
    $$sum *.org
Gilles 'SO - hör auf böse zu sein'
quelle
Ich musste die -POption des typeBefehls verwenden, damit die oben beschriebene Methode "GNU make" ordnungsgemäß funktioniert sum := $(shell { type -P sha1sum || type -P sha1 || type -P shasum; } 2>/dev/null).
Sean
@ Sean Danke für den Fehlerbericht. type -Pfunktioniert nur, wenn Ihre Shell bash ist, nicht wenn es zB ksh oder dash ist (was unter anderem unter Ubuntu der Fall ist). Sie können command -vfür die Portabilität verwenden.
Gilles 'SO - hör auf böse zu sein'
Es scheint, dass Sie von "Verwenden" typezu "Verwenden" gewechselt haben command. Sollten auch die anderen Methoden aktualisiert werden?
Sean
@Sean Die anderen Methoden sind in Ordnung: Dies typeist eine korrekte, tragbare Methode, um das Vorhandensein eines Befehls zu testen. Das Problem dabei ist, dass die Ausgabe sha1sum is /usr/bin/sha1sumnicht nur dem Programmnamen entspricht. Dies war der einzige Ort, an dem ich die Ausgabe typeund nicht nur den Rückgabewert verwendet habe.
Gilles 'SO - hör auf böse zu sein'
5

Es ist so etwas wie ein Hack, aber Sie können testen, ob jeder existiert, und sie ausführen, wenn dies der Fall ist:

[ -x "`which md5 2>/dev/null`" ] && md5 newfile >>sums
[ -x "`which md5sum 2>/dev/null`" ] && md5sum newfile >>sums

Ich bin mir ziemlich sicher, dass Cygwin Befehle (einschließlich md5sum) ohne das erkennt .exe, aber schließen Sie sie ein, wenn Sie müssen.

Kevin
quelle
4
whichExit-Werte sind nicht portierbar. Verwenden Sie typestattdessen (und Sie möchten wahrscheinlich verwenden if; then; elif, um Probleme zu vermeiden, da mehrere ausführbare Dateien vorhanden sind). whichund typesuchen Sie sowieso nur nach ausführbaren Dateien, so dass Ihr Test mit -x sinnlos ist.
Chris Down
Weitere Informationen zur Verwendung von "type": cmd = $ (für cmd in foo md5 md5sum bar; geben Sie $ cmd> / dev / null 2> & 1 && echo $ cmd && break; done ein); $ cmd file1 file2 file3> md5.txt
michael
1

Entweder GNU-Autotools (wie in einem Kommentar erwähnt) oder auch CMake sind eine Option.

GNU-Autotools sind der traditionellere Ansatz, aber (und vielleicht nur für mich selbst) ich glaube nicht, dass die Leute wirklich zu aufgeregt sind über die Aussicht, zunächst ein Projekt mit ihnen einzurichten. Nun, es ist auf jeden Fall eine Lernkurve. CMake ist das neuere Kind auf dem Block und vielleicht weniger verbreitet (und hat immer noch eine Lernkurve). Es hat eine eigene Syntax und generiert Makefiles für Ihre Plattform. CMake hat den entscheidenden Vorteil, dass es nicht so un * x-zentriert ist. Es funktioniert auch zuverlässig unter Unix, Windows und Mac (z. B. kann es beispielsweise MSVC-Projekte anstelle von Makefiles generieren.)

Bearbeiten: und natürlich, da 'Makefiles' vorgeschlagen wurden, geht diese Antwort mit dieser Vermutung einher. Aber vielleicht wäre nur ein Python-Skript oder (nach Luft schnappen) ein einfaches Java-Programm für diese Aufgabe besser geeignet. Die Skript- / Programmiersprache würde dies plattformübergreifend tun.

Michael
quelle