Running make gives "multiple definition of ... first defined here" error

87 Views Asked by At

I have following project structure:

ProjectX
├── Module1
│   ├── Module2
│   │   ├── CMakeLists.txt
│   │   ├── src
│   │   │   └── Module2.cpp // has #include "Common.h"
│   │   └── include
│   ├── CMakeLists.txt
│   ├── src
│   │   └── Class1.cpp  // has #include "Common.h"
│   │   └── Class2.cpp // has #include "Common.h"
│   └── include
│       └── Class1.h  // has #include "Class2.h"  ** NOTE **
├── Module3
│   ├── CMakeLists.txt
│   ├── src
│   │   └── Class3.cpp // has #include "Common.h"
│   └── include
├── src
│   └── NewClass.cc // newly added
├── include
│   ├── NewClass.h // newly added
│   └── Common.h // newly added
└── CMakeLists.txt

Commonn.h contains instances of NewClass to be used by all Modules:

#ifndef GLOBALS_H
#define GLOBALS_H

#include "NewClass.h"

namespace ProjectX {
    extern NewClass instance1 = NewClass();
    extern NewClass instance2 = NewClass();
    extern NewClass instance2 = NewClass();
}

#endif // GLOBALS_H

I have following CMakeFiles contents:

ProjectX/CMakeFiles.txt

add_library(${PROJECT_NAME} SHARED 
src/NewClass.cc
include/NewClass.h
include/Common.h
)

ProjectX/Module1/CMakeFiles.txt and
ProjectX/Module2/CMakeFiles.txt

set(PROJECTX_DIR ${PROJECT_SOURCE_DIR}/../)
target_include_directories(${PROJECT_NAME}
    PUBLIC ${PROJECTX_DIR}/include/
)

ProjectX/Module3/CMakeFiles.txt

set(PROJECTX_DIR ${PROJECT_SOURCE_DIR}/../../)
target_include_directories(${PROJECT_NAME}
    PUBLIC ${PROJECTX_DIR}/include/
)

Also note five #includes specified in the ASCII hierarchy at the top.

I am getting following errors while running make:

/usr/bin/ld: CMakeFiles/Module1.dir/src/Class1.cpp.o:(.bss+0x10): multiple definition of `ProjectX::instance1'; CMakeFiles/Module1.dir/src/Class2.cpp.o:(.bss+0x10): first defined here
/usr/bin/ld: CMakeFiles/Module1.dir/src/Class1.cpp.o:(.bss+0x20): multiple definition of `ProjectX::instance2'; CMakeFiles/Module1.dir/src/Class2.cpp.o:(.bss+0x20): first defined here
/usr/bin/ld: CMakeFiles/Module1.dir/src/Class1.cpp.o:(.bss+0x0): multiple definition of `ProjectX::instance3'; CMakeFiles/Module1.dir/src/Class2.cpp.o:(.bss+0x0): first defined here
/usr/bin/ld: Module2/libModule2.a(Module2.cpp.o):(.bss+0x20): multiple definition of `ProjectX::instance2'; CMakeFiles/Module1.dir/src/Class2.cpp.o:(.bss+0x20): first defined here
/usr/bin/ld: Module2/libModule2.a(Module2.cpp.o):(.bss+0x0): multiple definition of `ProjectX::instance3'; CMakeFiles/Module1.dir/src/Class2.cpp.o:(.bss+0x0): first defined here
/usr/bin/ld: Module2/libModule2.a(Module2.cpp.o):(.bss+0x10): multiple definition of `ProjectX::instance1'; CMakeFiles/Module1.dir/src/Class2.cpp.o:(.bss+0x10): first defined here
collect2: error: ld returned 1 exit status

Before including NewClass.cpp, NewClass.h, and Common.h, it was all working just fine. I wanted to add functionality that can be used as a kind of utility across all modules of ProjectX. Thats why I did then code and CMakeLists changes as explained above. But it started to give me above errors. How do I fix this? Also is there any better way to do this?

Update

I followed suggestions in answer by 0xbachmann below. Above error is gone. But now started getting following errors:

/usr/bin/ld: Module1/libModule1.so: undefined reference to `ProjectX::instance1'
/usr/bin/ld: Module1/libModule1.so: undefined reference to `ProjectX::NewClass::method(double, double)'
/usr/bin/ld: Module3/libModule3.so: undefined reference to `ProjectX::NewClass::method(std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l> > >, double)'
/usr/bin/ld: Module3/libModule3.so: undefined reference to `ProjectX::instance3'
/usr/bin/ld: Module1/libModule1.so: undefined reference to `ProjectX::instance2'
collect2: error: ld returned 1 exit status
1

There are 1 best solutions below

13
0xbachmann On

Even though add the extern keyword to this line

extern NewClass instance = NewClass(); 

this is a definition because you initialize the instance with NewClass(). What you should do, is declare the instances in the header file and define them in a source file:

Common.h:

#ifndef GLOBALS_H
#define GLOBALS_H

#include "NewClass.h"

namespace ProjectX {
    extern NewClass instance1;
    extern NewClass instance2;
    extern NewClass instance2;
}

#endif // GLOBALS_H

Some source file, maybe Common.cpp:

#include "Common.h"
#include "NewClass.h" // not necessarily needed

namespace ProjectX {
    NewClass instance1 = NewClass();
    NewClass instance2 = NewClass();
    NewClass instance2 = NewClass();
}

Then add this source file somewhere in your CMake Project either to your library or to one of your modules