Hoe voer ik rekenkunde uit in een makefile?

Is het mogelijk om bepaalde bewerkingen uit te voeren op variabelen in een makefile?
Bijvoorbeeld het definiëren van

JPI=4
JPJ=2

is het mogelijk om in dezelfde makefile een variabele JPIJte definiëren die gelijk is aan de uitgebreide waarde van $(JPI)*$(JPJ)?


Antwoord 1, autoriteit 100%

Met behulp van Bash rekenkundige uitbreiding:

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

De eerste regel is om in plaats daarvan de Bash-shell te kiezen van de standaard (sh). Doorgaans ondersteunt sh geen rekenkundige uitbreiding. In Ubuntu wordt /bin/sh echter geleverd door Dash, dat deze functie ondersteunt. Dus die regel kan worden overgeslagen.

Het dubbele dollartekenis omdat we de uitbreiding die door de schaal moet worden gedaan. Opmerking: de JPI- en JPJ-variabelen worden eerst uitgebreid met make, daarna wordt de uitdrukking als volgt aan bash doorgegeven:

$(( 4 * 2 ))

Antwoord 2, autoriteit 42%

Als je GNU makegebruikt en bcop je systeem hebt geïnstalleerd, kun je zoiets als dit gebruiken:

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

Antwoord 3, autoriteit 42%

Antwoord van @mrkj is geweldig, maar zoals @Daniel vermeldt, hebben niet alle systemen bc(ik heb het bijvoorbeeld niet op MSys).

Ik heb de twee volgende methoden gevonden, beide met behulp van shell: $$(( … ))en expr ...

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))

Merk op dat wanneer u exprgebruikt, u zalspaties rond de +plaatst, anders wordt 4+2. Dit is niet vereist bij gebruik van $$.

.

Als je bcbeschikbaar hebt, kun je daar zeker mee akkoord gaan. Ik vond de volgende pagina erg interessant: http://www.humbug.in/2010/makefile-tricks-arithmetic-addition-subtraction-multiplication-division-modulo-comparison/


Antwoord 4, autoriteit 29%

Het is onhandig (of briljant, afhankelijk van je perspectief), maar je kunt direct rekenen in GNU make. Zie GNU Make-functies leren met rekenkunde. Houd er echter rekening mee dat deze methode niet goed schaalt. Het zal geweldig werken voor kleine getallen, zoals je in je vraag hebt laten zien, maar het werkt niet goed als je werkt met getallen met een grote omvang (groter dan 10.000.000).


Antwoord 5, autoriteit 16%

In GNU Make met Guile-ondersteuning ( dwz sinds versie 4.0) is het gemakkelijk om de taal van het schema te gebruiken voor rekenkundige of andere berekeningen. Het wordt gedaan zonder een subshell of onderliggend proces te maken.

Een voorbeeld

JP-I := 4
JP-J := 2
JP-IJ := $(guile (* $(JP-I) $(JP-J) ))
$(info JP-IJ = $(JP-IJ) )
# prints: JP-IJ = 8

Zie ook de handleiding voor Guile Rekenkundige functies.

Een mogelijke cheque voor Guile:

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

Antwoord 6, autoriteit 8%

De GNU Make Standard Librarybiedt rekenkundige functies voor gehele getallen.

include gmsl
JPI = 4
JPJ = 2
JPIJ = $(call plus,$(JPI),$(JPJ))

Antwoord 7

Met makeppis het veel gemakkelijker. U krijgt direct toegang tot de onderliggende Perl-interpreter. In dit geval voert de makeperl-functie een variabele expansie uit voordat deze wordt geëvalueerd als Perl, de perl-functie OTOH zou alleen evalueren:

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

U kunt het ingebouwde &echo-commando buiten een regel als statement gebruiken.


Antwoord 8

Om een ​​laat antwoord aan de pool toe te voegen: De GNUmake-tabeltoolkitbevat veel rekenkundige functies. Je kunt optellen, aftrekken, vermenigvuldigen, delen, de modulus nemen in grondtal 8,10 en 16. Ook zijn er de gebruikelijke binaire bewerkingen and, or, xoren not. Nummers kunnen rond de 60 cijfers zijn, maar u kunt dit aanpassen als u meer nodig heeft. De code is pure GNUmake-syntaxis en daarom overdraagbaar tussen Windows en Unix, in tegenstelling tot shell-scripts – voor het geval je nummercrunch wilt, zijn er natuurlijk betere oplossingen 😉 natuurlijk.

Hier is een voorbeeld:

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)))

Uitvoer:

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

Other episodes