3

I have these two classes (let's call them A and B) that both include boost/archive and boost/serialization files. These includes are in my hpp files (with header guards) for each of the two classes. Class A (and other parts of the code base) include class B and as such repeats the exact same includes.

From my understanding the header guards in the boost library should be preventing the library files from being included a second time here; but that appears not to be the case. I have even gone as far as putting another header guard around the include bloc just to make sure it wouldn't be included multiple times; and yet at linkage I get a multiple definition's error.

Includes in class A:

#ifndef _A_H
#define _A_H


// Other none boost includes for class A
#ifndef _BOOST_INCLUDES_
#define _BOOST_INCLUDES_
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/binary_object.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/string.hpp>
#endif

class A{/*...*/};

And class B has the same include block (and _BOOST_INCLUDES_ guard) in its header file. Other parts of the code also include class A or class B at some point, but the problem stems from something in the includes here.

Why is this happening (and how could I fix it)? Why aren't the boost header guards stopping this second inclusion? Could this have nothing to do with the code itself but rather be a build problem?

Makefile extract:

BOOST_ROOT  := myPathToBoost/boost_1_75_0/
BOOST_LIBS  := -L$(BOOST_ROOT)stage/lib/ -lboost_serialization
BOOST       := -I $(BOOST_ROOT) $(BOOST_LIBS)

$(CM_OBJS): $(CM_SOURCES)
    $(CC) $(FLAGS) -MMD $(BOOST) -c $(INCLUDES) -o $@ $< $(LIBS)

The linker error is:

/usr/bin/ld: /projectPath/build/clientMain.o:(.bss+0x0): multiple definition of `boost::archive::detail::extra_detail::init_guid<EndGame>::g'; /projectPath/build/Register.o:(.bss+0x0): first defined here

And this message repeats for every include; with the file names varying, and the contents of ::init_guid<X> varying as well.

A.D
  • 427
  • 1
  • 4
  • 12
  • Please include the exact error message in the question. Also, what is `_BOOST_INCLUDES_`? I've never seen that before. – Ted Lyngmo Mar 06 '21 at 10:02
  • @TedLyngmo _BOOST_INCLUDES_ is just a header guard I made to try to prevent the includes from being put multiple times by the preprocessor – A.D Mar 06 '21 at 10:07
  • 1
    It looks like you have multiple BOOST_CLASS_EXPORT(EndGame) in your project – rustyx Mar 06 '21 at 10:18
  • @rustyx I've just done a `grep` on `BOOST_CLASS_EXPORT` and I'm finding only 1 occurrence of it, and it happens to be in class `A`'s header file. ` ./projectPath/A.hpp:BOOST_CLASS_EXPORT_GUID(EndGame, "EndGame")` – A.D Mar 06 '21 at 10:28
  • It should not be in a header. – rustyx Mar 06 '21 at 10:52
  • @rustyx Why not ? EndGame here is a struct defined in the header file, and BOOST_CLASS_EXPORT_GUID(...) is put right after it; I didn't write this code, but could you point out why that shouldn't be done ? – A.D Mar 06 '21 at 10:54
  • 1
    Not at my desk atm, try googling "where to put BOOST_CLASS_EXPORT". – rustyx Mar 06 '21 at 11:39
  • Duplicate of https://stackoverflow.com/questions/3396330/where-to-put-boost-class-export-for-boostserialization? – Alan Birtles Mar 06 '21 at 12:32
  • @AlanBirtles Not duplicate, but that is indeed the post rustyx recommended I read; however it is still not 100% clear if this is the same problem or just a part in common – A.D Mar 06 '21 at 12:36
  • *"at linkage I get a multiple definition's error."* -- then stop thinking "header guards". A header guard prevents multiple definitions within a single translation unit (compilation phase). Header guards have no effect across translation unit boundaries (linking phase). – JaMiT Mar 06 '21 at 13:41
  • Please try to create a [mre]. You should be able to get the Boost headers down to a single `#include` and your translation units down to 2 source files. Once you get rid of the noise ("minimal"), it is easier to see what is really relevant, and it should be clear whether or not the other question is a duplicate. You would also be putting the relevant details in the question itself ("reproducible"); at the moment, the speculation about `BOOST_CLASS_EXPORT` relies on information not in your question. – JaMiT Mar 06 '21 at 13:48

1 Answers1

1

Indeed putting BOOST_CLASS_EXPORT in a header file leads to multiply defined symbols as soon as you have included the header file into more than one translation unit (think .cpp file).

In absence of your code, I have many full examples on this site. I'd search like "user:85371 boost_class_export_key":

Most of them have multi-file live demos online and included in the answer text.

sehe
  • 374,641
  • 47
  • 450
  • 633
  • I may be misunderstanding this, but wouldn't my header-guards help for this: "as soon as you have included the header file into more than one translation unit" ? And prevent the second inclusion ? – A.D Mar 08 '21 at 12:21
  • 3
    @A.D Yes, you are misunderstanding. Header guards prevent multiple inclusions of a header _in the same translation unit_. The name says it: a TU is a _unit of translation, so one unit knows nothing about the other, and header guards couldn't possibly work there. After the compiler translation phase, the linker will still see objects all containing the repeated definitions. – sehe Mar 08 '21 at 14:18
  • 1
    Ah ! Header guards for translation units ! It's obvious now that you say it; but it's the first time I've seen someone say it that clearly +1 – A.D Mar 08 '21 at 15:07
  • 1
    I remember when I had the same lightbulb moment. Cheers! – sehe Mar 08 '21 at 15:23