I've recently been dealing with a C++ library to interface with our stock market data provider for real-time information. The wire-protocol is open and documented, but this library is closed source and unmaintained with the only alternative being to read the hard to understand protocol docs and to experiment a lot.
We needed to be able to run and test the application locally which resulted in my colleague to build Gcc 3.x from scratch to be able to compile our app and link against the library.
Obviously the real solution here is to provide the source code for the library, or to provide a C library (with an inherently more stable ABI), but that's not going to happen any time soon probably for political reasons.
Once you have the right version of gcc or a backdated version of libstdc++ to link against there are two roads you can go down. One is to link both versions of libstdc++, version 5 for the library and version 6 for your application. The other is to compile your application against the same version of libstdc++ as the library.
Linking both versions
Not only am I using a different version of libstdc++ by default with Gcc 4.1, but 4.1 uses a separate ABI version introducing even more incompatibilities. The symptoms for this are that any symbols defined in the old library you're linking against will come up as undefined.
The way to solve this is to force Gcc to output symbols with the old ABI naming style, this can be done with:
-fabi-version=1
And now C++ symbols in libstdc++ v5 which are referenced in the old library will not be found, so you have to manually link libstdc++.so.5 in, usually passing it directly in while linking:
$(LINK) -o $@ $(LDFLAGS) /usr/lib/libstdc++.so.5 $+This introduces yet another problem, objects from either versions of libstdc++ being leaked into each other which will result in your program crashing and burning. Luckily in our case the library was self contained and only took parameters in regular C types or references to objects defined in it's only library. I didn't manage to do much testing on this though, so it may have still crashed at some point and I recommend using the alternative approach.
Linking correctly
I'm sure there's a way to make Gcc 4.1 link against the standard library provided by Gcc 3.2, but I haven't been able to work it out so far. So I installed the backported Gcc 3.2 package provided by Ubuntu - which is probably cheating a bit and wouldn't be suitable if you had code which depended on Gcc 4.x features.
So that solves the linking issues, but to go one step further and making this executable run on more systems without having to resolve stupid dependency problems I decided to statically link the libstdc++ library, meaning all unresolved external symbols remaining are in libc and libm etc. using the C ABI.
Johan Petersson provides a good reference on how this can be done, which essentially just specifies -static-libgcc and links libstdc++.a directly. More information can be found at his article on linking libstdc++ staticly.
After linking, the dependencies look like:
linux-gate.so.1 => (0xffffe000)
libmysqlclient_r.so.15 => /usr/lib/libmysqlclient_r.so.15 (0xb7dbc000)
libz.so.1 => /usr/lib/libz.so.1 (0xb7da7000)
libm.so.6 => /lib/tls/i686/cmov/libm.so.6 (0xb7d81000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7c37000)
libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0xb7c1f000)
libcrypt.so.1 => /lib/tls/i686/cmov/libcrypt.so.1 (0xb7bf1000)
libnsl.so.1 => /lib/tls/i686/cmov/libnsl.so.1 (0xb7bd9000)
/lib/ld-linux.so.2 (0xb7fbb000)
Which should be compatible with all current, previous & future versions of LSB where MySQL is provided.
Leave a Reply