Ben Collins
Ben Collins

Reputation: 20686

Simplest way to reverse the order of strings in a make variable

Let's say you have a variable in a makefile fragment like the following:

MY_LIST=a b c d

How do I then reverse the order of that list? I need:

$(warning MY_LIST=${MY_LIST}) 

to show

MY_LIST=d c b a

Edit: the real problem is that

ld -r some_object.o ${MY_LIST}

produces an a.out with undefined symbols because the items in MY_LIST are actually archives, but in the wrong order. If the order of MY_LIST is reversed, it will link correctly (I think). If you know a smarter way to get the link order right, clue me in.

Upvotes: 16

Views: 6006

Answers (6)

Paweł Wójcik
Paweł Wójcik

Reputation: 342

GNU Make version 4.4 adds the new function $(let ...). The manual offers the following macro which can be used for reversing the order of words

reverse = $(let first rest,$1,\
            $(if $(rest),$(call reverse,$(rest)) )$(first))
all: ; @echo $(call reverse,d c b a)

Upvotes: 1

studog
studog

Reputation: 1088

An improvement to the GNU make solution:

reverse = $(if $(wordlist 2,2,$(1)),$(call reverse,$(wordlist 2,$(words $(1)),$(1))) $(firstword $(1)),$(1))

  • better stopping condition, original uses the empty string wasting a function call
  • doesn't add a leading space to the reversed list, unlike the original

Upvotes: 7

Tripp Lilley
Tripp Lilley

Reputation: 1663

Playing off of both Ben Collins' and elmarco's answers, here's a punt to bash which handles whitespace "properly"1

reverse = $(shell printf "%s\n" $(strip $1) | tac)

which does the right thing, thanks to $(shell) automatically cleaning whitespace and printf automatically formatting each word in its arg list:

$(info [ $(call reverse,  one two   three four  ) ] )

yields:

[ four three two one ]

1...according to my limited test case (i.e., the $(info ...) line, above).

Upvotes: 2

simona
simona

Reputation:

A solution in pure GNU make:

default: all

foo = please reverse me

reverse = $(if $(1),$(call reverse,$(wordlist 2,$(words $(1)),$(1)))) $(firstword $(1))

all : @echo $(call reverse,$(foo))

Gives:

$ make

me reverse please

Upvotes: 25

ajax
ajax

Reputation: 476

You can also define search groups with ld:

ld -r foo.o -( a.a b.a c.a -)

Will iterate through a.a, b.a, and c.a until no new unresolved symbols can be satisfied by any object in the group.

If you're using gnu ld, you can also do:

ld -r -o foo.o --whole-archive bar.a

Which is slightly stronger, in that it will include every object from bar.a regardless of whether it satisfies an unresolved symbol from foo.o.

Upvotes: 5

Ben Collins
Ben Collins

Reputation: 20686

Doh! I could have just used a shell script-let:

(for d in ${MY_LIST}; do echo $$d; done) | tac

Upvotes: 6

Related Questions