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.
Related
There are dynamic libraries provided by others, which are out of my control. What I know is that most of the aforementioned libraries are compiled
by g++4.9.4 & g++4.8.4 with C++11 support, and few libraries are
compiled by g++11.1.0 with C++14 support. And I have to use newer g++ which supports C++17 to compile my project. I intend to use g++11.3.0 on Ubuntu20.4.
Is there any potential problem I should be aware of when linking to dynamic libraries compiled by the said old version g++?
TL;DR: the dynamic library linkage you describe should "just work", provided you link the executable using the newer version of g++.
Both versions of GNU g++ you mention use libstdc++ (specifically libstdc++.so.6.0.*) to implement the support libraries needed for C++11/C++17.
For the most part, newer versions of libstdc++ maintain what their ABI policy manual calls "forward compatibility":
Versioning gives subsequent releases of library binaries the ability to add new symbols and add functionality, all the while retaining compatibility with the previous releases in the series. Thus, program binaries linked with the initial release of a library binary will still run correctly if the library binary is replaced by carefully-managed subsequent library binaries. This is called forward compatibility.
There are a few caveats, for unusual cases (which are probably irrelevant to your situation):
This assumes all the objects are built with compatible CPU ABI/architecture flags (i.e. -march, -mcpu, -m64, etc. if any), which is a general requirement for correctly linking libraries together (regardless of compiler version). The compiler defaults for these options should select compatible settings for your system, so this challenge usually only arises with cross-compilation scenarios where you've deliberately changed to a non-default ABI.
The internal representation of some C++ library classes (eg std::string, std::list) have changed over time, which can lead to problems if two libraries are sharing access to the same C++ object. This should only be a problem if you pass C++ library objects or references to them across the library interface where the g++ version differs.
Versions of gcc before 5.1 did not fully support C++11. They could not possibly. The ABI needed to support C++11 was not ready.
See this article for more information.
If you have object files compiled with gcc <5.1 and object files compiled with gcc >=5.1 (on default ABI settings), and they somehow share data that contain std::string and/or std::list objects, then they cannot work together. You need to recompile at least some of them.
In many cases you will get linker errors, and in some other (rare) cases the program will compile, link, and have mysterious crashes at run time. You probably should not worry about these cases as they are unlikely to occur naturally with normal libraries.
If there are no shared std::string or std::list involved, then you might be able to get away with it. However there are corner cases.
If you have a shared library dynamically linked with libstdc++.5.x. and another one dynamically linked to libstdc++.6.x, the final executable will be indirectly linked with both. This could be a problem in some cases. Try LD_PRELOADing one or the other to establish precedence.
I've written a fairly substantial C++11 library, and I'm planning to allow download of pre-compiled versions from my website.
So I've set up an automated build which compiles the library with clang and make it available for download, but this has exposed a problem: if I try to use the clang-compiled library with GCC I get undefined references (mainly related to std::string). I think this is related to the GCC dual-ABI changes in GCC 5.1 but I'm not sure how to fix it.
My question is, what flags should I set, or practices should I follow to make a C++ library compatible with both clang and GCC?
Or should I give up and compile two separate libraries?
As already mentioned in several places (eg. here) libc++ is not fully binary compatible with libstdc++.
There are several options, but some of them are somewhat not-so-straightforward.
Compile two separate libraries - always working solution.
Remove incompatible containers from your interface (eg. std::string) - but this might be lot of work and sometimes not a good idea.
Instruct your library GCC users that you link with libc++ and that they need to do the same, basic steps here. But I guess most GCC users do not want to do this.
Use clang with libstdc++ using -stdlib=libstdc++ flag to be compatible with libstdc++ (as suggested in other answer). This solution might be harder to setup on some platforms though.
I would suggest as already mentioned in comments to go with option 1.
There are several options:
Don't distribute it in binary form. Instead, make it easy to build everywhere (e.g. by using CMake, or autotools or ...)
Make it header only. This is by far the simplest solution but might not be what you want. It only really makes sense for templated code, and incurs a heavy impact on compile-time performance of your library.
Tell people to link with libstdc++ when using Clang and your library. Suboptimal solution (I for one like to check my code against libc++ as well as libstdc++), but (virtually) every Linux user has libstdc++ installed anyway. Make sure to pick a slightly older version (the one shipped in the latest Debian Stable distro is a good choice), because newer versions might introduce new symbols olders versions are missing. New versions should be ABI compatible anyway.
Note the situation for Visual Studio users is even worse, where every single compiler release mandates a new binary because they guarantee absolutely nothing with respect to the C++ libraries' or compiler's ABI.
Another option is for your shared library to not expose any C++ standard library types in its interface. And have a header file supplied with your shared library that converts std::string to types consumed by your library, such as struct my_string_span { char const *begin, *end; }; and other standard containers as necessary.
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.
I have a question related to embedding one library in another.
I have a code that is pure C and my users rely on that, they don't want to depend on C++ libraries. However, the need arose to embed a 3rd party library (ICU) into mine. None of the ICU functions would be exported, they would only be used internally in my library. Unfortunately ICU is a C++ library, though it does have a C wrapper. ICU does not use exceptions, but it does use RTTI (abstract base classes).
The question is how could I create my static library so that
ICU is embedded in my library (all references to ICU functions are resolved within my library)
all references to libstdc++ are also resolved and the necessary code is embedded into my library
if a user does not even have libstdc++ installed on their system things work just fine
if a user does happen to use my library within a C++ project then there are no conflicts with whatever libstdc++ (presumably the system libstdc++) he uses.
Is this possible at all? The targeted platforms are pretty much everything: windows (there my library is dynamic), and all sort of unix versions (linux, solaris, aix, hpux - here my library needs to be static).
gcc-4.5 and later does have --static-libstdc++, but as far as I understand it is only for creating shared libs or executables, and not static libs.
Thanks for any help!
The solution to this problem is pretty simple, but may not fall inside the parameters you have set.
The simple rules are:
You can dynamically link a C++ library to a C caller, but you have to wrap the library inside an extern C layer. You design the extern C API and implement it using C++ internals, which are forever hidden from view. [You can also use COM or .NET to do this on Windows.]
You cannot statically link a C++ library to a C caller. The libraries are different and the calling sequences/linker symbols are different. [You often can't even statically link between different versions of the same compiler, and almost never between different compilers.]
In other words, the solution is simple: use dynamic linking. If that's not the right answer, then I don't think there is one.
Just to make things interesting, you can even implement your own plug-in architecture. That's just another name for dynamic linking, but you get to choose the API.
Just to be clear, the only viable portable option I can see is that you link ICU inside its own dynamic library (DLL or SO). Its symbols, C++ libs, RTTI and exceptions all stay inside that. Your static lib links to the ICU dynamic lib by extern C. That's exactly how much of Windows is built: C++ inside DLL, extern C.
You can debug across the boundary, but you cannot export type information. If you need to do that, you will have to use a different API, such as .NET or COM.
I don't know if this will work, but let me at least suggest that you try it!
The excellent LLVM project (origin of clang compiler) has many front-ends and back-ends for different languages, such as C++ and C. And according to this S.O. question it should be possible for LLVM to compile C++ into C which in turn can be compiled as normal.
I imagine this route is a bumpy one, but if it works, it might solve your problem without the need to link dynamically. It all depends on if ICU will compile with LLVM C++.
If you do decide to give it a go, please let us know how you fare!
I know that if I link my c++ program to a dynamic library (DLL) that was built with a different version of Visual Studio, it won't work because of the binary compatibility issue.
(I have experienced this with Boost library and VS 2005 and 2008)
But my question is: is this true for all versions of MSVS? Does this apply to static libraries(LIB) as well? Is this an issue with GCC & Linux as well? and finally how about linking in VS to a DLL built with MinGW?
By the way aside from cross-platform or cross-compiler, why can't two version of the same compiler(VS) be compatibile?
Hi. I know that if I link my c++ program to a dynamic library (DLL) that was built with a different version of Visual Studio, it won't work because of the binary compatibility issue. (I have experienced this with Boost library and VS 2005 and 2008)
I do not remember ever seeing MS changing the ABI, so technically different versions of the compiler will produce the same output (given the same flags (see below)).
Therefore I don't think this is not incompatibilities in Dev Studio but changes in Boost.
Different versions of boost are not backwards compatible (in binary, source they are backward compatible).
But my question is: is this true for all versions of MSVS?
I don't believe there is a problem. Now if you use different flags you can make the object files incompatible. This is why debug/release binaries are built into separate directories and linked against different versions of the standard run-time.
Does this apply to static libraries(LIB) as well?
You must link against the correct static library. But once the static library is in your code it is stuck there all resolved names will not be re-resolved at a later date.
Is this an issue with GCC & Linux as well?
Yes. GCC has broken backwards compatability in the ABI a couple of times (several on purpose (some by mistake)). This is not a real issue as on Linux code is usually distributed as source and you compile it on your platform and it will work.
and finally how about linking in VS to a DLL built with MinGW?
Sorry I don't know.
By the way aside from cross-platform or cross-compiler, why can't two version of the same compiler(VS) be compatibile?
Well fully optimized code objects may be compressed more thus alignment is different. Other compiler flags may affect the way code is generated that is incompatible with other binary objects (changing the way functions are called (all parameters on the stack or some parameters in registers)). Technically only objects compiled with exactly the same flags should be linked together (technically it is a bit looser than that as a lot of flags don't affect the binary compatibility).
Note some libraries are released with multiple versions of the same library that are compiled in different ways. You usually distinguish the library by the extension on the end. At my last job we used the following convention.
libASR.dll // A Sincgle threaded Relase version lib
libASD.dll // A Single threaded Debug version
libAMR.dll // A Multi threaded Release version
libAMD.dll // A Multi threaded Debug version
If properly built, DLLs should be programming-language and version neutral. You can link to DLLs built with VB, C, C++, etc.
You can use dependency walker to examine the exported functions in the dll.
To answer part of your question, GCC/Linux does not have this problem. At least, not as often. libstdc++ and glibc are the standard C++/C libraries on GNU systems, and the authors of those libraries go to efforts to avoid breaking compatibility. glibc is pretty much always backward compatible, but libstdc++ has broken ABI several times in the past and probably will again in the future.
It is very difficult to write stable ABIs in C++ compared to C, because the automatic features in C++ take away some of the control you need to maintain an ABI. Especially once you get into templates and inline functions, where some of the code gets embedded in your application rather than staying contained in the shared library. That means that the object's structure can't ever change without requiring a recompilation of the application.
In practice, it isn't a huge deal on Windows. It would be fantastic if Microsoft just made the MSI installer know how to grab Microsoft-provided DLLs from Windows Update when an app is installed that needs them, but simply adding the redistributable to an InnoSetup-generated installer works well enough.