38

Suppose I am working on a makefile and I have the following variable declaration at the top:

FILES = file1.cpp file2.cpp file3.cpp

Now suppose I want to compile each of those with a special command without specifying each target like this:

file1.o : file1.cpp
    custom_command file1.cpp
file2.o : file2.cpp
    custom_command file2.cpp
file3.o : file3.cpp
    custom_command file3.cpp

Is there a better way to do this using the $(FILES) variable I declared above?

Something like:

$(FILES:.cpp=.o) : $(FILES)
    custom_command $(FILES)

...only it needs to do this for each file in the $(FILES) variable.

Nathan Osman
  • 71,149
  • 71
  • 256
  • 361

3 Answers3

62

Yes. There are what are known as pattern rules. An example is the easiest to understand:

%.o: %.cpp
       $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

(remember that Makefiles require tabs). This rule describes how to make an object file from a cpp file.

If you do not want such a broad rule, you can use what are called static patterns:

objects = file1.o file2.o file3.o

all: $(objects)

$(objects): %.o: %.cpp
        $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

Here's the section on static pattern rules and pattern rules in the GNU Make manual.

Chris
  • 3,000
  • 26
  • 43
12

You can do that, as per the following:

SRCS=a.c b.c
OBJS=$(SRCS:.c=.o)

$(OBJS): $(SRCS)
        cc -c -o a.o a.c
        cc -c -o b.o b.c

but you have to remember that the dependencies are complete - it assumes that a.o depends on b.c as well which is probably not the case.

What you're probably after is a single rule on how to turn one file type into another:

SRCS=a.c b.c
OBJS=$(SRCS:.c=.o)

all: $(OBJS)

.c.o:
        gcc -c -o $@ $<

.c.o is such a rule which states what commands to run to turn a .c file into a .o file. In the actual command, $@ is replaced with the specific target and $< is replaced with the name of the first prerequisite.

There are many other automatic variables you can use, look them up with info make or look for a good book on make if you don't have the info stuff available.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Ya, that's pretty much what I'm trying to do. – Nathan Osman Dec 01 '10 at 03:07
  • Another way to specify dependencies exactly is to use [secondary expansion](https://www.gnu.org/software/make/manual/html_node/Secondary-Expansion.html) of the prerequisites (GNU Make specific feature). – ruvim Jan 14 '16 at 13:48
  • FYI- for anyone looking for documentation - the `.c.o` rule is called a [suffix rule](https://www.gnu.org/software/make/manual/html_node/Suffix-Rules.html) in GNU-make's parlance. GNU-make recommends using pattern rules over suffix rules. – user650654 Aug 31 '19 at 03:23
1
SRCS = a.c b.c
OBJS = $(SRCS:.c=.o)

.c.o:
        ${CC} ${CFLAGS} -c -o $@ $<

Though $< isn't quite portable (IIRC, bsdmake has the meaning of $^ and $< exactly swapped to what gmake uses), this is the default recipe for .c.o that would be in effect in either implementation.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
user502515
  • 4,346
  • 24
  • 20