Hugues
Hugues

Reputation: 3170

GNU make: prepend a recursively expanded variable?

In a GNU Makefile, there are two types of variables:

# simple variable (immediate evaluation):
VAR := some_assignment

# recursively expanded variable (deferred evaluation):
VAR = some_assignment

One may append to a recursively expanded variable using:

  IMMEDIATE += DEFERRED or IMMEDIATE

For the append operator, '+=', the right-hand side is considered immediate if the variable was previously set as a simple variable (':=' or '::='), and deferred otherwise.

Is there any way to prepend to a recursively expanded variable?

My motivating example is to introduce a new library ahead of other ones in $(LDLIBS):

  # Unfortunately, newlib gets added to the end rather than the beginning.
  LDLIBS += $(if $(later_condition),newlib.a)

  # Unfortunately, the expression is evaluated now rather than being deferred.
  LDLIBS := $(if $(later_condition),newlib.a) $(LDLIBS)

Upvotes: 5

Views: 3049

Answers (2)

alecov
alecov

Reputation: 5172

Use this:

# Expand a variable, properly escaping '$' characters.
expand = $(if $(findstring simple,$(flavor $1)),$(subst $$,$$$$,$($1)),$(value $1))

# Prepend to a variable, preserving flavor.
prepend = \
    $(if $(findstring simple,$(flavor $1)), \
    $(eval $1 := $2 $(call expand,$1)), \
    $(eval $1 = $2 $(call expand,$1)))

x := 1 $$ 2
$(call prepend,x,X)
$(info $x)

x = 1 $$ 2
$(call prepend,x,X)
$(info $x)

$(value) is not good enough because, in an $(eval) context, $ characters will be parsed as variable references.

Upvotes: 3

Kuchara
Kuchara

Reputation: 715

I've came across the same problem. My solution is quite hacky, and makes use of $(value) and $(eval) functions.

What was important for me, it preserves flavor (recursive) of the variable, so that neither prepended variable, nor original variable is expanded during this action:

# Macro for prepending to a recursively expanded variable.
#
# Usage:
# * Prepending "text" to the VAR variable:
#       $(call prepend,VAR,text)
#
# * Prepending "a word list" to the VAR variable -- remember 
#   to add any trailing separator character (e.g. space):
#       $(call prepend,VAR,a word list )
#
# * Prepending OTHER_VAR variable to the VAR variable -- use $$ 
#   to defer any variable expansions:
#       $(call prepend,VAR,$$(OTHER_VAR))

define prepend
$(eval $(1) = $(2)$(value $(1)))
endef

# Macro for appending to a recursively expanded variable.
#
# Usage:
# * Appending "text" to the VAR variable:
#       $(call append,VAR,text)
#
# * Appending "a word list" to the VAR variable -- remember
#   to add any heading separator character (e.g. space):
#       $(call append,VAR, a word list)
# 
# * Appending OTHER_VAR variable to the VAR variable -- use $$ 
#   to defer any variable expansions:
#       $(call append,VAR,$$(OTHER_VAR))

define append
$(eval $(1) = $(value $(1))$(2))
endef

Quick testcase:

A = A
B = B
VAR = $(A)

$(info before: VAR=$(VAR) | value(VAR)=$(value VAR) | $(flavor VAR))
$(call prepend,VAR,$$(B))
$(info after : VAR=$(VAR) | value(VAR)=$(value VAR) | $(flavor VAR))

And its execution:

before: VAR=A | value(VAR)=$(A) | recursive
after : VAR=BA | value(VAR)=$(B)$(A) | recursive
make: *** No targets.  Stop.

Additional notes:

  • My problem was actually related to the fact that GNU make adds a whitespace separator when appending.
  • Hacky solution, but there is no native GNU make feature for such problem.

Upvotes: 5

Related Questions