Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Help simplifying a Makefile for multiple executables

Tags:

c++

makefile

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
like image 459
mpenkov Avatar asked Jan 12 '11 05:01

mpenkov


1 Answers

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.)

like image 98
Daniel Gallagher Avatar answered Sep 23 '22 15:09

Daniel Gallagher