comment un makefile peut-il détecter si une commande est disponible sur la machine locale?

11

J'ai commencé à utiliser le mode org pour planifier mes tâches dans le système de style GTD . En plaçant tous les fichiers org dans un répertoire d'un dossier Dropbox , j'exécute emacs pour éditer / gérer ces fichiers à partir de trois machines locales différentes: Cygwin, Mac OS X et Debian. Comme j'utilise également MobileOrg pour accéder à ces fichiers org depuis mon iPad, un checksums.datfichier doit être tenu à jour lorsque des modifications sont apportées. Cela peut être fait en exécutant md5sum *.org > checksums.dat.

Le problème est qu'il existe trois commandes différentes pour la md5sumcommande: md5sum.exedans Cygwin, md5dans Mac OS X et md5sumdans Debian. La situation la plus idéale est un makefile, stocké dans un foder Dropbox, détecte quelle commande est disponible dans la machine actuelle et exécute cette commande pour effectuer l'opération de somme de contrôle md5.

Federico Magallanez
la source
gnuautotools
Kevin
1
@Kevin Cela ressemble à une exagération. Je ne veux pas installer un programme dans trois systèmes distincts. Dans chaque système, un dossier Dropbox est accessible en tant que répertoire local. Lorsque je lance make checksumpour générer des données de somme de contrôle sous un dossier Dropbox, je veux que le makefile utilise une commande appropriée après avoir détecté la commande de somme de contrôle disponible sur la machine actuelle.
Federico Magallanez
Si vous allez faire une quantité importante de scripts et que le projet est petit, je suggère Scons.
Faheem Mitha

Réponses:

7

Commandes possibles pour générer une somme de contrôle

Malheureusement, il n'y a pas d'utilitaire standard pour générer une somme de contrôle cryptographique. Il est un utilitaire standard pour générer un CRC: cksum; cela peut être suffisant pour détecter les changements dans un environnement non hostile.

Je recommanderais d'utiliser SHA1 plutôt que MD5. Il n'y a pas beaucoup de systèmes qui ont un utilitaire MD5 mais pas de SHA1, et si vous allez utiliser des sommes de contrôle cryptographiques, vous pourriez aussi bien utiliser un algorithme sans méthode connue pour trouver des collisions (en supposant que vous vérifiez également la taille).

OpenSSL est un outil qui n'est pas standard mais commun et qui peut calculer les résumés . Il est disponible pour Cygwin, Debian et OSX, mais ne fait malheureusement pas partie de l'installation par défaut sur OSX.

openssl dgst -sha1

Sur OSX 10.6, il y a un shasumutilitaire, qui est également présent sur Debian (il fait partie du perlpaquet) et je crois aussi sur Cygwin. Ceci est un script Perl. La plupart des systèmes Unix ont installé Perl, vous pouvez donc regrouper ce script avec votre makefile si vous craignez que ce script ne soit pas disponible partout.

Sélection de la bonne commande pour votre système

Ok, disons que vous ne pouvez vraiment pas trouver une commande qui fonctionne partout.

Dans la coquille

Utilisez la fonction typeintégrée pour voir si une commande est disponible.

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

Marque GNU

Vous pouvez utiliser la shellfonction pour exécuter un extrait de shell lorsque le makefile est chargé et stocker la sortie dans une variable.

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

Marque portable (POSIX)

Vous ne pouvez exécuter que des commandes shell dans la règle, de sorte que chaque règle qui calcule une somme de contrôle doit contenir le code de recherche. Vous pouvez mettre l'extrait de code dans une variable. N'oubliez pas que les lignes distinctes des règles sont évaluées indépendamment. Souvenez-vous également que les $signes qui doivent être passés au shell doivent être échappés $$.

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- arrête d'être méchant'
la source
J'ai dû utiliser l' -Poption de la typecommande pour que la méthode "GNU make" décrite ci-dessus fonctionne correctement, donc je me suis retrouvé avec sum := $(shell { type -P sha1sum || type -P sha1 || type -P shasum; } 2>/dev/null).
Sean
@Sean Merci pour le rapport de bogue. type -Pne fonctionne que si votre shell est bash, pas si c'est par exemple ksh ou dash (ce qui est le cas sur Ubuntu entre autres). Vous pouvez utiliser command -vpour la portabilité.
Gilles 'SO- arrête d'être méchant'
Il semble que vous soyez passé de l'utilisation typeà l'utilisation command. Les autres méthodes devraient-elles également être mises à jour?
Sean
@Sean Les autres méthodes sont très bien: typeest un moyen correct et portable pour tester la présence d'une commande, le problème avec cela est qu'il produit une sortie comme sha1sum is /usr/bin/sha1sumplutôt que juste le nom du programme. C'était le seul endroit où j'ai utilisé la sortie de typeplutôt que juste sa valeur de retour.
Gilles 'SO- arrête d'être méchant'
5

C'est un peu un hack, mais vous pouvez tester si chacun existe et les exécuter s'ils le font:

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

Je suis tout à fait certain que cygwin reconnaît les commandes (y compris md5sum) sans le .exe, mais incluez-le si vous le devez.

Kevin
la source
4
whichles valeurs de sortie ne sont pas portables. Utilisez à la typeplace (et vous voudrez probablement l'utiliser if; then; elifpour éviter d'avoir des problèmes car il y a plusieurs exécutables). whichet typene cherchez de toute façon que les exécutables, donc votre test avec -x est inutile.
Chris Down du
plus sur l'utilisation de "type": cmd = $ (pour cmd dans la barre foo md5 md5sum; tapez $ cmd> / dev / null 2> & 1 && echo $ cmd && break; done); $ cmd fichier1 fichier2 fichier3> md5.txt
michael
1

Soit les outils automatiques GNU (comme mentionné dans un commentaire), soit CMake est également une option.

Les autotools GNU sont l'approche la plus traditionnelle, mais (et peut-être seulement pour moi), je ne pense pas que les gens soient vraiment trop excités à l'idée de mettre en place un projet en les utilisant. Eh bien, c'est une courbe d'apprentissage, en tout cas. CMake est le plus récent enfant du bloc, et peut-être moins courant (et a toujours une courbe d'apprentissage). Il a sa propre syntaxe et génère des makefiles pour votre plateforme. CMake a le net avantage de ne pas être si peu centré sur x; il fonctionne également de manière fiable sur unix, windows et mac (par exemple, il peut générer des projets msvc, par exemple, au lieu de makefiles.)

Edit: et bien sûr, puisque des «makefiles» ont été suggérés, cette réponse va de pair avec cette présomption. Mais peut-être qu'un simple script python ou (halètement) un simple programme Java serait plus approprié pour cette tâche; le langage de script / programmation ferait la même chose sur toutes les plateformes.

Michael
la source