I’d love help diagnosing the source of a duplicate symbol error that I’m receiving when I try to compile with g++ 4.2.1.
The specific error is
ld: duplicate symbol _SOCIODEM_FILENAMES in /var/folders/c+/c+eq1Qz1Feye7vxs5mQOUE+++TI/-Tmp-//ccP3yVgF.o and /var/folders/c+/c+eq1Qz1Feye7vxs5mQOUE+++TI/-Tmp-//cc1NqtRL.o
collect2: ld returned 1 exit status
The error occurs only when I include this declaration in a file called Parameters.h:
// Parameters.h
#ifndef PARAMETERS_H
#define PARAMETERS_H
// ...[code snipped]...
const int NUM_SOCIODEM_FILES = 5;
const char * SOCIODEM_FILENAMES[ NUM_SOCIODEM_FILES ] = { "LSPAN_PDF.txt",
"FLEDGE_PDF.txt",
"PAIR_PDF.txt",
"BIRTH_AGE_PDF.txt",
"SPLIT_PDF.txt" };
// ...[code snipped]...
#endif
I’ve searched all my files, and this is the only place where SOCIODEM_FILENAMES is declared. When I comment out the declaration, the ‘duplicate symbol’ error goes away.
I’m unfamiliar with linker errors (if that’s what this is) and would appreciate help troubleshooting the problem. All my header files have #ifndef...#define...#endif wrappers. My compile command is
g++ -o a.out -I /Applications/boost_1_42_0/ Host.cpp Simulation.cpp main.cpp Rdraws.cpp
Thanks in advance.
Solution summary
I now have in Parameters.h:
const char * const SOCIODEM_FILENAMES[ NUM_SOCIODEM_FILES ] = { "LSPAN_PDF.txt",
"FLEDGE_PDF.txt",
"PAIR_PDF.txt",
"BIRTH_AGE_PDF.txt",
"SPLIT_PDF.txt" };
All other definitions and declarations in Parameters.h are unchanged. Andrey and other commenters summarize an alternative approach using extern, which is overkill for my purposes.
For some reason none of the answers so far cared to explain the difference between your integer
NUM_SOCIODEM_FILESobject and arraySOCIODEM_FILENAMESobject. The latter triggers the linker error for the reasons already explained: because you include you header file into multiple implementation files. Yet, the former would link without any problems (because there are indeed no problems withNUM_SOCIODEM_FILESdeclaration). Why?The reason for this is that your
NUM_SOCIODEM_FILESobject is declaredconst. In C++ const objects have internal linkage by default, meaning that they do not cause linking problems even if they are defined in multiple implementation files. In other words, in C++ yourNUM_SOCIODEM_FILESis equivalent towhich is why it does not lead to any linking problems.
At the same time your
SOCIODEM_FILENAMESis not declared constant, which is why it gets external linkage by default and eventually leads to linker errors. But if you declare yourSOCIODEM_FILENAMESasconstas well, the problem will go awayNote where the extra
constis placed in the declaration. If you just add that extraconstand leave everything else as is (i.e. keep the definition ifSOCIODEM_FILENAMESin the header file), the linker will not report the error even if you include your header file into multiple translation units.This is not a recommended approach though, since that way you will give your
SOCIODEM_FILENAMESinternal linkage and end up with a standalone copy ofSOCIODEM_FILENAMESarray in each translation unit – something that might work fine but still makes very little sense. So, for your array, it is normally better to use theexternapproach recommended in other answers.However, note that you shouldn’t normally do it for
NUM_SOCIODEM_FILESdeclaration!!! It is fine as it is, defined in the header file. Unless you are trying to do something unusual, scalar constants should normally be defined with initializer in the header files – that way they can be seen as compile-time constants in all translation units, which is a rather valuable thing to have. So, beware of the strange advice present in some other answers to move the definition ofNUM_SOCIODEM_FILESinto.cppfile as well – this actually makes no sense and is a totally wrong thing to do.