scruffaluff
scruffaluff

Reputation: 365

Makefile For Loop Pattern Substitution

In the following makefile for loop, how can I edit the string, that the i variable represents, with a pattern substitution in the middle of the string? In my case, I wish to replace any / character in the string with a _ character.

for i in $(MODULES:%.cpp=%); do \
    g++ -c Sources/$$i.cpp -o Build/$$i.o; \
done

For example if MODULES = Directory/File.cpp then the inner line should expand to

g++ -c Sources/Directory/File.cpp -o Build/Directory_File.o

Upvotes: 0

Views: 772

Answers (1)

Renaud Pacalet
Renaud Pacalet

Reputation: 28965

This answer is valid only with GNU make and bash.

Simple bash substitution (${parameter/pattern/string}) in the context of a make recipe (double $):

for i in $(MODULES:%.cpp=%); do \
    g++ -c Sources/$$i.cpp -o Build/$${i//\//_}.o; \
done

Warning: this works only if the shell used by make is bash. So, add maybe a:

SHELL := bash

at the beginning of your Makefile.

Explanation:

  • ${i/X/_} expands as the value of variable i in which the first occurrence of X is replaced by _.
  • ${i//X/_} expands as the value of variable i in which all occurrences of X are replaced by _.
  • In your case X is the / character and it must be escaped (\/): ${i//\//_}.

Note that there is probably a less bash and more make way to do the same. Something like:

SRCS := $(shell find Sources -type f -name *.cpp)
OBJS :=

define OBJ_rule
obj := Build/$$(subst /,_,$$(patsubst Sources/%.cpp,%,$(1))).o
OBJS += $$(obj)
$$(obj): $(1)
    g++ -c $$< -o $$@
endef
$(foreach s,$(SRCS),$(eval $(call OBJ_rule,$(s))))

.PHONY: objs

objs: $(OBJS)

Which instantiates one rule per module and should do the same... with the significant advantage that, when you type make objs, only the outdated object files are rebuilt. But it's a bit more tricky.

Upvotes: 1

Related Questions