Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Makefile string functions be nested?

I'm attempting to do some string manipulation in a Makefile using the string functions that Make offers. I want to do two conversions on my strings, I have a variable that lists source files similar to:

C_SRCS += \
./src/foo.c \
./src/bar.c \
...

I want to take this string and convert it in a new variable holding all the object files. The Objects will be stored in a different directory, and obvious will have a .o extension instead of the .c. Effectively they should change from:

./src/<file>.c

to

./artifacts/src/<file>.o

I can do this with two rules like:

OBJS1 := $(C_SRCS:%.c=%.o)
OBJS = $(subst ./,./artifacts/,$(OBJS1))

that will work fine, but I was hoping to combine these two rules and remove the intermediate variable. I tried:

OBJS = $($(subst ./,./artifacts/,$(C_SRCS)):%.c=%.o)

and that just left OBJS empty, I thought maybe it would be better if I used two of the exact same function type so I tried:

OBJS = $(subst %.c,%.o,$(subst ./,./artifacts/,$(C_SRCS)))

and that executed the nested rule only and OBJS was set to ./artifacts/src/foo.c ./artifacts/src/bar.c ...

I started reading through some Make documentation, but I can't find anything about nesting string functions. Is it possible to nest string functions in Makefiles? If so what am I doing wrong here?

like image 800
Mike Avatar asked Mar 27 '26 13:03

Mike


2 Answers

Yes, you can nest string functions.

You cannot use the shorthand :X=Y notation on the result of a function though.

So when you combined OBJS1 := $(C_SRCS:%.c=%.o) and OBJS = $(subst ./,./artifacts/,$(OBJS1)) you didn't do that correctly (or the obvious way) you did something else. You wrote OBJS = $($(subst ./,./artifacts/,$(C_SRCS)):%.c=%.o) when the obvious (and correct) nesting would have been OBJS = $(subst ./,./artifacts/,$(C_SRCS:%.c=%.o)). (Maybe that was a typo I'm not sure).

The :X=Y shorthand is a shorthand for patsubst (an automatically % prefixed shorthand) not subst which is why your line OBJS = $(subst %.c,%.o,$(subst ./,./artifacts/,$(C_SRCS))) didn't work (consider otherwise that $(C_SRCS:.c=.o) would happen in more places than just the end of the values).

See below for working versions.

C_SRCS += \
          ./src/foo.c \
          ./src/bar.c

pv = $(warning $1: $($1))
$(call pv,C_SRCS)

$(warning RAW: $(subst ./,./artifacts/,$(C_SRCS:%.c=%.o)))

OBJS = $(patsubst %.c,%.o,$(subst ./,./artifacts/,$(C_SRCS)))
$(call pv,OBJS)
like image 160
Etan Reisner Avatar answered Mar 29 '26 06:03

Etan Reisner


You're doing it the wrong way around. Just "expand the macro" and replace $(OBJS1) in $(OBJS):

OBJS1 := $(C_SRCS:%.c=%.o)
OBJS = $(subst ./,./artifacts/,$(OBJS1))

becomes:

OBJS = $(subst ./,./artifacts/,$(C_SRCS:%.c=%.o))
like image 38
xbug Avatar answered Mar 29 '26 05:03

xbug