samedi 24 juin 2023

Unable to Locate Multiple Definitions Linker Error [duplicate]

I am trying to understand what happens during the linking stage of the translation process in C++. Basically I was experimenting with header files and wanted to see if it's alright to define functions in header files as opposed to separating them in their respective cpp files. That said, I have World.h and its definitions written in the same file. The same goes for my Util.h header file.

The problem occurred when I was in the middle of separating function definitions into their own separate source files. But instead of just following basic protocol, I first want to understand why this is happening.

PS: I am fully aware that best practice would be to separate the definitions from the function declarations in another source file. I just wanted to experiment a bit.

Inside the Util.h file (The gcf function produces the multiple definitions error):

#pragma once

...

int gcf(int a, int b)
{
    if (a == 0) return b;
    return gcf(b % a, a);
}

World.h:

#pragma once

#include <SFML/Graphics.hpp>
#include "Paddle.h"
#include "Ball.h"
#include "Util.h"

class Paddle;
class Ball;

class World
{...};

Paddle.cpp:

#include "World.h"
#include "Paddle.h"

Paddle::Paddle(const sf::Vector2f& size, const Side& side, World& world)
: sf::RectangleShape(size), m_Side(side), m_World(&world) {}

...

Ball.cpp:

#include <cstdlib>
#include <cmath>

#include "World.h"
#include "Ball.h"

Ball::Ball(const sf::Vector2f& size, float speed, World& world)
: sf::RectangleShape(size), m_Speed(speed), m_World(&world)
{
    initializeVelocity();
}

...

As you can see, I included Util.h in World.h. Then, in Paddle.cpp and Ball.cpp, I included World.h in both of them because I have a circular dependency (World.h also refers to Paddle.h and Ball.h). I think it is also important to note that the Paddle.cpp and Ball.cpp files have their own corresponding header files with only the declarations. Only Util.h and World.h have function definitions with them in the same file (Also GameView.h but that header file is not relevant).

So is this why the error occurs? Because I was including World.h in two translation units or source files? If so, then I have firm reason to believe that I am misunderstanding the purpose of include guards or #pragma once. I thought these are enough to prevent linker errors but it turns out it can't prevent duplication in two source files. Can somebody explain to me how include guards actually work and why I'm getting the linker error? It would be very much appreciated.

Here is the full source code in my GitHub if you want to see the full context. It's a Pong game clone I'm trying to code using SFML.

And here's the linker error I get:

/usr/bin/ld: Main.o: in function `gcf(int, int)':
Main.cpp:(.text+0x0): multiple definition of `gcf(int, int)'; Ball.o:Ball.cpp:(.text+0x0): first defined here
/usr/bin/ld: Paddle.o: in function `gcf(int, int)':
Paddle.cpp:(.text+0x0): multiple definition of `gcf(int, int)'; Ball.o:Ball.cpp:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status

Aucun commentaire:

Enregistrer un commentaire