2011-02-10 1 views
1

J'ai par exemple. une liste de fichiers-source affectée à une variable au sein de makefile et souhaite à comprendre au moment de la construction, s'il y a des entrées répertoriées deux fois ce qui pourrait troubler le processus de construction et son résultat:Récupération des entrées redondantes des éléments listés contenus dans les variables make

Exemple:

ListofSource = ./a/hello.c ./b/sys.c ./c/input.c ./d/hello.c 

Comment est-il possible d'analyser/ListofSource filtre récupération d'une liste

DuplicateSources = ./a/hello.c ./d/hello.c 

Fonction $ (liste de tri) trie une liste et supprime les entrées redondantes, j'ai besoin le comportement opposé. Existe-t-il des fonctionnalités de création qui pourraient être appliquées?

Répondre

0

Si vous êtes obsédé par Makefile bonne tenue, vous pouvez exiger que la liste soit pour faire quelque chose et triée comme:

ifneq ($(LIST),$(sort $(LIST))) 
$(error $$(LIST) contains duplicates) 
endif 
+0

Échec lorsque $ {LIST} n'est pas trié, mais sans doublons. Je suggère que vous deviez comparer la sortie de '$ (mots ...)': 'ifneq ($ (mots $ {LIST}), $ (mots $ (trier $ {LIST}))) ...'. (Oh, et votre test est à l'envers.) – bobbogo

+0

@bobbogo: Vous avez raison de dire que le test est mauvais, mais quelle partie de "vous pourriez exiger que la liste soit dans l'ordre"? ? L'utilisation de '$ (words)' n'est pas une mauvaise idée, mais vous n'utilisez pas '$ {}' pour développer des variables dans 'make'. –

+1

Oh oui vous faites! Je réserve habituellement '$()' pour les fonctions, et '$ {}' pour les variables utilisateur (trop de perl methinks). Améliore la lisibilité à mon humble avis. Vous avez raison sur le libellé. Dans la mesure où la liste doit être triée, tout en conservant les doublons, ce serait une question en soi! – bobbogo

0

Utilisez $(shell), par exemple

DuplicateSources = $(shell perl -e '++$c{$_} for @ARGV; print join(" ",grep{$c{$_}>1} sort keys %c),"\n"' $(ListofSource)) 

devrait fonctionner.

+0

Si vous utilisez '$ (shell)', utilisez ': =' au lieu de '=', pour forcer l'expansion immédiate. Vous ne voulez pas appeler perl à chaque fois que $ (DuplicateSources) 'est référencé. –

+0

Bon point, j'y ai pensé mais je ne voulais pas expliquer la différence :) – reinierpost

0

$(shell...) n'est pas recommandé lorsque vous pouvez tout faire dans la fabrication.

list := a/1 b/2 c/3 a/1 
duplicates := $(foreach v,$(sort ${list}),$(if $(filter-out 1,$(words $(filter $v,${list}))),$v)) 

(Naturellement, cela peut être nettoyé un peu.) De telles expressions sont mieux lues à partir de l'intérieur vers l'extérieur.

  • $v est défini sur chaque élément de la liste à tour de rôle. Pas de doublons ici que nous utilisons $(sort...)
  • $(filter $v,${list}) renvoie tous les éléments correspondant à $v. Généralement, il y aura exactement une valeur de retour, mais dans cet exemple, lorsque $v est a/1, nous obtenons deux valeurs (identiques).
  • Ensuite, nous comptons les mots dans le précédent. Généralement $(words...) renverra 1, ou un nombre plus élevé dans le cas de doublons.
  • Nous ne sommes pas intéressés lorsque $(words...) renvoie 1, donc nous $(filter-out...) ces cas.
  • Tout ce qui reste est un doublon! Donc, en utilisant $(if...), nous retournons $v dans ce cas.

Il existe d'autres façons d'utiliser $(eval...) qui vous offre de véritables opportunités de programmation.

Questions connexes