1

I am writing a library for neural nets. There are some necessary functions I needed so I separated them in a separate header file. I also provided the definition guards. I also included the header file in only one file but then also linker claims that there are multiple definitions of all the functions in the program. The library structure is as follows:

namespace maya:
     class neuron [neuron.hpp, neuron.cpp]
     class ffnet [ffnet.hpp, ffnet.cpp]
     struct connection [connection.hpp]
     functions [functions.hpp]

the functions header file is written something like this:

#ifndef FUNCTIONS_HPP
#define FUNCTIONS_HPP
// some functions here
double random_double(){//some code}
#endif

this functions.hpp file is included only one in neuron.hpp and since ffnet is dependent on neuron, I included neuron.hpp in ffnet only once. This ffnet.hpp is included in main.cpp only once. main.cpp is file that I use for testing my library.

this linker throws error something like this:
/usr/bin/ld: /tmp/ccN7ywby.o: in function `maya::random_double()': neuron.cpp:(.text+0x0): multiple definition of maya::random_double()'; /tmp/ccvDr1aG.o:main.cpp:(.text+0x0): first defined here

/usr/bin/ld: /tmp/cc66mBIr.o: in function `maya::random_double()':`` ffnet.cpp:(.text+0x0): multiple definition of `maya::random_double()'; /tmp/ccvDr1aG.o:main.cpp:(.text+0x0): first defined here

Also I compiled my program using :
g++ main.cpp neuron.cpp ffnet.cpp -o net

I don't think this will be needed but just in case :
$ uname -a
Linux brightprogrammer 4.19.0-kali3-amd64 #1 SMP Debian 4.19.20-1kali1 (2019-02-14) x86_64 GNU/Linux

Christophe
  • 68,716
  • 7
  • 72
  • 138
  • 2
    Include guards stop a header from being included in the same translation unit (basically cpp file) more than once. They do nothing to stop the header from being included once in every cpp file where you include it. If your functions are defined in headers and are not inline then you will have multiple definitions. You can declare the prototypes in the header and implement them in a cpp file to fix that. – Retired Ninja Mar 02 '19 at 07:04
  • 3
    Possible duplicate of [multiple definition in header file](https://stackoverflow.com/questions/2727582/multiple-definition-in-header-file) – Retired Ninja Mar 02 '19 at 07:05

2 Answers2

2

You must write code of random_double() in .cpp file other than .hpp or .h file. Or, add inline before double random_double() { //some code } if you keep your code in your .hpp file.

Fryz
  • 2,119
  • 2
  • 25
  • 45
Yuanhui
  • 459
  • 5
  • 15
  • Indeed, inline allows the compiler to accept exactly the same function definition in several compilation units. However, I wonder if these functions are really meant to be inlined, or if they are general utility functions that are meant to be reused and that could later evolve (without having to recompile every dependent compilation unit). – Christophe Mar 02 '19 at 07:24
1

The problem

You have your function definition with their full code in a header that you include in several compilation units. This causes the function to be defined in each compilation unit (cpp) and this breaks the One Definition Rule (ODR).

The include guards make sure that the same definition doesn't occur several time in the same compilation unit (e.g. if you include function.hpp in neuron.hpp and also include it directly). But here this header is included directly or indirectly in main.cpp, ffnet.cpp and neuron.cpp, which makes a first definition and 2 invalid redefinitions.

The solution

You must change function.hpp to keep only the function declaration:

#ifndef FUNCTIONS_HPP
#define FUNCTIONS_HPP
double random_double();  // no body !!
#endif

and move the function bodies to a separate function.cpp, which must be added to your compiler command.

The advantage of this approach are:

  • You can then compile the utility functions separately. Every time you'd change the function body, you'd no longer have to recompile all the cpp.
  • Encapsulation is improved, by sharing in the hpp only what other modules need to know, and hiding the implementation details.
  • Reuse could be facilitated across projects by making a library of functions.
  • The includes would be shorter (in case in some distant future your code would evolve to a large project with thousands of hpp, this could make you gain some time)

Additional remarks

Not sure that it applies, but be aware also that it's not a good idea to include a header into a namespace.

I also recommend reading this article about headers. It's old but the advice is still very relevant :-)

Note that there are exceptions to the ODR for classes and inline functions, in which case the multiple definitions must be exactly the same sequence of tokens.

Christophe
  • 68,716
  • 7
  • 72
  • 138