|
From: Brian Cole on 21 Jul 2008 21:59 I have two libraries, A and B. B includes A.h which has a Meyers singleton implementation like the following: class ClassA { protected: static const ClassA &GetInstance() { static ClassA singleton; return singleton; } }; I then compile the libraries with the following commands: g++ -fPIC -c A.cpp g++ -shared -o libA.so A.o g++ -fPIC -c B.cpp g++ -shared -o libB.so B.o -L. -lA Now why does libB.so have a reference to ClassA::GetInstance when it was told at link time (the last command) to use libA.so? coleb(a)vader~/tests$ ldd libB.so | grep libA libA.so => ./libA.so (0x00002ade269c1000) coleb(a)vader~/tests$ nm libB.so | grep GetInstance 0000000000000690 W _ZN6ClassA11GetInstanceEv 00000000002009dc V _ZZN6ClassA11GetInstanceEvE9singleton coleb(a)vader~/tests$ nm libA.so | grep GetInstance 0000000000000680 W _ZN6ClassA11GetInstanceEv 00000000002009bc V _ZZN6ClassA11GetInstanceEvE9singleton This is causing me problems when I load two separate shared libraries into Python. Python dlopen's shared libraries with RTLD_LOCAL (I'm guessing because it assumes the worst: name conflicts can occur between two unrelated libraries). Python will load libA.so and libB.so. The libA.so singleton will be used when libA is used normally from Python. But when a call is made into libB.so which subsequently makes a call into libA.so a different singleton is returned, violating the singleton semantics. The singleton is actually switching midway through a function call in libB.so. Is there a good reason dlopen("libB.so") does not cause the libA.so ClassA::GetInstance symbol to be used within libB.so? Especially since libB.so was explicitly linked against libA.so. Couple notes: 1) I realize moving the GetInstance implementation into a .cpp file that is compiled into a .o relieves the problem since B.o no longer needs to compile its own version. However, this is not feasible if ClassA is a template. 2) I know making python dlopen with the RTLD_GLOBAL flag solves the problem. But how is this a desirable solution as it requires the library user to know about implementation details of libB? -Brian
From: Giorgos Keramidas on 21 Jul 2008 23:58 On Mon, 21 Jul 2008 18:59:59 -0700 (PDT), Brian Cole <coleb2(a)gmail.com> wrote: > I have two libraries, A and B. B includes A.h which has a Meyers > singleton implementation like the following: [...] > Python will load libA.so and libB.so. The libA.so singleton will be > used when libA is used normally from Python. But when a call is made > into libB.so which subsequently makes a call into libA.so a different > singleton is returned, violating the singleton semantics. The > singleton is actually switching midway through a function call in > libB.so. > > Is there a good reason dlopen("libB.so") does not cause the libA.so > ClassA::GetInstance symbol to be used within libB.so? Especially since > libB.so was explicitly linked against libA.so. > > Couple notes: > 1) I realize moving the GetInstance implementation into a .cpp file > that is compiled into a .o relieves the problem since B.o no longer > needs to compile its own version. However, this is not feasible if > ClassA is a template. > 2) I know making python dlopen with the RTLD_GLOBAL flag solves the > problem. But how is this a desirable solution as it requires the > library user to know about implementation details of libB? RTLD_GLOBAL is a pretty heavy axe to grind in this case. Maybe you can hack around this by a 'libmyloader.so' that runs dlopen(RTLD_LOCAL) on both libA.so and libB.so?
From: Paul Pluzhnikov on 22 Jul 2008 22:39 Brian Cole <coleb2(a)gmail.com> writes: > Now why does libB.so have a reference to ClassA::GetInstance when it > was told at link time (the last command) to use libA.so? On ELF platforms, gcc by default instantiates every inline method as a weak symbol in every compilation unit in which that symbol is visible to gcc. The linker then discards duplicates from multiple objects, while linking a shared library or an executable. AFAIK, the linker pays no attention to the fact that the same symbol is already defined in a shared library included later on the link line. Without RTLD_LOCAL, it all works as one would expect. With RTLD_LOCAL, you'd better know what you are doing :( Some other possible solutions: A. merge libA.so and libB.so into a combined library. B. if libB.so doesn't actually use ClassA::GetInstance(), compile it with -ffunction-sections -fdata-sections and link with -Wl,--gc-sections,-O Cheers, -- In order to understand recursion you must first understand recursion. Remove /-nsp/ for email.
|
Pages: 1 Prev: Problem with read(2) and pseudo-terminals Next: gdb vs fortran RTL -- fight for SIGSEGV |