Reputation: 4737
Say I have a list of source files and each are to be compiled to separate binaries:
SRCS = abcd.c efgh.c ijkl.c
And I want output files in separate subdirectories based on the file names like this:
I'm thinking a static pattern rule is the way to go. The pseudo-make-rule can be something like:
$(TARGETS): build/%/%: %.c
# stuff ...
I started by making a list of the subdirectories based on the filenames:
DIRS = $(SRCS:%.c=build/%)
So now we have DIRS = build/abcd build/efgh build/ijkl. I thought I can make the list of targets now with something like:
BLDS = $(DIRS:%=%/$(basename %))
But of course this doesn't work since the wildcard can not be used multiple times within a pattern. Therefore I'm now stuck at BLDS = build/abcd/% build/efgh/% build/ijkl/%.
Obviously I'm totally going about this the wrong way. How would you go about this?
For now I'm writing each rule explicitly, which is starting to get a bit tedious:
compile = # command to do stuff
BD = build
all: $(BD)/abcd/abcd $(BD)/efgh/efgh $(BD)/ijkl/ijkl
$(BD)/abcd/abcd: abcd.c
$(call compile)
$(BD)/efgh/efgh: efgh.c
$(call compile)
$(BD)/ijkl/ijkl: ijkl.c
$(call compile)
clean:
rm -rf build/*
.PHONY: all
Upvotes: 2
Views: 1074
Reputation: 151441
I believe this does what you want:
SRCS:=abcd.c efgh.c ijkl.c
# We could fold NAMES into BLDS's definition if NAMES is not used elsewhere.
NAMES:=$(SRCS:%.c=%)
BLDS:=$(foreach name,$(NAMES),$(subst foo,$(name),build/foo/foo))
# We don't use DIRS below but the question had this variable.
DIRS:=$(dir $(BLDS))
TARGETS:=$(BLDS)
.PHONY: all
all: $(TARGETS)
.SECONDEXPANSION:
$(TARGETS): $$(notdir $$@).c
@echo Build $@ from $^
mkdir -p $(dir $@)
touch $@
There are two important changes. The first is to reorder how the variables are created, and use subst
, which allows replacing a matched string multiple times. The second is to use secondary expansion so that make builds rules for each of your targets. You initially a pattern with two %
, but the docs say:
A pattern rule looks like an ordinary rule, except that its target contains the character `%' (exactly one of them).
(Emphasis added.)
I've tested the above with fake files abcd.c
efgh.c
and ijkl.c
and get the following output:
$ make
Build build/abcd/abcd from abcd.c
mkdir -p build/abcd/
touch build/abcd/abcd
Build build/efgh/efgh from efgh.c
mkdir -p build/efgh/
touch build/efgh/efgh
Build build/ijkl/ijkl from ijkl.c
mkdir -p build/ijkl/
touch build/ijkl/ijkl
Upvotes: 3