Reputation: 4537
I have this makefile code:
$(DIRS):
@echo " MKDIR build/tmp/base/socket/$@"
$(Q)mkdir -p $@/
%.a.s:
@echo " CC build/tmp/base/socket/$@"
$(Q)$(CC) $(CFLAGS_A) -S $< -o $@
%.so.s:
@echo " CC build/tmp/base/socket/$@"
$(Q)$(CC) $(CFLAGS_SO) -S $< -o $@
%.o: %.s
@echo " AS build/tmp/base/socket/$@"
$(Q)$(AS) $< -o $@
tcp/client.a.s: $(TCP_CLIENT_SRC) $(TCP_CLIENT_INC)
tcp/client.so.s: $(TCP_CLIENT_SRC) $(TCP_CLIENT_INC)
tcp/server.a.s: $(TCP_SERVER_SRC) $(TCP_SERVER_INC)
tcp/server.so.s: $(TCP_SERVER_SRC) $(TCP_SERVER_INC)
I'd like to add a | tcp
in the prerequisites of all targets that have a leading tcp/
in their name, but I'd like to be able to do it in one line. I wouldn't want to append that manually to every line that needs it.
I thought of adding this new rule:
tcp/%.s: | tcp
but it isn't doing anything.
I also thought of the more generic, which would be nicer, but same results:
%.s: | $(@D)
How should I write that?
A workaround would be to call mkdir every time (include it in both %.a.s and %.so.s rules), but that would add unnecessary calls to mkdir, wouldn't it?
Upvotes: 0
Views: 88
Reputation: 4537
This answer is only to show a working Makefile implementing @bobbogo 's answer.
This Makefile is a leaf of a Makefile tree, so all variables not defined here are exported by upper Makefiles.
Makefile
:
#! /usr/bin/make -f
################################################################################
# *AUTHOR*
# FULL NAME "Alejandro Colomar Andrés"
################################################################################
################################################################################
DIRS = \
$(CURDIR)/tcp
OBJ = \
$(CURDIR)/tcp/client.o \
$(CURDIR)/tcp/server.o \
$(CURDIR)/foo.o
SRC = \
$(SRC_DIR)/base/socket/tcp/client.c \
$(SRC_DIR)/base/socket/tcp/server.c \
$(SRC_DIR)/base/socket/foo.c
DEP = $(OBJ:.o=.d)
BOTH_OBJ = $(subst .a.o,.a.o ,$(join $(OBJ:.o=.a.o),$(OBJ:.o=.so.o)))
BOTH_ASM = $(subst .a.s,.a.s ,$(join $(OBJ:.o=.a.s),$(OBJ:.o=.so.s)))
NEEDDIR = $(DEP) $(BOTH_ASM)
################################################################################
PHONY := all
all: $(BOTH_OBJ)
@:
$(DIRS): $(CURDIR)/%:
@echo " MKDIR build/tmp/base/socket/$*"
$(Q)mkdir -p $@
$(NEEDDIR): | $(DIRS)
$(CURDIR)/%.d: $(SRC_DIR)/base/socket/%.c
@echo " CC -M build/tmp/base/socket/$*.d"
$(Q)$(CC) $(CFLAGS_A) -MG -MT"$@" \
-MT"$(CURDIR)/$*.a.s" -MT"$(CURDIR)/$*.so.s" \
-M $< -MF $@
$(CURDIR)/%.a.s: $(SRC_DIR)/base/socket/%.c $(CURDIR)/%.d
@echo " CC build/tmp/base/socket/$*.a.s"
$(Q)$(CC) $(CFLAGS_A) -S $< -o $@
$(CURDIR)/%.so.s: $(SRC_DIR)/base/socket/%.c $(CURDIR)/%.d
@echo " CC build/tmp/base/socket/$*.so.s"
$(Q)$(CC) $(CFLAGS_SO) -S $< -o $@
$(CURDIR)/%.o: $(CURDIR)/%.s
@echo " AS build/tmp/base/socket/$*.o"
$(Q)$(AS) $< -o $@
include $(DEP)
PHONY += clean
clean:
$(Q)rm -rf *.o *.s *.d
################################################################################
# Declare the contents of the PHONY variable as phony.
.PHONY: $(PHONY)
################################################################################
######## End of file ###########################################################
################################################################################
output:
MKDIR build/tmp/base/socket/tcp
CC -M build/tmp/base/socket/foo.d
CC -M build/tmp/base/socket/tcp/server.d
CC -M build/tmp/base/socket/tcp/client.d
CC build/tmp/base/socket/tcp/client.a.s
AS build/tmp/base/socket/tcp/client.a.o
CC build/tmp/base/socket/tcp/client.so.s
AS build/tmp/base/socket/tcp/client.so.o
CC build/tmp/base/socket/tcp/server.a.s
AS build/tmp/base/socket/tcp/server.a.o
CC build/tmp/base/socket/tcp/server.so.s
AS build/tmp/base/socket/tcp/server.so.o
CC build/tmp/base/socket/foo.a.s
AS build/tmp/base/socket/foo.a.o
CC build/tmp/base/socket/foo.so.s
AS build/tmp/base/socket/foo.so.o
Upvotes: 0
Reputation: 15503
I am not a fan of pattern rules. They are too arbitrary for my tastes. (What actually happens depends on what files you may have lying around on your hard disk.)
You cannot just add a prerequisite to a given set of targets using a pattern rule
Well you can if you use static pattern rules. This is a much nicer idiom. Here we prefix a pattern rule with the actual list of sources you want the pattern rule to apply to. This is good where you can describe dependencies using make's noddy pattern matching.
A sketch:
%.a: ; date >$@ # Pattern rule
tcp: ; mkdir -p $@ # Explicit rule
tcp/a.a: tcp/%.a: | tcp ; # Static pattern rule!
.PHONY: all
all: tcp/a.a
all: c.a
all: dir/b.a
all: ; : $@ Success
And we have:
$ make all
mkdir -p tcp
date >tcp/a.a
date >c.a
date >dir/b.a
/bin/sh: dir/b.a: No such file or directory
make: *** [Makefile:3: dir/b.a] Error 1
Here we have told make that before it builds (i.e., "runs the recipe for") tcp/a.a
, it must first build tcp
. That works. We didn't tell make about the directory for dir/b.a
, so that failed. Note that the .a
file's recipe is still in an ordinary pattern rule. This is just by way of exposition. I would definitely change this.
Yeah, in this case the pattern rule for tcp/
is over-the-top. Consider though that before you create tcp/a.a
, you might first need to create a auto/a.src
(say).
tcp/a.a: tcp/%.a: auto/%.src | tcp ; # Static pattern rule!
Easily extensible.
targets := tcp/a.a tcp/b.a tcp/c.a
${targets}: tcp/%.a: auto/%.src | tcp ; # Static pattern rule!
[By the way, in your original makefile, your archive and shared object should depend on the .o
files, not the source (???)]
Upvotes: 1
Reputation: 101051
You cannot just add a prerequisite to a given set of targets using a pattern rule. That's not how pattern rules work: they are rules: they must have a recipe associated with them. A pattern rule without a recipe actually deletes that pattern rule (see Canceling Implicit Rules).
You can either create two sets of pattern rules, one for all targets and a second one for just targets that start with tcp/
that have an extra prerequisite, but you have to write the entire pattern rule twice, including a recipe, not just the pattern line.
Or just put the mkdir
into the recipe. A mkdir
on a directory that already exists won't even be noticeable.
Upvotes: 1