Search code examples
c++compilationincludepragma

error LNK2005 struct already defined in .obj file


I've been trying to deal with an issue regarding compilation units.

The error I am getting is

1>frtinvxml.obj : error LNK2005: "struct repFieldInfo det_rep_info" (?det_rep_info@@3UrepFieldInfo@@A) already defined in Frtinv.obj
1>frtinvxml.obj : error LNK2005: "struct repFieldInfo frt_rep_info" (?frt_rep_info@@3UrepFieldInfo@@A) already defined in Frtinv.obj
1>frtinvxml.obj : error LNK2005: "struct FormToolbar * tb" (?tb@@3PAUFormToolbar@@A) already defined in Frtinv.obj
1>frtinvxml.obj : error LNK2005: "struct tagDATE_STRUCT dateFrom" (?dateFrom@@3UtagDATE_STRUCT@@A) already defined in Frtinv.obj
... (It goes on for every variable and method in the header...)

This is the only error that I am getting. here are the includes to each respective classes involved in order from highest on the tree to lowest...

***Frtinv.hxx***
#pragma once

#include <voyage.ddh>
#include <vsched.ddh>
# ...

struct frtinvType : public frtinv_type
    {
    int     fixCarSeq;
    ...

...

***frtinv.cxx***
//#define _IN_MAIN_
#include <decisionTable.h>
... 

#define RINDEX 2
#define LINDEX 2
#define PINDEX 0

BOOL s_fNeedSaveAfterDelete = FALSE;
static int rateCnt = RINDEX, lumpCnt = LINDEX, pcntCnt = PINDEX;


//------------------------------------------------------------------------
int getPortcar(char *vslCode, int voyNo, int portCallSeq, int berthSeq, int seq, portcar_type *pret)
    ...

...

***frtinvxml.h***
#define _IN_MAIN_

#include <iostream>
#include <sstream>
#include <stdio.h>
#include <zdb.hxx>
#include <opr32.h>
#include <voyage.ddh>
#include <frtinv.ddh> <------ Tried to add these two to the solution, that failed.
#include <frtinv.hxx> <------

void exitGracefully();
std::list<voyage_type> getVoyages();

...

***frtinvxml.cpp***
#include "frtinvxml.h" <------ taking everything from frtinvxml.h

void main(int argc, char *argv[]) {

    InitWinLib (10, 8);
    ...

My problem stems from the fact that even if I place the files in the same folder/solution I cannot get them to not define themselves twice. Even when using the 'pragma once' keyword. I also tried using the old school #define, don't include if it already exists...that did not work either.

Do you have any solutions or recommendations?


Solution

  • #pragma once prevents inclusion of a header multiple times in a single compilation unit--a .obj file in this case--and the error plainly states frtinvxml.obj defines something that has already been defined in Frtinv.obj. Two separate objs. Two separate compilation units.

    once worked perfectly in the case of Frtinv.obj and again in the case of frtinvxml.obj. Both have exactly one definition otherwise the sources would not have compiled. Unfortunately the linker is trying to put both objs into the same output.

    Two solutions for this, depending on how the variable is to be used, but for both do not make declarations in headers. It almost always ends badly.

    Solution 1: All objects share a single variable

    Define:

    extern struct repFieldInfo det_rep_info;
    

    in the appropriate header. extern tells the compiler that somewhere det_rep_info will be declared and that compilation should continue using this external det_rep_info.

    In a cpp file, frtinvxml.cpp, Frtinv.cpp, or in some third cpp that contains common data, declare

    struct repFieldInfo det_rep_info;
    

    Then do the same with the other three duplicated variables.

    Exactly where to put these variable depends on personal taste, choice and coding standard. Compile this file and link it in with the other .obj files so that everyone can access the variable.

    Solution 2: All objects have their own private variable

    Declare:

    static struct repFieldInfo det_rep_info;
    

    in each cpp file that requires it. Repeat for all variables that are required. static ensures that each det_rep_info is only visible within a particular scope. In this case a single compilation unit. There is actually a bit of subtlety in there, so read the documentation to make sure static is right for you.

    You could put the declaration in the header, and each includer of the header will get its own copy, but it's important to note that every includer of the header will get a copy whether they want it or not. Don't make this decision for other people. Declare the variable in the cpp files that need it. Compiler will catch it if you miss one.