0

let me start by saying that I am not the best C++ and I know very little in ways of Linux. For a class project we had to implement a heap so I coded everything on my Windows PC assuming I could just upload the files to the Linux repository the school has. [Perhaps this is where I went wrong and this cannot be done this simply.] My codes compiles and clears all test cases provided on my Windows pc. When I upload the files to Linux, I created a makefile and when I use the make command I get back a laundry list of multiple definition errors. One error per function that I am using. I have done some searching and I am more confused then when I started.

My files are: main.cpp, main.h, heap.cpp, heap.h, util.cpp, and util.h.

I think the issue is with my include statements but I am not 100% sure.

Here is an example of the files.

main.cpp

 #include <iostream>  //needed to use basic inputs/outputs
 #include <stdio.h>
 #include <stdlib.h>
 #include "main.h"
 #include "util.cpp"
 #include "heap.cpp"
 #include <fstream>
 using namespace std;

main.h is blank.

heap.cpp

 #include <iostream>  //needed to use basic inputs/outputs
 #include <stdio.h>
 #include <stdlib.h>
 #include "heap.h"
 #include <cmath>
 #include <math.h>
 using namespace std;

 //expanded functions found in the heap.h file

heap.h

 //2 structs
 //9 functions

util.cpp

 #include <iostream>  //needed to use basic inputs/outputs
 #include <stdio.h>
 #include <stdlib.h>
 #include "util.h"
 using namespace std;

 //expanded functions found in util.h

util.h

 //1 function

Between heap.h and util.h I have 10 function and upon running the make command I get a warning about all ten:

 multiple definition of 'FUNCTIONNAME'
 main.o:main.cpp:(.text+0x1b7): first defined here

I am assuming the 0x1b7 is a memory location because they are each different.

Any help would be greatly appreciated.

AxGryndr
  • 2,274
  • 2
  • 22
  • 45
  • 3
    you have set the guards in the header where you declare FUNCTIONNAME function. – eyllanesc Mar 18 '18 at 20:29
  • 6
    `#include "util.cpp"` this is almost certainly wrong. – llllllllll Mar 18 '18 at 20:30
  • 1
    You should not include source files (the files ending in `.cpp`). Build them separately into object files, and link all object files into an executable. It seems to me that the root cause is that you do *both*: Include the source *and* link with the separate object files. However, it's impossible to say without knowing how you build your program. – Some programmer dude Mar 18 '18 at 20:32
  • @eyllanesc what is a guard? – AxGryndr Mar 18 '18 at 20:32
  • https://stackoverflow.com/questions/1143936/pragma-once-vs-include-guards – eyllanesc Mar 18 '18 at 20:34
  • [Include guards](https://en.wikipedia.org/wiki/Include_guard), or [`#pragma once`](https://en.wikipedia.org/wiki/Pragma_once). However that's most likely not the problem here. – Some programmer dude Mar 18 '18 at 20:34
  • 1
    @Someprogrammerdude So because my make file has main.o, heap.o and util.o I don't have to include the .cpp files in main.cpp? – AxGryndr Mar 18 '18 at 20:35
  • 1
    There are almost *never* a good reason to `#include` a source file – Some programmer dude Mar 18 '18 at 20:36
  • You compile the .cpp files, individually, to object files. Then the linker links all of the object files and any libraries you're using. If you include a .cpp file when you're generating the object file for main.cpp and also link the object (.o) file that was generated from that .cpp file, then the compiler has created symbols for everything in the .cpp file twice, and the linker doesn't know which copy to use. – Tom Mar 18 '18 at 20:52
  • If there are 9 functions in heap.h then they must be `inline` (or templates) – M.M Mar 18 '18 at 21:48

1 Answers1

2

You haven't shown the Makefile, but most likely, it includes this or a similar rule

program: main.o heap.o util.o
    $(CXX) $(CXXFLAGS) -o program main.o heap.o util.o

What happens now, the compiler builds the three object files main.o, heap.o and util.o. Next the object files are linked together to build program.

The linker sees definitions of the various functions defined in both main.o and heap.o, or main.o and util.o respectively. This is why it complains about "multiple definition of 'FUNCTIONNAME'"


Why are these functions defined more than once?

When you include a file into another source, it is as if you copy the contents at the location of the #include. This means a function defined in heap.cpp:

void create_heap(int size)
{
    // create a heap ...
}

is copied verbatim into main.cpp where the line

#include "heap.cpp"

is.


Because heap.cpp has the definition of create_heap() and main.cpp #includes the contents of heap.cpp, both contain their own copy of create_heap(). Now you compile both heap.o and main.o, and link them together. Each object file has a copy of create_heap() and this is where the linker is confused and complains

multiple definition of 'create_heap'
main.o:main.cpp:(.text+0x1b7): first defined here

To fix this, simply replace the lines including the cpp sources, e.g.

#include "util.cpp"
#include "heap.cpp"

with their respective header files

#include "util.h"
#include "heap.h"

Only keep the function definitions relevant to main.cpp, nothing else. Now main.cpp has no function definitions belonging to util.cpp or heap.cpp, and the linker errors are gone.


Presumably, this worked on Windows, because only main.cpp was included in the project file, and so only one definition (from main.o) was in the resulting executable.

If you had included all sources as in the Linux Makefile, the error could be seen in Windows as well.

Olaf Dietsche
  • 72,253
  • 8
  • 102
  • 198
  • 1
    It's worth noting that _this was still a problem on Windows_. It just wasn't exposed, presumably because the other `.cpp` files were not properly added to the project in an IDE (and therefore were not independently compiled, as they should have been). – Lightness Races in Orbit Mar 18 '18 at 21:25
  • Yes, presumably only main.cpp was added to the project, and therefore the error didn't show. – Olaf Dietsche Mar 18 '18 at 21:26
  • With that added to the answer, it would be essentially perfect. – Lightness Races in Orbit Mar 18 '18 at 21:27
  • @LightnessRacesinOrbit or perhaps the linker in use discarded multiple copies. (Most ODR violations, including this one, are UB with no diagnostic required) – M.M Mar 18 '18 at 21:49
  • @M.M: Mm fair point technically possible (if highly unlikely) – Lightness Races in Orbit Mar 18 '18 at 21:52
  • As I stated above I don't know much about C++ and I know even less about Linux. I am using Dev C++ as my compiler in Windows and I don't have anything in a project. It seems to be this point which is why I was getting errors in Linux and not Windows. – AxGryndr Mar 18 '18 at 23:47
  • I disagree on one point in your answer though. You cannot simply remove the includes because the functions from the headers are not defined as function prototypes in main.cpp therefore the includes had to be changed to .h instead of .cpp. – AxGryndr Mar 18 '18 at 23:51
  • @AxGryndr Thank you for the clarification, I fixed the answer appropriately. – Olaf Dietsche Mar 19 '18 at 07:13