sil2100//vx developer log

Welcome to my personal web page

C++ symbols in debian/symbols files. Symbol export maps

When developing a C++ library that we later intend to provide by means of a Debian package, there are certain things that make it really complicated and hard to maintain. Everyone that had to deal with debian/symbols in a C++ library knows how troublesome it is. The biggest problem besides name mangling: symbols leakage. By default the GNU ELF linker exports everything as it goes, leading to maintenance hell. Sadly, this has to be dealt with on the source level - the best way? Symbol export maps.

2014-03-17 20:04

Empty

This, by any chance, is nothing new. We encountered this problem because symbol export maps is not popular enough. At least most of the C++ projects I had contact with packaging-wise were either not shipping any debian/symbols files or were exporting, like, everything. dpkg-gensymbols is usually generating enormous symbols files which are then used to generate the symbols for the packaging side - after demangling the names and preparing them for C++ (see here for details on name demangling).

As mentioned before - by default the linker on GNU/Linux systems exports all symbols automatically, which does not happen in case of DLLs. We can stop that from happening on various ways: by using gcc-specific source-code stanzas or by using symbol export maps. The second approach sounds a bit better as the source code is not bloated with any additional stanza. How can a symbols export map look? Let me provide a real world example, coming from Thomas Voss and his dbus-cpp project:


 {
 global:
     extern "C++" {
         core::dbus::*;
         typeinfo?for?core::dbus::*;
         typeinfo?name?for?core::dbus::*;
         VTT?for?core::dbus::*;
         virtual?thunk?to?core::dbus::*;
         vtable?for?core::dbus::*;
         std::hash*;
     };
 local:
     extern "C++" {
         *;
     };
 };

Symbol export maps are called LD Version Scripts in the gnulib and can be used for both C and C++, as well as additionally for ABI versioning. The latter is also very important, but let's concentrate only on symbol export for this post.

First o all, we need to warn the linker that the names will be mangled as for all C++ - we can do that through the extern "C++". Then, everything that we put in the global: scope will be exported. Everything else that is mentioned in the local: scope will be hidden. The rest is simply using wildcards for which symbols should be considered in which scope. In our example the local scope has *, as an indication for: "everything that's not in global should be hidden". And all the other stuff? Anyone that was managing any C++ debian/symbols files knows the presented naming. Besides exporting actual types and symbols from their namespaces, we also try remembering about their typeinfo and vtables. Some STL types that might be useful should also be considered for exporting.

What we should do next is simply pass our map file to the linker by using --version-script=symbols.map. And then we can finally have a maintainable, sane C++ symbols file in our packaging. It still requires some time and thought, but at least we won't have to export all the STL symbols that we actually only use locally. Phew.