wallyk
wallyk

Reputation: 57764

makefile rule to build multiple targets without intermediate file

I am stumped coming up with a makefile rule to have several executables where each depends on its respective source file. There is a library common to all and each program has a single source file: a.c compiled and linked with the library produces executable a, etc.

LIB_C_FILES = f1.c f2.c f3.c
LIB_H_FILES = f1.h f2.h f3.h
TARGETS = a b c
CFLAGS = -g -O0 -DDEBUG

.PHONY : all clean

.c.o:
    g++ -c $(CFLAGS) -o $@ $<

all:    $(TARGETS)

${TARGETS} : lib.a ${@:%=%.c}
        g++ $(CFLAGS) ${@:=.c} -o $@ lib.a

lib.a:  ${LIB_C_FILES:.c=.o}  $(LIB_H_FILES)
        ar r $@ $?

The library portion works fine. And when an executable does not exist, it also works fine. But when one of the standalone source files is modified it says make: Nothing to be done for 'all'.

I don't understand the proper way to make target a depend on source a.c individually in a list. What am I missing?

Upvotes: 0

Views: 1923

Answers (2)

bobbogo
bobbogo

Reputation: 15483

Just for completeness: you can do what you want with plain old static pattern rules, so long as you can match all of ${TARGETS} with make's (noddy) pattern matching.

${TARGETS}: %: %.C lib.a
    g++ ${CFLAGS} $< -o $@ lib.a

lib.a: ...
    ar ...

A tad more readable, and perhaps more compatible than .SECONDEXPANSION?

Upvotes: 3

Eric Miller
Eric Miller

Reputation: 2021

First, I assume fio.a was a typo (you probably meant lib.a).

Second, I think the tricky part is your ${@:%=%.c} prerequisite. AFAIK, $@ can't be used this way.

I think you can get the behavior you're looking for using .SECONDEXPANSION though.

Try:

.SECONDEXPANSION:
${TARGETS} : lib.a $$(patsubst %,%.c,$$@)

There may be an old-style substitution way to do this, but I find the patsubst line to be more readable than ${@:%=%.c}.

(I should add that this applies to Gnu make 3.82. YMMV with older versions of Gnu make, or [heaven forbid] non-Gnu versions of make).

Upvotes: 2

Related Questions