(C++) Linking with namespaces causes duplicate symbol error
Asked Answered
V

4

6

For the past few days, I have been trying to figure out how to link the files for a CLI gaming project I have been working on. There are two halves of the project, the Client and the Server code.

The client needs two libraries I've made. The first is a general purpose game board. This is split between GameEngine.h and GameEngine.cpp. The header file looks something like this

namespace gfdGaming {

//  struct sqr_size {
//      Index x;
//      Index y;
//  };
    typedef struct { Index x, y; } sqr_size; 
    const sqr_size sPos = {1, 1};
    sqr_size sqr(Index x, Index y);
    sqr_size ePos;
    class board
    {
    // Prototypes / declarations for the class
    }
}

And the CPP file is just giving everything content

#include "GameEngine.h"

type gfdGaming::board::functions

The client also has game-specific code (in this case, TicTacToe) split into declarations and definitions (TTT.h, Client.cpp). TTT.h is basically

#include "GameEngine.h"

#define TTTtar "localhost"
#define TTTport 2886

using namespace gfdGaming;
void* turnHandler(void*);
namespace nsTicTacToe 
{
    GFDCON gfd;
    const char X = 'X';
    const char O = 'O';
    string MPhostname, mySID;
    board TTTboard;
    bool PlayerIsX = true, isMyTurn;
    char Player = X, Player2 = O;

    int recon(string* datHolder = NULL, bool force = false);
    void initMP(bool create = false, string hn = TTTtar);
    void init();
    bool isTie();
    int turnPlayer(Index loc, char lSym = Player);
    bool checkWin(char sym = Player);

    int mainloop();

    int mainloopMP();

}; // NS

I made the decision to put this in a namespace to group it instead of a class because there are some parts that would not work well in OOP, and it's much easier to implement later on.

I have had trouble linking the client in the past, but this setup seems to work.

My server is also split into two files, Server.h and Server.cpp.

Server.h contains exactly:

#include "../TicTacToe/TTT.h" // Server needs a full copy of TicTacToe code

class TTTserv;
struct TTTachievement_requirement {
    Index id;
    Index loc;
    bool inUse;
};
struct TTTachievement_t {
    Index id;
    bool achieved;
    bool AND, inSameGame;
    bool inUse;
    bool (*lHandler)(TTTserv*);
    char mustBeSym;
    int mustBePlayer;
    string name, description;
    TTTachievement_requirement steps[safearray(8*8)];

};

class achievement_core_t : public GfdOogleTech {
public: // May be shifted to private
    TTTachievement_t list[safearray(8*8)];
public:
    achievement_core_t();

    int insert(string name, string d, bool samegame, bool lAnd, int lSteps[8*8], int mbP=0, char mbS=0);
};


struct TTTplayer_t {
    Index id;
    bool inUse;
    string ip, sessionID;
    char sym;
    int desc;
    TTTachievement_t Ding[8*8];
};
struct TTTgame_t {
    TTTplayer_t Player[safearray(2)];
    TTTplayer_t Spectator;
    achievement_core_t achievement_core;
    Index cTurn, players;
    port_t roomLoc;
    bool inGame, Xused, Oused, newEvent;
};


class TTTserv : public gSserver {
    TTTgame_t Game;
    TTTplayer_t *cPlayer;

    port_t conPort;
public:
    achievement_core_t *achiev;
    thread threads[8];
    int parseit(string tDat, string tsIP);
    Index conCount;
    int parseit(string tDat, int tlUser, TTTplayer_t** retval);

private:
    int parseProto(string dat, string sIP);
    int parseProto(string dat, int lUser);

    int cycleTurn();
    void setup(port_t lPort = 0, bool complete = false);

public:
    int newEvent;
    TTTserv(port_t tlPort = TTTport, bool tcomplete = true);

    TTTplayer_t* userDC(Index id, Index force = false);
    int sendToPlayers(string dat, bool asMSG = false);
    int mainLoop(volatile bool *play);
};



// Other 
void* userHandler(void*);
void* handleUser(void*);

And in the CPP file I include Server.h and provide main() and the contents of all functions previously declared.

