SU3
SU3

Reputation: 5387

Makefile: match multiple pattern rules

I have a makefile like this:

EXT = .cc
BLD = .build

all: bin/analyses/test

bin/analyses/test: $(BLD)/object.o

.SECONDEXPANSION:

$(DEPS): $(BLD)/%.d: src/%$(EXT) | $(BLD)/$$(dir %)
    $(CXX) $(CPPFLAGS) -MM -MT '$(@:.d=.o)' $< -MF $@

$(BLD)/%.o: | $(BLD)
    $(CXX) $(CXXFLAGS) -c $(filter %$(EXT),$^) -o $@

bin/%: $(BLD)/%.o | $$(dir bin/%)
    $(CXX) $(LDFLAGS) $(filter %.o,$^) -o $@ $(LDLIBS)

bin/%/ $(BLD)/%/:
    mkdir -p $@

If line 6 looks the way it is, then everything works. Both bin/analyses/test: and bin/%: rules are used. But if I change line 6 to

bin/analyses/%: $(BLD)/object.o

only the bin/%: rule gets picked up.

How can I make multiple pattern rules match for the same target?

Upvotes: 0

Views: 165

Answers (1)

Beta
Beta

Reputation: 99084

First, Make sometimes removes trailing slashes from targets, which can cause some confusion. In this case it takes your rule bin/%/ $(BLD)/%/: ..., which you clearly intended for directories, and uses it for files, at least sometimes. It is easy enough to do without an explicit rule for directories, by using mkdir -p in other rules.

Second, Make doesn't combine pattern rules the way it does ordinary rules. It finds one pattern rule and uses that. In a relatively simple case like this, we can write a rule that will do what we want:

all: bin/analyses/test

$(BLD)/%.o:
    mkdir -p $(dir $@)
    $(CXX) $(CXXFLAGS) -c $^ -o $@

bin/analyses/%: $(BLD)/analyses/%.o $(BLD)/object.o
    mkdir -p $(dir $@)
    $(CXX) $(LDFLAGS) $^ -o $@ $(LDLIBS)

bin/%: $(BLD)/%.o
    mkdir -p $(dir $@)
    $(CXX) $(LDFLAGS) $^ -o $@ $(LDLIBS)   

(There is some obvious redundancy in those last two rules which I don't see how to iron out without making the makefile less readable, but it works as intended.)

Upvotes: 1

Related Questions