8

I have common code (e.g. hello.cpp) that is used by multiple executables. I'm using a single Makefile to build it all:

EXE=app1.out app2.out
SRC=hello.cpp
OBJ=$(SRC:.cpp=.o)
SRC_MAIN=app1.cpp app2.cpp
OBJ_MAIN=$(SRC_MAIN:.cpp=.o)
all: $(EXE)    
app1.out: app1.o $(OBJ)
    g++ $< $(OBJ) -o $@    
app2.out: app2.o $(OBJ)
    g++ $< $(OBJ) -o $@    
.cpp.o:
    g++ -c $< -o $@    
clean:
    rm -f $(EXE) $(OBJ) $(OBJ_MAIN)

I'm not very happy about having a separate target for each executable -- the targets are essentially the same. Is there any way to do this with one target for all executables? I was hoping that something like this would work:

EXE=app1.out app2.out
SRC=hello.cpp
OBJ=$(SRC:.cpp=.o)
SRC_MAIN=app1.cpp app2.cpp
OBJ_MAIN=$(SRC_MAIN:.cpp=.o)
all: $(EXE)
.o.out: $(OBJ)
    g++ $< $(OBJ) -o $@
.cpp.o:
    g++ -c $< -o $@
clean:
    rm -f $(EXE) $(OBJ) $(OBJ_MAIN)

But I get a linking error:

misha@misha-desktop:~/cpp/stack$ make -f Makefile2
g++ -c app1.cpp -o app1.o
g++ app1.o hello.o -o app1.out
g++: hello.o: No such file or directory
make: *** [app1.out] Error 1
rm app1.o

For some reason it tries to build app1.out without building its dependency hello.o. Can anyone explain why this doesn't work, and suggest something that does?

Here's the rest of the dummy code, just in case.

app1.cpp:

#include "hello.h"   
int
main(void)
{
    print_hello();
}

app2.cpp:

#include "hello.h"    
int
main(void)
{
    for (int i = 0; i < 4; ++i)
        print_hello();
    return 0;
}

hello.cpp:

#include "hello.h"    
#include <stdio.h>    
void
print_hello()
{
    printf("hello world!\n");
}

hello.h:

#ifndef HELLO_H
#define HELLO_H
void
print_hello();
#endif
mu is too short
  • 426,620
  • 70
  • 833
  • 800
mpenkov
  • 21,621
  • 10
  • 84
  • 126

1 Answers1

4

The problem appears to be that you are using old-style suffix rules. From the make info:

Suffix rules cannot have any prerequisites of their own. If they have any, they are treated as normal files with funny names, not as suffix rules. Thus, the rule:

  .c.o: foo.h
          $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<

tells how to make the file '.c.o' from the prerequisite file 'foo.h', and is not at all like the pattern rule:

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

which tells how to make '.o' files from '.c' files, and makes all '.o' files using this pattern rule also depend on 'foo.h'.

The solution is to use new-style pattern rules:

%.out: %.o $(OBJ)
    g++ $< $(OBJ) -o $@
%.o: %.cpp
    g++ -c $< -o $@

(Also note that you don't need to define a .cpp to .o rule; make has a sensible default.)

Daniel Gallagher
  • 6,915
  • 25
  • 31
  • Thanks for your answer. I use the .cpp to .o rule to provide custom `CPPFLAGS` to the compiler. I didn't show them in the sample code because I was keeping things simple. Will `make` defaults still include the "default" variable names (e.g. `CFLAGS`, `CPPFLAGS`, `LDFLAGS`, etc)? – mpenkov Jan 12 '11 at 07:47
  • 1
    Yes, but `CPPFLAGS` is for the C pre-processor. `CXXFLAGS` is for C++ flags. – Daniel Gallagher Jan 12 '11 at 07:48