2
votes

All related questions I was able to find do not detail my exact scenario, so I hope this is not considered a duplicate question.

I have class A(using A.h to declare and A.cpp to define) that includes and uses functions from a Math.h.

When I try to build my main.cpp to use object A that #includes the header for class A, I get a multiple definition error for every single math function defined in Math.h(Math.h does not have a .cpp, all functions/variables are defined in the header).

A.h

#ifndef A_H
#define A_H

#include "Math.h"

//Other #includes

namespace MY_NAMESPACE
{
    class A
    {
        public:

            A();
            //Variable/Function declarations

        private:

            //Variable/Function declarations
    };
}

#endif

A.cpp

#include "A.h"

void MY_NAMESPACE::A::Func1()
{
    //define
}

ect...

main.cpp

#include "A.h"


int main()
{
    MY_NAMESPACE::A* a = new MY_NAMESPACE::A();

    delete a;

    return 0;
}

Math.h(Declared and defined only in header)

#ifndef MATH_H
#define MATH_H

float DotProduct(Vector3 v1, Vector3 v2)
{
    return (v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z);
}

#endif

etc...

I am new to linux/g++. This has never caused any issue in the past when programming in Visual Studio on a Windows platform.

This is pretty basic stuff, so I am rather baffled.

makefile

CC=g++ FLAGS=-std=c++11 -g

build: clean A.o main

clean:
  rm -f -v bin/*.*

A.o:
  $(CC) -c $(FLAGS) A.cpp

main:
  $(CC) $(FLAGS) main.cpp A.o

Any advice?

EDIT Actual error snippit

In function WF_RPI::MATH::Normalize(WF_RPI::MATH::Vector3)': /home/pi/projects/WFRPI/TPx2SController/../WFStandard/WFSMath.h:574: multiple definition of WF_RPI::MATH::Normalize(WF_RPI::MATH::Vector3)' Arcus.o:/home/pi/projects/WFRPI/Arcus/../TPx2SController/../WFStandard/WFSMath.h:574: first defined here bin//libtpx2s.a(tpx2s.o): In function WF_RPI::MATH::Normalize(WF_RPI::MATH::Vector2)': /home/pi/projects/WFRPI/TPx2SController/../WFStandard/WFSMath.h:590: multiple definition of WF_RPI::MATH::Normalize(WF_RPI::MATH::Vector2)' Arcus.o:/home/pi/projects/WFRPI/Arcus/../TPx2SController/../WFStandard/WFSMath.h:590: first defined here bin//libtpx2s.a(tpx2s.o): In function `WF_RPI::MATH::Magnitude(WF_RPI::MATH::Vector2)':

1
Just a guess, but could Math.h be lacking header guard? Also; could you show the actual error messages you get (verbatim)? As well as the actual compiler commandline you used? In fact, a minimal reproducible example would be best. - Jesper Juhl
You have two instances of DotProduct with the same signature in two different compilation units. This is not allowed. Either force it into one of the existing compilation units and have the other reference it, or move it into a third compilation unit entirely. - Ignacio Vazquez-Abrams
Don't name your header file "math h" or "Math.h". - n. 1.8e9-where's-my-share m.
There is no mention of WFSMath.h or Normalize in the posted code. Nome of the posted files is named Arcus. Error messages are obviously produced by something totally different from posted code. Please post a minimal reproducible example. - n. 1.8e9-where's-my-share m.

1 Answers

3
votes

Functions in Math.h need to be inlined ...

inline float DotProduct(Vector3 v1, Vector3 v2)
{ 
    return (v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z);
}

C/C++ currently uses a textual insertion for an include file. That means that for each .cpp file, it is made up of all of the text in all of its includes, and its own code.

When a compiler sees

 int funName( int param ) {
         // something...
 }

It declares an external function. When it links the C++ files together, it spots there are multiple definitions causing the issue.

The fix (as mentioned right at the top), is to mark the functions as inline. Which allows multiple definitions to be linked.

The error describes a more complex issue, than you have described. It mentions an archive (.a) file which has the duplicate definition with the header file WFSMath.h.

The archive will need to be re-built, as it may have embedded non-inline implementations, and some make systems are less than perfect at spotting a library requires re-building if a header file changes.