tags:

views:

697

answers:

5

Hi all,

I have 4 '.cpp' files and 1 header files:

Tools.cpp
Code1.cpp
Code2.cpp
Code3.cpp

and Tools.hh

Now all Code1.cpp, Code2.cpp, Code3.cpp use functions stored in Tools.cpp.

Currently, what I do to compile all of them is using this simple shell script:

#!/bin/bash
echo "compiling Code1.cpp";
g++ Code1.cpp Tools.cpp -o Code1

echo "compiling Code2.cpp";
g++ Code2.cpp Tools.cpp -o Code2 

echo "compiling Code3.cpp";
g++ Code3.cpp Tools.cpp -o Code3

It all works fine.

Now I want to do that using a standard makefile. But why this doesnt' work:

CXX = g++

TOOLSRC = Tools.cpp Code1.cpp Code2.cpp \
Code3.cpp    

TOOLSINC = Tools.hh      

all: Code1 Code2 Code3

Code1: $(TOOLSRC) $(TOOLSINC) makefile
    $(CXX) $^ -o $@  

Code2: $(TOOLSRC) $(TOOLSINC) makefile
    $(CXX) $^ -o $@  

Code3: $(TOOLSRC) $(TOOLSINC) makefile
    $(CXX) $^ -o $@

The error I got is this:

ld: warning in makefile, file is not of required architecture
ld: duplicate symbol neighbors(std::vector<int, std::allocator<int> >&, int, int)in /var/folders/Yx/YxKmmyVPGpakdPL4St7X6++++TI/-Tmp-//ccQCrGHe.o and /var/folders/Yx/YxKmmyVPGpakdPL4St7X6++++TI/-Tmp-//ccreq9YU.o

collect2: ld returned 1 exit status
make: *** [FindNeighbours] Error 1

How can I correct the mistakes?

+2  A: 

Hm. Normally you'd specify dependencies on object files, with ".o" extensions. It might be that Make is being confused, since it has built-in rules for files of various types.

The error is because you're trying to link the makefile into the program, by passing $^ to the compiler.

unwind
Hi, what's the alternative to $^ then?
neversaint
You shouldn't need any, make should be able to deduce the build command by itself. Or do it as greyfade suggests, by not depending on the makefile.
unwind
+1  A: 

On the right hand side of a rule you should put only the files that are usefull.

Code1: Code1.cpp Tools.cpp
    $(CXX) $^ -o $@
Code1: Code2.cpp Tools.cpp
    $(CXX) $^ -o $@
Code3: Code3.cpp Tools.cpp
    $(CXX) $^ -o $@

While this solves your problem you should definitely read Grayfade’s answer on how to do things the "Right Way".

kmkaplan
This will make the compiler process tools.cpp more than once -- which is unnecessary. See Greyfade below for a nice explanation and Rberteig for an even shorter makefile.
nimrodm
+4  A: 

In short, $^ isn't what you want here. It evaluates to the "names of all the prerequisites, with spaces between them." In the problem Makefile, that causes all three targets to use almost identical command lines, that each look like

g++ Tools.cpp Code1.cpp Code2.cpp Code3.cpp Tools.hh makefile -o Code1

From the error message quoted, g++ has decided that makefile should be passed to the linker as if it were an object. It isn't. Without makefile on the line, you would still be compiling and linking all four of your source files, and quite likely leaving the linker to decide which of four main() functions to use.

You probably want to leverage the fact that make has a huge number of builtin rules for common cases. Compiling two source files and linking the result fits neatly into those common cases. Its untested, but the following should do all you want (assuming a recent build of gnu make, at least), and have the advantage of only compiling each object once.

all: Code1 Code2 Code3
Code1: Code1.o Tools.o
Code2: Code2.o Tools.o
Code3: Code3.o Tools.o

Code1.o Code2.o Code3.o Tools.o: Tools.hh

If you needed to set some compiler options you could add a definition for CXXFLAGS, traditionally near the top of the file.

RBerteig
and LDFLAGS to control the linking process. I never new GNU make had implicit rules for linking. Thanks for pointing that out.
nimrodm
Gnu make seems to be a union of every feature found in any version of make ever built. The manual is huge, but is worth reading at least once... I still learn things about it after over 20 years of using various versions of make on a wide array of systems.
RBerteig
+4  A: 

In these targets:

Code1: $(TOOLSRC) $(TOOLSINC) makefile
    $(CXX) $^ -o $@

The resulting command will be:

g++ Tools.cpp Code1.cpp Code2.cpp Code3.cpp Tools.hh makefile -o Code1

This is clearly not what you want. g++ is attempting to compile both the header file and the makefile and doesn't know what to do with the makefile. You're also declaring dependencies on all three of your main units for each unit. So if Code3.cpp changes, Code1 will require recompilation. This is also undesirable.

Try something like this instead:

CXX = g++

all: Code1 Code2 Code3

%.o: %.cpp
    $(CXX) $(CXXFLAGS) -c -o $@ $^

Code1: Code1.o Tools.o
    $(CXX) -o $@ $^

Code2: Code1.o Tools.o
    $(CXX) -o $@ $^

Code3: Code1.o Tools.o
    $(CXX) -o $@ $^
greyfade
A: 

I am no expert at makefiles, but this is how I usually do it, and it works well.

COMPILER = g++
CXXFLAGS = 
EXECUTABLE = code 

all: code

code: Code1.o Code2.o Code3.o Tools.o
  ${COMPILER} ${CXXFLAGS} -o ${EXECUTABLE} Code1.o Code2.o Code3.o Tools.o

Code1.o: Code1.cpp Tools.o
  ${COMPILER} ${CXXFLAGS} -c Code1.cpp

Code2.o: Code2.cpp Tools.o
  ${COMPILER} ${CXXFLAGS} -c Code2.cpp

Code3.o: Code3.cpp Tools.o
  ${COMPILER} ${CXXFLAGS} -c Code3.cpp

Tools.o: Tools.cpp Tools.hh
  ${COMPILER} ${CXXFLAGS} -c Tools.cpp

clean:
  rm *.o
  rm ${EXECUTABLE}
sdellysse