CMake: Enhance checkPandaVersion.h

This removes the requirement that it only be included
in a single C++ file per library, by forcing the compiler
to emit the function that references the version symbol
as a weak symbol itself.  Now, the linker will not only
tolerate redundant inclusions, it will also coalesce them
together.
This commit is contained in:
Sam Edwards 2018-05-16 17:38:13 -06:00
parent b08ab6324e
commit d96765b957

View File

@ -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<typename T>
class CheckPandaVersion {
public:
int check() { return @PANDA_VERSION_SYMBOL@; }
};
template class CheckPandaVersion<void>;
#endif