diff --git a/dtool/src/dtoolbase/checkPandaVersion.h.in b/dtool/src/dtoolbase/checkPandaVersion.h.in index 0986e84b28..d3950d412a 100644 --- a/dtool/src/dtoolbase/checkPandaVersion.h.in +++ b/dtool/src/dtoolbase/checkPandaVersion.h.in @@ -18,7 +18,7 @@ /* Include this file in code that compiles with Panda to guarantee that it is linking with the same version of the Panda DLL's that it - was compiled with. You should include it in one .cxx file only. */ + was compiled with. */ /* We guarantee this by defining an external symbol which is based on the version number. If that symbol is defined, then our DLL's @@ -26,14 +26,39 @@ DLL; but the system linker will prevent the DLL from loading with an undefined symbol. */ +#ifndef CHECKPANDAVERSION_H +#define CHECKPANDAVERSION_H + #include "dtoolbase.h" extern EXPCL_DTOOL_DTOOLBASE int @PANDA_VERSION_SYMBOL@; -#ifndef WIN32 -/* For Windows, exporting the symbol from the DLL is sufficient; the - DLL will not load unless all expected public symbols are defined. - Other systems may not mind if the symbol is absent unless we - explictly write code that references it. */ -static int check_panda_version = @PANDA_VERSION_SYMBOL@; +/* Just declaring the symbol isn't good enough. We need to force the + compiler and linker to preserve the external reference long enough + to end up in the output DLL. Therefore, we have to reference that + symbol somehow. + + Forcing the compiler to include a reference in its output object + file is easy enough: just define a function that makes use of it + in some way. The problem is the linker, which will enforce the + C++ One-Definition Rule and get upset about said definition + appearing in multiple places in the program. We can appease the + linker by forcing the compiler to emit a weak symbol. Many + compilers have syntax to request this explicitly, but since it + varies from compiler to compiler, that wouldn't be very portable. + + Fortunately, the C++ ODR itself has some exceptions, where a + definition can occur in multiple translation units *if and only if* + it's the same definition each time. In these cases, the compiler + must emit a weak symbol, because the ODR does not guarantee that + the same definition isn't repeated in any other translation units. + One such exception is template instantiation, which we use thus: */ +template +class CheckPandaVersion { +public: + int check() { return @PANDA_VERSION_SYMBOL@; } +}; + +template class CheckPandaVersion; + #endif