From: Alexey Sheplyakov Date: Wed, 6 Jan 2021 07:20:46 +0000 (+0400) Subject: Avoid multiple definitions of `lst::info` (MinGW compile fix) X-Git-Tag: release_1-8-1~14 X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=commitdiff_plain;h=c3195f0b5a7ac9fdbfdd04e5f4acf6a836063de0 Avoid multiple definitions of `lst::info` (MinGW compile fix) [55/59] Linking CXX shared library bin/libginac.dll FAILED: bin/libginac.dll ginac/libginac.dll.a [skipped long list of object files] /usr/bin/x86_64-w64-mingw32-ld: ginac/CMakeFiles/ginac.dir/lst.cpp.obj: in function `GiNaC::ptr::~ptr()': /home/asheplyakov/work/sw/ginac/_build_w64/../ginac/container.h:150: multiple definition of `GiNaC::container::info(unsigned int) const'; ginac/CMakeFiles/ginac.dir/integration_kernel.cpp.obj:/home/asheplyakov/work/sw/ginac/_build_w64/../ginac/container.h:116: first defined here integration_kernel.cpp makes use of GiNaC::lst without including the `lst.h` header. That's possible since there's a typedef in `registrar.h` (included by virtually all GiNaC sources) and a defintion in `container.h` (included via `add.h` -> `expairseq.h` -> `indexed.h` -> `exprseq.h`), so the compiler can instantiate container. However the explicit specialization of `lst::info` is not available (in integration_kernel.cpp). This violates 17.8.3.6 [templ.expl.spec] which demands If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required. If the program does not provide a definition for an explicit specialization and either the specialization is used ina way that would cause an implicit instantiation to take place or the member is a virtual member function, the program is ill-formed, no diagnostic required. On ELF platforms libginac appears to link just fine despite having two instantiations of `lst::info` since the of them (in `integration_kernel.o`) is a weak symbol: $ find ginac -type f -name '*.o' | xargs -n 1 nm --print-file-name --defined | c++filt | grep -e 'list>::info(' ginac/CMakeFiles/ginac.dir/integration_kernel.cpp.o:0000000000000000 W GiNaC::container::info(unsigned int) const ginac/CMakeFiles/ginac.dir/lst.cpp.o:0000000000000000 T GiNaC::container::info(unsigned int) const so the linker discards the wrong instantiation of `lst::info` method. However on MinGW there are no weak symbols (in ELF sense): $ find ginac -type f -name '*.obj' | xargs -n 1 x86_64-w64-mingw32-nm --print-file-name --defined | c++filt | grep -e 'list>::info(' ginac/CMakeFiles/ginac.dir/lst.cpp.obj:0000000000000010 T GiNaC::container::info(unsigned int) const ginac/CMakeFiles/ginac.dir/integration_kernel.cpp.obj:0000000000000000 T GiNaC::container::info(unsigned int) const Hence the above multiple definition error. To avoid the problem #include "lst.h" (so explicit specialization is available). While at it explicitly instantiate lst::info method in lst.cpp A better solution would be to remove declaration of lst from registrar.h, but that's too disruptive since GiNaC uses lst a lot: subs, unarchive, etc. --- diff --git a/ginac/integration_kernel.h b/ginac/integration_kernel.h index 1e49338c..4a8b5658 100644 --- a/ginac/integration_kernel.h +++ b/ginac/integration_kernel.h @@ -26,6 +26,7 @@ #include "basic.h" #include "archive.h" #include "numeric.h" +#include "lst.h" #include #include diff --git a/ginac/lst.cpp b/ginac/lst.cpp index 5ea42bc8..9397e351 100644 --- a/ginac/lst.cpp +++ b/ginac/lst.cpp @@ -38,6 +38,7 @@ template <> bool lst::info(unsigned inf) const return inherited::info(inf); } +template bool container::info(unsigned) const; GINAC_BIND_UNARCHIVER(lst); } // namespace GiNaC diff --git a/ginac/lst.h b/ginac/lst.h index b6badee9..8591861c 100644 --- a/ginac/lst.h +++ b/ginac/lst.h @@ -42,6 +42,7 @@ template<> inline char lst::get_close_delim() { return '}'; } // defined in lst.cpp template<> bool lst::info(unsigned inf) const; +extern template bool container::info(unsigned) const; GINAC_DECLARE_UNARCHIVER(lst); } // namespace GiNaC