1

Currently I am trying to implement an ELF shared library, built with -static-libstdc++ and -static-libgcc options. This shared library MUST be built with C++11 and it has some legacy code, besides, it has a very specific design.

If some application links this shared library, their C++ utilities MUST NOT interfere with each other. For example, std::cout-related, and hence, std::ios_base::Init::Init() (_ZNSt8ios_base4InitC1Ev), are awaited to be present in two independent implementations, one static for this specific shared library, and another shared one for the application and it's other shared libraries. However, LD_DEBUG=all usage shows that there this specific shared library's C++ utility symbols, like std::ios_base::Init::Init(), get bound to the symbols, defined in libstdc++, which I try to avoid...

Can such logic be implemented or at least worked around somehow? In any case, I DO NEED separate C++ utility. Thanks in advance!

  • A static library is really nothing more than an archive of object files. When you link with a static library, its like linking with the individual object files. When you link with a static library, it becomes an integral part of your executable or shared library. Unfortunately that means global data in your library *will* clash with global data from the process your library is running with. Besides that, a library really shouldn't be using global state, including `std::cout`. If the library needs to use a stream, let the host process pass it in using some kind of initialization function. – Some programmer dude Jun 27 '23 at 16:13

1 Answers1

2

Currently I am trying to implement an ELF shared library, built with -static-libstdc++ and -static-libgcc options.

Your best bet is to not do that -- link your library "normally" (so it depends on libstdc++.so.6 and libgcc_s.so.1), and most of your problems would disappear. (See also http://xyproblem.info -- why do you want to link libstdc++ statically?)

However, LD_DEBUG=all usage shows that there this specific shared library's C++ utility symbols, like std::ios_base::Init::Init(), get bound to the symbols, defined in libstdc++

This statement is meaningless when you have two copies of libstdc++ -- one inside your library, and one "outside" (presumably libstdc++.so.6).

What you probably mean is that references to std::ios_base::Init::Init() from your library get bound to definitions inside libstdc++.so.6.

You can avoid this by making all symbols inside your library hidden, and only exposing the "official" interface from it, using linker script. See this answer.

Note:

  • Controlling the ABI of a C++ shared library is much harder than for a pure-C one
  • If you "hide" libstdc++ inside your shared library, and pass C++ objects through the interface (e.g. a std::string or std::map), you can expect all kinds of ~impossible to debug issues due to ABI incompatibility between the "hidden" libstdc++.a and the external libstdc++.so.6.
Employed Russian
  • 199,314
  • 34
  • 295
  • 362
  • Wow, this is exactly what I needed! Thank you ever so much! Using the linker script has helped, now all those externally visible C++ symbols are hidden, as intended. Note this is fairly _abnormal_ programming. Related build options are: `-shared -fPIC -static-libgcc -static-libstdc++ -Wl,--version-script=libfoo.version`. – DumbStudent2016 Jun 30 '23 at 16:02