web-dev-qa-db-fra.com

Comment puis-je effectuer du calcul dans un fichier makefile?

Est-il possible d'effectuer des opérations sur des variables dans un fichier makefile? Par exemple, définir

JPI=4
JPJ=2

Est-il possible de définir dans le même fichier make une variable JPIJ égale à la valeur étendue de $ (JPI) * $ (JPJ)?

35
malaboca

Utilisation de Développement arithmétique Bash :

Shell=/bin/bash
JPI=4
JPJ=2
all:
    echo $$(( $(JPI) * $(JPJ) ))

La première ligne consiste à choisissez le shell Bash au lieu de la valeur par défaut (sh) . En règle générale, sh ne supporte pas l'expansion arithmétique. Cependant, dans Ubuntu,/bin/sh est fourni par Dash, qui prend en charge cette fonctionnalité . Donc, cette ligne pourrait être ignorée.

Le double signe dollar est parce que nous voulons l'expansion doit être effectuée par Shell . Remarque: les variables JPI et JPJ sont d'abord développées par make, puis l'expression est transmise à bash comme ceci:

$(( 4 * 2 ))
27
Dominic

Si vous utilisez GNU make et que vous avez bc installé sur votre système, vous pouvez utiliser quelque chose comme ceci:

JPI=4
JPJ=2
FOO=$(Shell echo $(JPI)\*$(JPJ) | bc)
all:
  echo $(FOO)
12
mrkj

C'est maladroit (ou brillant, selon votre point de vue), mais vous pouvez faire de l'arithmétique directement dans GNU make. Voir Apprentissage GNU Création de fonctions avec de l'arithmétique . Sachez cependant que cette méthode ne s’adapte pas bien. Comme vous l'avez montré dans votre question, cela fonctionnera à merveille pour les petits nombres, mais cela ne va pas si vous travaillez avec des nombres de grande ampleur (supérieurs à 10 000 000).

10
Eric Melski

La réponse de @mrkj est excellente, mais comme @Daniel le mentionne, tous les systèmes n'ont pas bc (par exemple, je ne l'ai pas sous MSys).

J'ai trouvé les deux méthodes suivantes, toutes deux utilisant Shell: $$ ((...)) etexpr ...

JPI=4
JPJ=2

#With Double-dollar
JPIJ_1 = $(Shell echo $$(( $(JPI) + $(JPJ) )))

#With 'expr'
JPIJ_2 = $(Shell expr $(JPI) + $(JPJ) )

$(info Sum with Double-$$: $(JPIJ_1))
$(info Sum with 'expr': $(JPIJ_2))

Notez que lorsque vous utilisez expr, vous devez mettez des espaces autour du + ou il retournera 4+2. Ceci n'est pas requis lorsque vous utilisez$$.

.

Lorsque vous aurez bc disponible, vous pourrez certainement l’utiliser. J'ai trouvé la page suivante très intéressante: http://www.humbug.in/2010/makefile-tricks-arithmetic-addition-subtraction-multiplication-division-modulo-comparison/

5
Jean-Francois T.

Le GNU Make Standard Library fournit des fonctions arithmétiques entières.

include gmsl

JPI = 4
JPJ = 2

JPIJ = $(call plus,$(JPI),$(JPJ))
4
Matthew Simoneau

Dans GNU Make avec Guile support (c’est-à-dire depuis la version 4.0), il est facile d’appeler le langage Scheme pour des calculs arithmétiques ou autres. Cela se fait sans créer de sous-shell ni de processus enfant.

Un exemple

JP-I := 4
JP-J := 2
JP-IJ := $(guile (* $(JP-I) $(JP-J) ))

$(info JP-IJ = $(JP-IJ) )
# prints: JP-IJ = 8

Voir aussi le manuel pour Guile Fonctions arithmétiques .

Vérification possible pour Guile:

ifeq (,$(filter guile,$(.FEATURES)))
  $(error Your Make version $(MAKE_VERSION) is not built with support for Guile)
endif
2
ruvim

Pour ajouter une réponse tardive au pool: La boîte à outils de la table GNUmake présente de nombreuses fonctions arithmétiques. Vous pouvez ajouter, soustraire, multiplier, diviser, prendre le module en base 8, 10 et 16. Il existe également les opérations binaires habituelles and, or, xor et not. Les numéros peuvent comporter environ 60 chiffres, mais vous pouvez l’adapter si vous avez besoin de plus. Le code est une pure syntaxe GNUmake et est donc portable entre Windows et Unix, contrairement aux scripts Shell - au cas où vous voudriez effectuer des calculs complexes, il pourrait y avoir de meilleures solutions;) bien sûr.

Voici un exemple:

include gmtt/gmtt.mk

NUMBER_A := -12392834798732429827442389
NUMBER_B := 984398723982791273498234
$(info $(call add,$(NUMBER_A),$(NUMBER_B)))
$(info $(call sub,$(NUMBER_A),$(NUMBER_B)))
$(info $(call mul,$(NUMBER_A),$(NUMBER_B)))
$(info $(call div,$(NUMBER_A),$(NUMBER_B)))
$(info $(call mod,$(NUMBER_A),$(NUMBER_B)))

Sortie:

$ make
-11408436074749638553944155
-13377233522715221100940623
-12199490762401735834920873237276176262117128241026
-12
-580050110938934545463581
0
Vroomfondel

Avec makepp c'est beaucoup plus facile. Vous obtenez un accès direct à l'interpréteur Perl sous-jacent. Dans ce cas, la fonction makeperl effectue un développement variable avant d'être évaluée en tant que Perl, la fonction Perl OTOH évaluera uniquement:

JPI=4
JPJ=2
JPIJ = $(makeperl $(JPI)*$(JPJ))
&echo result: $(JPIJ)

Vous pouvez utiliser la commande builtin & echo en dehors d'une règle en tant qu'instruction.

0
Daniel