0

I have a main method,

main.cpp:

#include "MyStruct.h"

MyStruct.h:

#ifndef MYPROJ_MYSTRUCT_H
#define MYPROJ_MYSTRUCT_H
#include <vector>
#include <unordered_map>

bool function1(std::vector<std::string> label){ 
    // actual implementation     
}
bool function2(...){ ... }

struct MyStruct{ ... }
#endif

This compiles. However, when I add the cpp file to contain the function definitions,

main.cpp: 

#include "MyStruct.h"

MyStruct.h:

#ifndef MYPROJ_MYSTRUCT_H
#define MYPROJ_MYSTRUCT_H
#include <vector>

bool function1(...){ ... }
bool function2(...){ ... }

struct MyStruct{ ... }
#endif

MyStruct.cpp:

#include "MyStruct.h"

// and that's it

Just by including the header file, I get linker errors as if I am importing the header multiple times;

Here is the CMakeLists:

cmake_minimum_required(VERSION 3.8)
set(CMAKE_CXX_STANDARD 17)

set(SOURCE_FILES main.cpp MyStruct.cpp)
add_executable(my_proj ${SOURCE_FILES})

The errors consist of all duplicate symbol errors. I am not sure how to get this to work, as this is something I do all the time using make and g++ without running into issues; I also don't seem to have this problem when I use CMake with g++ on Cygwin/Windows (this is on MacOSX).


Next, when I transition all functions to the .cpp file, and only declarations are present in the header, I eliminate most of the duplicate symbols except for :

duplicate symbol __Z8get_uvidv in:
    CMakeFiles/main.cpp.o
    CMakeFiles/MyStruct.cpp.o
duplicate symbol _uvid in:
    CMakeFiles/main.cpp.o
    CMakeFiles/MyStruct.cpp.o
ld: 2 duplicate symbols for architecture x86_64

Updated Source


// header: MyStruct.h

#ifndef MYPROJ_MYSTRUCT_H
#define MYPROJ_MYSTRUCT_H

#include <unordered_map>
#include <vector>
#include "AnotherStruct.h"

bool add_item(std::pair<std::string,float> & item);
void insert_item(std::vector<AnotherStruct> & A, std::pair<std::string,float> element);
...

struct MyStruct {
    std::unordered_map<std::string,int> labels;
    std::vector<AnotherStruct> data;

    MyStruct(std::vector<char *> inputs);

    void GetData();
    void SortData(bool (*compare)(AnotherStruct &,AnotherStruct &);
    //...
}
#endif

And the .cpp:

#include "MyStruct.h"

// implement everything declared in .h 
bool add_item(...){
    ...
}
bool insert_item(...){
    ...
} 

MyStruct::MyStruct(...){
    ...
}
void MyStruct::GetData(...){
    ...
}
void MyStruct::SortData(...){
    ...
}

And the main:

#include "MyStruct.h"

The errors:

duplicate symbol __Z8get_uvidv in: 
    main.cpp.o
    MyStruct.cpp.o
duplicate symbol _uvid in:
    main.cpp.o
    MyStruct.cpp.o

I have no idea what __Z8get_uvidv could possibly be, nor _uvid, so I assumed there was something going on with the std imports, or underneath the hood with respect to the compiler.

Bearing in mind that everything compiles when I copy it over to the main method, or leave all definitions in the header file, I am stumped.

Chris
  • 28,822
  • 27
  • 83
  • 158
  • 1
    [This answewr](https://stackoverflow.com/a/16851880/4342498) answers the question but I don't like the Q for a dupe target. – NathanOliver Feb 20 '18 at 15:30
  • 2
    Those braces makes me think that your header contains actual function definitions rather than mere forward declarations, this is consistent with duplicate symbols as well. – Caninonos Feb 20 '18 at 15:30
  • @Caninonos Yes, it does. I am trying to move everything from my main method to files. I reduced this to the bare minimum I needed to do to make it break, but when I move all the function definitions to the cpp, I get the same errors. – Chris Feb 20 '18 at 15:32
  • 1
    @bordeo your headers shouldn't contain any function definitions (e.g. `int f() { return 1; }`) only forward declarations (e.g. `int f();`) unless those are template functions or they are marked inline (in which cases you shouldn't write their definitions elsewhere). Otherwise, when you include the header in two different files, there will be two definitions of the same function in different translation units (= cpp files if you will) which will confuse the linker. – Caninonos Feb 20 '18 at 15:36
  • 1
    Oh by the way, an interesting detail is that functions defined in class scope are implicitly marked inline. So if you have `struct C { int method() { return 1; } };` in a header, including it twice won't cause problems for the linker (`method` is implicitly marked inline here). However you'd have problems with `struct C { int method(); }; int C::method() { return 1; }` in a header (assuming it's included twice), the second part should probably moved to a cpp file. – Caninonos Feb 20 '18 at 15:41
  • 1
    That `AnotherStruct.h` that you include, did you write it or does it come from some third-party library? Did you make sure it doesn't contain definitions as well? (same for any other header you'd include directly or indirectly in `AnotherStruct.h`) – Caninonos Feb 20 '18 at 16:06
  • @Caninonos oh, got it. man. alright, no definitions ever. Now I see. Thank you so much. – Chris Feb 20 '18 at 16:10

1 Answers1

2

You have included MyStruct.h in both main.cpp and MyStruct.cpp.

Include basically does a copy-paste, leaving you with 2 translation units (main.cpp and MyStruct.cpp) that both contain a definition for function1 and function2 (because you included the header file in both).

Solution:

Only declare the functions in the header file and define them in one translation unit only.

Hatted Rooster
  • 35,759
  • 6
  • 62
  • 122
  • Hmm. I have done this, and walked it back to produce this minimum step to break it. Is it possible that I can cause this error with functionality inside my struct, and not just my functions? – Chris Feb 20 '18 at 15:33
  • @bordeo `bool function1(...){ ... }` in "_MyStruct.h_" Suggests that the header contains the definition, which is the reason for the error, and that is explained in this answer. If it doesn't contain the definition, of a function, however - please edit your [mcve], so that it matches your code. – Algirdas Preidžius Feb 20 '18 at 15:36
  • Yes. @bordeo By convention, use header files for declaration, .cpp (or whatever) for implementation. This will prevent this error. – Major Feb 20 '18 at 15:37
  • @Major, huh. Yeah, that is what I thought. However, the last two duplicate symbol errors: `duplicate symbol __Z8get_uvidv` and `duplicate symbol _uvid` seem to be impossible to eliminate, after transitioning everything over to the .cpp file. – Chris Feb 20 '18 at 15:41
  • 1
    @bordeo I'm not really used to decrypting types from symbols. What are the types of `get_uvid` and `uvid` (or something similar) in your program ? Where and how do they appear in your header ? – Caninonos Feb 20 '18 at 15:46
  • @Caninonos I have no idea. They are not in my program, nor do they appear in my header; I figured they were something from under the hood of CLang and whatnot. I write code like this all the time. I have no idea why this isn't working. – Chris Feb 20 '18 at 15:48
  • @bordeo will you update the question with your updated source? – Major Feb 20 '18 at 15:49
  • @Major yup one sec – Chris Feb 20 '18 at 15:50
  • @Major updated with new header (where the problem probably is?) and working on the cpp – Chris Feb 20 '18 at 15:58
  • @bordeo Have you tried `rm`ing the object files and recompiling? especially `main.cpp.o`. Also, need a semicolon in `struct MyStruct {...};` – Major Feb 20 '18 at 16:18