Now to the problem at hand I am having issues when linking my server. More specifically, I get a duplicate symbol error for every variable in nsTicTacToe (and possibly in gfdGaming as well). Since I need the TicTacToe functions, I link Client.cpp ( without main() ) when building the server

ld: duplicate symbol nsTicTacToe::PlayerIsX       in Client.o and Server.o
collect2: ld returned 1 exit status
Command /Developer/usr/bin/g++-4.2 failed with exit code 1

It stops once a problem is encountered, but if PlayerIsX is removed / changed temporarily than another variable causes an error

Essentially, I am looking for any advice on how to better organize my code to hopefully fix these errors.

Disclaimers: -I apologize in advance if I provided too much or too little information, as it is my first time posting

-I have tried using static and extern to fix these problems, but apparently those are not what I need

Thank you to anyone who takes the time to read all of this and respond =)

Volution answered 15/1, 2011 at 22:47 Comment(4)
Try using header guards, you aren't using any.Leavy
I provided an answer below but also, do use header guards as the other commenters have noted.Koah
Since he is having troubles LINKING, header guards are probably not his only problem, although using them is always better (I think?) than not using.Fume
In your header file you have usually forward declarations like void DoWork(); If you have an implementation of function body like void DoWork() { /* your code goes here...*/ }, and this header file is included by some cpp files, then your linker has a problem. For this you can implement a cpp file and exclude the DoWork function body into it. Similar problems we have by fields. To solve it, move the field declarations in the cpp file. When you need it in other files, see the solution from maxelostBoarder
A
9

You get error about duplicate definitions because that's what you have: each time a .cpp file includes TTT.h, a global bool PlayerIsX is defined (in the nsTicTacToe namespace, but still global). In this case, it's Server.cpp and Client.cpp that are including it.

One way to solve this could be to change the definitions into declarations by using extern, then doing the actual definition in a corresponding .cpp file (TTT.cpp, for instance).

In TTT.h:

namespace nsTicTacToe {
   ...
   extern bool PlayerIsX;
   ...
}

In TTT.cpp:

#include "TTT.h"

bool nsTicTacToe::PlayerIsX;

and so on for the other definitions.

By the way, remember to have proper guard #ifdefs:

#ifndef __TTT_H
#define __TTT_H
... header contents
#endif   // __TTT_H
Acquit answered 15/1, 2011 at 23:2 Comment(2)
Thank you so much for your fast response, and thank you for all of the helpful info. It turns out that's exactly what I needed to. Works perfectly now.Volution
@Gfdking: No problem. I would, however, also recommend lefticus's suggestion about improving the code organization (using struct or class).Acquit
H
4

Actually, extern IS what you need. You're probably just not realizing or remembering that you'll also have to define such variables in a cpp file.

header:

extern int somevar;

source:

int somevar = ?;

By putting all of your globals in the header you're making copies of them everywhere you include them, which is exactly what your compiler is bitching about.

Harvey answered 15/1, 2011 at 23:11 Comment(1)
Thanks for the response! You are right, it turns out I slightly misunderstood how to implement extern. Fixed nowVolution
K
3

You are essentially using globals, which is strongly not recommended in C++, but is sometimes necessary in C.

You could get it working with extern, but the "better" answer would be to wrap your globals in a state object of some sort.

struct State
{
  GFDCON gfd;
  const char X;
  const char O;
  string MPhostname, mySID;
  board TTTboard;
  bool PlayerIsX, isMyTurn;
  char Player, Player2;
};

Create your state object in Main and pass it to each function that needs to know the state of the game system.

This will lead to much better code organization in the long run.

Koah answered 15/1, 2011 at 23:4 Comment(1)
Thanks. Yes I agree in retrospect that holding the data in an object would have been better. Although restructuring my code at this stage doesn't sound very appealing, I'll certainly keep this in mind =)Volution
P
1

you could put the namespace nsTicTacToe part into it's own .cpp file, compile it separately and link it in. You might also need a header file which just declares externs for the variables, and include that in you client and server .cpp files.

Puttier answered 15/1, 2011 at 23:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.