5

I need to extract the word before the last from $(MAKEFILE_LIST).

So far I could not come up with anything better than this kind of monstrosity:

LIST := a b c

LAST_WORD_INDEX = $(words $(LIST))
BEFORE_LAST := $(word $(shell echo $(LAST_WORD_INDEX) - 1 | bc),$(LIST))
$(info word before last is $(BEFORE_LAST))

When I run it:

word before last is b
make: *** No targets.  Stop.

The result is correct, but is there more elegant and sane way to achieve the same?

Roman Saveljev
  • 2,544
  • 1
  • 21
  • 20
  • possible duplicate of [Included Makefile's parent directory](http://stackoverflow.com/questions/24960054/included-makefiles-parent-directory) – Etan Reisner Sep 19 '14 at 13:19
  • Not a duplicate of the exact goal but my answer there has what you need (and I actually talk about `$(MAKEFILE_LIST)` in my answer. – Etan Reisner Sep 19 '14 at 13:20
  • @EtanReisner thank you for the GMSL pointer – Roman Saveljev Sep 19 '14 at 13:55
  • 1
    You could use `$(lastword $(filter-out $(lastword $(MAKEFILE_LIST)), $(MAKEFILE_LIST)))`. – Beta Sep 19 '14 at 23:10
  • 1
    @Beta -- Sorry, commenting on this a bit late -- if the last two entries in the list were identical, i.e. `a b c c`, then the `filter-out` would wipe out both `c`'s, and would incorrectly return `b`... – HardcoreHenry Jan 20 '21 at 14:39
  • @HardcoreHenry: You're right, good catch. – Beta Jan 20 '21 at 17:52

2 Answers2

5

$(words ${LIST}) will give you the index of the last-but-one word if you prepend an element to LIST.

BEFORE_LAST := $(word $(words ${LIST}),1st ${LIST})

Notice that 1st in there.

bobbogo
  • 14,989
  • 3
  • 48
  • 57
  • You put `$(words ${LIST})` an extra time in there. – HardcoreHenry Jan 18 '21 at 18:28
  • @HardcoreHenry Did you try it? That is correct. If _LIST_ has 4 words, we make it a 5 word list and take the 4th word `$(word 4,4,1st a b c d)`. Neat huh? – bobbogo Jan 19 '21 at 10:47
  • @HardcoreHenry No, I am wrong of course, I'm not using `$(wordlist)`. And _make_ is wrong too, nice one!. Looks like `$(word 4, …args…, list)` "works." It takes the word from the list it finds in its _last_ argument. Oh well. – bobbogo Jan 19 '21 at 10:53
  • So, after a little investigation, it looks like this would fail if there were exactly two entries in the list. Because `word` is a built-in that expects exactly two parameters, the second comma does not act as a parameter delimiter -- so `$(info word 1: $(word 1,1,a b c d))`, `1,a` is considered the first word. – HardcoreHenry Jan 19 '21 at 14:02
  • @HardcoreHenry Yes, again you are right about `$(word)` ignoring the second comma. However, my original formulation with the two calls to `$(words)` still works, even when `${LIST}` has zero or one word. The augmented list merely has something like `1,1st` as its new first item. I have edited the text. Thank you for noticing! – bobbogo Jan 20 '21 at 09:36
2

I ended up using GMSL library, which makes things quite a bit more coherent:

include gmsl-1.1.6/gmsl

$(lastword $(call chop,$(MAKEFILE_LIST)))
Roman Saveljev
  • 2,544
  • 1
  • 21
  • 20