I am writing an application and I would like to use GCC 4.8 on rhel7. My problem is that I need to use a 3rd party shared lib which was built using GCC 4.4 built on rhel6.
Someone suggested I create an interface between my app
and the library using extern "C" to avoid ABI issues of going between c++03
to c++11, and only pass simple C structs in the interface.
That's a meaningful suggestion as it's too hard to preserve ABI compatibility in C++ interfaces.
But they also suggested its possible I might have to copy and link
libstdc++ and libgcc from the rhel6 machine since the 3rd party lib
(and my interface) is built using those. This is where I am confused.
Both libgcc and libstdc++ preserve backwards compatibility (unless in GCC5 but that's not your case) so the 3rd party lib should work just fine with RHEL7 libs.
Given that the major version (libName.so.major.minor.x.z) of libstdc++
and libgcc is the same on rhel6 and 7, do I really need to copy them
from rhel6 to 7?
No (see above).
Cant I build my interface on rhel6, and just copy it along
with 3rd party lib to rhel7 (without copying old libstdc++/libgcc)?
Yes, this will work.
I mean, since stuff built using old libstdc++/libgcc
should be forward compatiable, no?
Correct (they usually say that "new versions of standard libs are backwards compatible i.e. software compiled with older libs will continue to work").
Can I run into issues (ABIs)?
If you somehow manage to pass STL object created in one libstdc++ to another you'll have weird errors. But if both your and 3rd party library have pure C interfaces this should not be an issue (as there's no way for STL objects to escape their containing libraries).
If I do need to copy libstdc++ and libgcc from rhel6,
and link new and old versions together -- how do i do that?
will there suggestion of statically linking the new versions work?
This would be unnecessary burden.
Related
I am having a difficult time configuring an iOS project which uses a static library linked against the old libstdc++ that gcc used. That library is 32 and 64-bit.
There are 6 libraries (libssl.a for example) that are 32-bit and must be updated. If I compile those libraries from source, they will be automatically linked with libc++, which will result in my linker complaining.
Therefore, here are my questions:
1) Is there any way to have a single static library inside the project use libstdc++, and have the others use libc++?
2) How can I compile libraries from source (like libcrypto and libssh) and force them use the old libstdc++ standard library?
3) Is there any other way out of this mess?
1) Yes, you can certainly mix and match which C++ runtimes your C++ code uses so long as those separate modules don't actually pass objects between each-other. For example, if you have two modules in your app which just expose C APIs but internally use C++, then each can use whichever C++ runtime they want. Problems occur when trying to share objects between the runtimes.
2) You can use the '--stdlib=libstdc++' or '--stdlib=libc++' command line argument when compiling and linking to specify which C++ library to use. If your final executable needs to link against both, you'll need to manually specify the other one (eg: --stdlib=libc++ -lstdc++).
3) Yep, but note that libstdc++ was deprecated years ago and isn't even available on watchOS nor tvOS, so your best bet is to just get everything over to libc++.
As long as you don't mix objects (like passing a string from one library into a function that expects a different kind of string), you can do it by including both libraries when you build the top-level app.
In my case, it worked by setting the standard C++ lib to the GNU version and then adding libc++ as I would any other system library.
Having gone through a number of similar questions (see below), I don't think any of them cover this case.
Problem
Is it possible to dlopen and use a C++11 shared library compiled using gcc 4.9 from a C++03 application compiled with gcc 4.1? Both the library and application use libstdc++, including on the API (but not std::list, which is apparently a problem). I can't change the way the application is compiled (sadly), and must be certain that existing code doesn't break (e.g. if it ends up dynamically linking to a new version of libstdc++.so).
As far as I understand it (which is not very), on Linux the dynamic linker uses a flat namespace, meaning that is not possible to have the same symbol defined in two libraries. Does statically linking the library against the newer libstdc++ help at all here, or is there perhaps some other way?
Some similar questions that don't seem to answer this
C++11 backwards compatibility
C++03 library with C++11 source code
C++11 compatibility with existing libraries/frameworks
Can a compiled C++11 library (lib,dll,etc.) be linked in older C++ compilers? [softwareengineering.stackexchange.com]
If you do that, you definitely need to use the newer libstdc++.so.6, which should be compatible with the system libstdc++.so.6 based on GCC 4.1 (in the sense that GCC upstream intends to preserve ABI compatibility for the library). It would be a very good idea to use the libstdc++.so.6 library that came with the GCC 4.9 compiler.
Once you do that, it is supposed to work, unless you hit the few of the compatibility gotchas you already listed, and as long as the C++ part of the library interface actually sticks to the C++98 subset and does not use any constructs which are not expressible in the language subset.
All this assumes that the library was actually compiled on the the system which uses GCC 4.1, which probably has something like glibc 2.5. If the library was compiled on a completely different, newer system, then you will likely run into library compatibility issues beyond libstdc++.so.6, and these libraries tend to be even harder to upgrade.
(There is also the possibility that the library was explicitly compiled for use with the 4.1-based system libstdc++.so.6 and everything just works, just as if by magic, but then you wouldn't be asking here, I suppose.)
If you still have problems there is the option to use a statically linked C-API library as border between the two, application and your library, see this post.
Also you may be able to explicitely demand an old version of a symbol, see this post
GCC is great with ABI-compatibility as long as you use the same C++ standard [1].
But it strikes me that if a shared library compiled by GCC 4.3 in C++03 mode exposes, say, a std::string, this is going to be a different std::string than that understood by an executable compiled by GCC 4.8 in C++11 mode.
The reason I ask is that I am planning to deploy a program compiled by GCC 4.8 in C++11 mode on CentOS 6, whose maximum packaged GCC is 4.3... and some of the shared libraries (be they third-party C++ libraries or more system-level stuff) will presumably therefore all be C++03. But if that were the case, we'd never be able to deploy any C++11 programs on older Linux distributions, which seems unlikely.
Am I naive to think there might be a problem here? And, if there is, how can I resolve it?
There is a wonderful page on this matter: https://gcc.gnu.org/wiki/Cxx11AbiCompatibility
In short, C++11 in gcc is mostly ABI compatible with c++98, but there are a couple of mismatches. Page above lists all of those.
To alleviate the issue I can suggest following approach:
Clearly identify all your dependencies which are C++ libraries. You usually do not have too many of them - boost comes to mind first, do you have anything else?
Than you check if the symbols your app needs are in the list of broken ABI (see above). If they are not, you are in the clear.
If they are, you recompile the lib, and either distribute it as shared lib together with your app (playing with Rpath flags to make sure your app loads your version) or link statically against it.
Just in case, you might as well link statically against libstdc++.
Actually, you can distribute a program compiled with a newer g++ compiler on a vanilla CentOS 6 platform. There are several ways to do this: The easiest is to use the DevToolset 3, which will give you g++ 4.9.2 (the dev toolset 2 will give you gcc 4.8.2). Then, just compile your application with this g++. When distributing your software, you need to make sure to also ship the libstdc++.so that is being shipped with g++ 4.9. Either set the LD_LIBRARY_PATH so it gets picked up on startup, or set the RPATH to tell your executable where to look first for libraries.
Essentially, you can do this also with newer compilers, but then you first need to compile the compiler itself. If you don't want to compile a compiler first, go with a respective dev toolset and you should be fine.
Yes, you can also try to statically link libstdc++.a. Search for the option -static-libstdc++:
When the g++ program is used to link a C++ program, it normally automatically links against libstdc++. If libstdc++ is available as a shared library, and the -static option is not used, then this links against the shared version of libstdc++. That is normally fine. However, it is sometimes useful to freeze the version of libstdc++ used by the program without going all the way to a fully static link. The -static-libstdc++ option directs the g++ driver to link libstdc++ statically, without necessarily linking other libraries statically.
But if you statically link, you will not get any security updates etc. Granted, you will not get the updates, if you ship libstdc++.so on your own as well, but incremental updates maybe easier.
And with respect to running your application: The rule of thumb is: Compile on the oldest platform you need to support, then your binaries (with self-shipped libstdc++ and other required libs) will likely work also on newer versions. That is, if you compile on CentoOS 6, and it works, then you can expect it to also work on CentOS 7. On a related subject, this is exactly the reason why for instance AppImage and related solutions recommend to build on an old system.
In my company we use gcc 5.1.0, compiled and used on CentOS 5.5 (with old gcc on-board).
When we deploy our application we also redistribute libstdc++.so and libgcc_s.so, compiled from gcc 5.1.0 sources.
For example:
/opt/ourapp/lib/libstdc++.so
/opt/ourapp/lib/libgcc_s.so
/opt/ourapp/bin/myapp
And for starting the binary correctly we execute:
LD_LIBRARY_PATH=/opt/ourapp/lib/ myapp.
Hope it helps.
Drawbacks:
At least you can't use native gdb on such an environment because DWARF format incompatibilities.
If you build your C++11 program with the define _GLIBCXX_USE_CXX11_ABI=0 (see this) and the option --abi-version=2 (see this) you should be compatible with any library build with GCC 4.3, including libstdc++.
The default ABI version was 2 through 4.9, it seems like a safe assumption that CentOS uses the default ABI.
The _GLIBCXX_USE_CXX11_ABI macro will affect the standard library's types, to use the same layout as the pre C++11 version. This will introduce some C++11 conformance issues (the reason why they were changed in the first place), things like the complexity of std::list<>::size().
The --abi-version= command line option affects the compiler's ABI, calling conventions, name mangling etc. The default ABI was 2 from 3.4 through 4.9.
I am currently writing a library and am considering moving from GCC 4.1.2 to 4.5.2 (latest release) of GCC. If I compile my code into a static library can I assume compiler compatibility (on the same OS obviously) should be a non-issue for clients?
EDIT
To further clarify: if I provide a client a statically linked library compiled with gcc 4.5.2, what restrictions does this place on users of this library in terms of the compiler and version they must use?
Just came across this which I believe answers my question from http://gcc.gnu.org/bugs/#nonbugs:
ABI changes The C++ application binary
interface (ABI) consists of two
components: the first defines how the
elements of classes are laid out, how
functions are called, how function
names are mangled, etc; the second
part deals with the internals of the
objects in libstdc++. Although we
strive for a non-changing ABI, so far
we have had to modify it with each
major release. If you change your
compiler to a different major release
you must recompile all libraries that
contain C++ code. If you fail to do so
you risk getting linker errors or
malfunctioning programs. Some of our
Java support libraries also contain
C++ code, so you might want to
recompile all libraries to be safe. It
should not be necessary to recompile
if you have changed to a bug-fix
release of the same version of the
compiler; bug-fix releases are careful
to avoid ABI changes. See also the
compatibility section of the GCC
manual.
Remark: A major release is designated
by a change to the first or second
component of the two- or three-part
version number. A minor (bug-fix)
release is designated by a change to
the third component only. Thus GCC 3.2
and 3.3 are major releases, while
3.3.1 and 3.3.2 are bug-fix releases for GCC 3.3. With the 3.4 series we
are introducing a new naming scheme;
the first release of this series is
3.4.0 instead of just 3.4.
From this as I understand it I'll need to ensure clients are linking my library in with a major-release compatable version of gcc.
It doesn't really matter if you are providing a static library or dynamic library, the users will still need to use a compatable compiler/linker to link against it. Usually when GCC does a ABI change they offer a switch that can be set to use the old ABI. I know that they did that when they went from 3.x to 4.x and even a couple of the releases within the 4.x series.
I'm writing a cross-platform application which is not GNU GPL compatible. The major problem I'm currently facing is that the application is linked dynamically with glibc and libstdc++, and almost every new major update to the libraries are not backwards compatible. Hence, random crashes are seen in my application.
As a workaround, I distribute binaries of my application compiled on several different systems (with different C/C++ runtime versions). But I want to do without this. So my question is, keeping licensing and everything in mind, can I link against glibc and libstdc++ statically? Also, will this cause issues with rtld?
You don't need to.
Copy the original libraries you linked against to a directory (../lib in this example) in your application folder.
Like:
my_app_install_path
.bin
lib
documentation
Rename you app for something like app.bin. Substitute your app for a little shell script that sets the enviroment variable LD_LIBRARY_PATH to the library path (and concatenate the previous LD_LIBRARY_PATH contents, if any). Now ld should be able to find the dynamic libraries you linked against and you don't need to compile them statically to your executable.
Remember to comply with the LGPL adding the given attribution to the libraries and pointing in the documentation where the source can be downloaded.
glibc is under the LGPL. Under section 6. of LGPL 2.1, you can distribute your program linked to the library provided you comply with one of five options. The first is to provide the source code of the library, along with the object code (source is optional, not required) of your own program, so it can be relinked with the library. You can alternatively provide a written offer of the same. Your own code does not have to be under the LGPL, and you don't have to release source.
libstdc++ is under the GPL, but with a major exception. You can basically just distribute under the license of your choice without providing source for either your own code or libstdc++. The only condition is that you compile normally, without e.g. proprietary modifications or plugins to GCC.
IANAL, and you should consider consulting one if you need real legal advice.
Specifying the option -static-libgcc to the linker would cause it to link against a static version of the C library, if available on the system. Otherwise it is ignored.
I must question what the heck you are doing with the poor library functions?
I have some cross platform software as well. It runs fine on Linux systems of all sorts. Build with the oldest version of software that you want to support. The glibc and libstdc++ libraries are really very backward compatible.
I have built on CentOS 4 and run it on RHEL 6 beta. No problems.
I can build on stable Debian and run it on testing.
Now, I do sometimes have trouble with some libraries if I try to build on, say old Debian and try to run it on CentOS 5.4. That is usually due to distribution configuration choices that are different, like choosing threading or non-threading.