Binding libstdc ++ statically: any errors?

I need to deploy a C ++ application based on Ubuntu 12.10 with GCC 4.7 libstdC ++, on systems running Ubuntu 10.04, which comes with a significantly older version of libstdC ++.

I am currently compiling with -static-libstdc++ -static-libgcc , as suggested in this blog post: Linking libstdC ++ is static . The author warns about using any dynamically loaded C ++ code when compiling libstdC ++ statically, which I have not yet verified. However, everything seems to be going smoothly so far: I can use the features of C ++ 11 on Ubuntu 10.04, which was after.

I note that this article has been from 2005, and perhaps a lot has changed since then. Is his advice still relevant? Are there any hidden issues that I should know about?

+79
c ++ gcc linux libstdc ++ static-libraries
Nov 29 '12 at 23:12
source share
5 answers

This blog post is pretty inaccurate.

As far as I know, C ++ ABI changes were introduced with each major release of GCC (i.e. with different components of the first or second version number).

Not true. The only C ++ ABI changes introduced since GCC 3.4 were backward compatible, which means that C ++ ABI has been stable for almost nine years.

In the worst case, most major Linux distributions use GCC snapshots and / or fix their GCC versions, so it’s almost impossible to know exactly which versions of GCC you can have when distributing binary files.

The differences between the fixed versions of GCC for distributions are minor, and not a change of ABI, for example. Fedora 4.6.3 20120306 (Red Hat 4.6.3-2) is an ABI compatible with versions of FSF 4.6.x and higher, and almost certainly with any 4.6.x from any other distribution.

The GNU / Linux GCC runtime libraries use ELF character version control, so it's easy to check the character versions needed by objects and libraries, and if you have libstdc++.so that provides these characters, it will work, no matter, this is a slightly different fixed version from another version of your distribution.

but C ++ code (or any code that uses C ++ runtime support) can be linked dynamically if necessary.

This is also not true.

However, static binding to libstdc++.a is one option for you.

The reason this might not work if you dynamically load the library (using dlopen ) is because the libstdC ++ characters that it depends on may not be needed by your application when you are (statically) linked to it, therefore, these characters will not be present in your executable file. This can be solved by dynamically linking the shared library to libstdc++.so (which in any case must be done if it depends on it). ELF character substitution means that characters present in your executable file will be used by the shared library, but others not present in your executable file will be found depending on what type of libstdc++.so it refers to. If your application does not use dlopen , you do not need to worry about it.

Another option (and one that I prefer) is to deploy the new libstdc++.so next to your application and make sure that it is found before the default system libstdc++.so , which can be done by forcing the dynamic linker to look at the right, or using the environment variable $LD_LIBRARY_PATH at run time, or by setting RPATH in the executable at the time of the link. I prefer to use RPATH as it does not rely on the proper environment setting for the application to work. If you linked your application with '-Wl,-rpath,$ORIGIN' (note the single quotes to prevent the shell from expanding with the $ORIGIN extension), then the executable will have RPATH from $ORIGIN , which tells the dynamic linker to look for shared libraries in the same directory as the executable itself. If you put the new libstdc++.so in the same directory as the executable file, it will be found at runtime, the problem will be solved. (Another option is to put the executable in /some/path/bin/ and the new libstdC ++, so in /some/path/lib/ and the link with '-Wl,-rpath,$ORIGIN/../lib' or any another fixed location relative to the executable and set RPATH relative to $ORIGIN )

+118
Dec 29
source share

Another addition to Jonathan Wakeley, the excellent answer is why dlopen () is problematic:

Due to the new exception handling pool in GCC 5 (see PR 64535 and PR 65434 ), if you delete and close a library that is statically linked to libstdc ++, you will receive a memory leak (of the pool object) each time. So if there is a chance that you will ever use dlopen, it seems that a static link is a really bad idea of ​​libstdc ++. Please note that this is a real leak, unlike the benign one mentioned in PR 65434 .

+9
Jan 26 '16 at 13:52
source share

You may also need to make sure that you are not dependent on dynamic glibc. Run ldd in your executable file and look for any dynamic dependencies (libc / libm / libpthread are suspected of being used).

An additional exercise would be to create a bunch of involved C ++ 11 examples using this methodology, and actually try to get the binary files in a real 10.04 system. In most cases, if you are not doing something strange with dynamic loading, you will immediately know if the program is working or it will work.

+2
Nov 29 '12 at 23:34
source share

I would like to add to Jonathan Wakeley the answer to the following question.

Playing -static-libstdc++ on Linux, I ran into the dlclose() problem. Suppose we have application "A" statically linked to libstdc++ and it loads dynamically, linked to libstdc++ "P" at runtime. It's great. But when "A" unloads "P", a segmentation error occurs. I assume that after unloading libstdc++.so "A" can no longer use the symbols associated with libstdc++ . Please note that if β€œA” and β€œP” are statically linked to libstdc++ , or β€œA” is linked dynamically, and β€œP” is static, the problem does not occur.

Summary: if your application loads / unloads plugins that can dynamically link to libstdc++ , the application must also be dynamically linked to it. This is just my observation, and I would like to receive your comments.

0
Feb 27 '19 at 19:16
source share

Addition to Jonathan Wakeley's answer regarding RPATH:

RPATH will only work if the RPATH in question is the RPATH of the running application . If you have a library that dynamically links to any library through its own RPATH, the RPATH library will be overwritten by the RPATH of the application that loads it. This is a problem where you cannot guarantee that the RPATH application matches the RPATH of your library, for example, if you expect your dependencies to be in a specific directory, but that directory is not part of the RPATH application.

For example, let's say you have an App.exe application that is dynamically linked to libstdc ++. So.x for GCC 4.9. App.exe resolves this dependency via RPATH, i.e.

 App.exe (RPATH=.:./gcc4_9/libstdc++.so.x) 

Now suppose that there is another Dependency.so library that has a dynamically linked dependency on libstdc ++. So.y for GCC 5.5. Dependence here is resolved through RPATH libraries, i.e.

 Dependency.so (RPATH=.:./gcc5_5/libstdc++.so.y) 

When App.exe loads Dependency.so, it does not add or add RPATH libraries . It does not cope at all. The only RPATH under consideration will be the running application or App.exe in this example. This means that if the library uses characters that are in gcc5_5 / libstdc ++. So.y but not in gcc4_9 / libstdc ++. So.x, the library will not be able to load.

This is a warning, as I myself have encountered these problems in the past. RPATH is a very useful tool, but there are still some bugs in its implementation.

0
Jun 19 '19 at 17:24
source share



All Articles