Is there any way to compile GCC's libstdc++ with hash style SYSV instead of GNU/Linux? I have a toolchain (via crosstool-ng) that I use to compile our company library to work with a very wide range of Linux systems.
One of these system is a very old RedHat that have only SYSV hash style, when I compile a C only library/program with the toolchain, it works great since the generated binary uses SYSV.
But, when I link with libstdc++, the binary automatically changes to GNU/Linux style, the reason is because libstdc++ was built as GNU/Linux, hence the question.
Running the binary in this system gives me the error
ELF file OS ABI invalid
Just for completeness, I have already tried -Wl,--hash-style=sysv, without success.
Also, I have another toolchain for ARM system which have the same version of GCC, GLIBC, etc, but in this toolchain libstdc++ uses SYSV, dunno why.
Thanks in advance!
Try to rebuild your GCC with --disable-gnu-unique-object configure option. According to documentation on GCC configure options:
--enable-gnu-unique-object
--disable-gnu-unique-object
Tells GCC to use the gnu_unique_object relocation for C++ template static data members and inline function local statics. Enabled by default for a toolchain with an assembler that accepts it and GLIBC 2.11 or above, otherwise disabled.
Using gnu_unique_object may lead to GNU ABI in your final executable, which is not supported in old Red Hat.
Related
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.
If I build a static library with llvm-gcc, then link it with a program compiled using mingw gcc, will the result work?
The same for other combinations of llvm-gcc, clang and normal gcc. I'm interested in how this works out on Linux (using normal non-mingw gcc, of course) and other platforms as well, but the emphasis is on Windows.
I'm also interested in all languages, but with a strong emphasis on C and C++ - obviously clang doesn't support Fortran etc, but I believe llvm-gcc does.
I assume they all use the ELF file format, but what about call conventions, virtual table layouts etc?
Yes, for C code Clang and GCC are compatible (they both use the GNU Toolchain for linking, in fact.) You just have to make sure that you tell clang to create compiled objects and not intermediate bitcode objects. C ABI is well-defined, so the only issue is storage format.
C++ is not portable between compilers in the slightest; different compilers use different virtual table calls, constructors, destruction, name mangling, template implementations, etc. As a rule you should assume objects from one C++ compiler will not work with another.
However yes, at the time of writing Clang++ is able to use GCC/C++ compiled libraries as well; I recently set up a rig to compile C++ programs with clang using G++'s standard runtime library and it compiles+links just fine.
I don't know the answer, but slide 10 in this presentation seems to imply that the ".o" files produced by llvmgcc contain LLVM bytecode (.bc) instead of the usual target-specific object code, so that link-time optimization is possible. However, the LLVM linker should be able to link LLVM code with code produced by "normal" GCC, as the next slide says "link in native .o files and libraries here".
LLVM is a Linux tool, I have sometimes found that Linux compilers don't work quite right on Windows. I would be curious whether you get it to work or not.
I use -m i386pep when linking clang's .o files by ld. llvm's devotion to integrating with gcc is seen openly at http://dragonegg.llvm.org/ so its very intuitive to guess llvm family will greatly be cross-compatible with gcc tool-chain.
Sorry - I was coming back to llvm after a break, and have never done much more than the tutorial. First time around, I kind of burned out after the struggle getting LLVM 2.6 to build on MinGW GCC - thankfully not a problem with LLVM 2.7.
Going through the tutorial again today I noticed in Chapter 5 of the tutorial not only a clear statement that LLVM uses the ABI (Application Binary Interface) of the platform, but also that the tutorial compiler depends on this to allow access to external functions such as sin and cos.
I still don't know whether the compatible ABI extends to C++, though. That's not an issue of call conventions so much as name mangling, struct layout and vtable layout.
Being able to make C function calls is enough for most things, there's still a few issues where I care about C++.
Hopefully they fixed it but I avoid llvm-gcc because I (also) use llvm as a cross compiler and when you use llvm-gcc -m32 on a 64 bit machine the -m32 is ignored and you get 64 bit ints which have to be faked on your 32 bit target machine. Clang does not have that bug nor does gcc. Also the more I use clang the more I like. As to your direct question, dont know, in theory these days targets have well known or used calling conventions. And you would hope both gcc and llvm conform to the same but you never know. the simplest way to find this out is to write a couple of simple functions, compile and disassemble using both tool sets and see how they pass operands to the functions.
If I get some C++ code built by, lets say, GCC 4.8 on Ubuntu, the code has no GUI/interface, only call standard Linux libraries, then can the binary run on RHEL 5/6, with much older GCC flawlessly?
Normally it can't. It will complain about libc being too old, for one.
If you statically link with libstdc++ and carefully avoid newer glibc features, you may be able to get away with it. The latter is not always possible though. Static linking with libc is not officially supported and may work or not work for you.
The issue is probably more Glibc than libstdc++ (which you can indeed link statically) or GCC itself.
You could use an alternative Libc, such as MUSL libc (which is supposed to be more friendly with static linking)
Also, there might be some kernel dependencies.
According to the gcc ABI policy, gcc 4.4.7 should depend on libstdc++ 6.0.13. As far as I understood, the compiler version and the libstdc++ version are deeply interrelated and can't be swapped, so it came to me as a surprise to discover the following facts:
CentOS 5.8 somehow manages to have a gcc44 package that links against 6.0.8, apparently coming with the default system (which is based on gcc-4.1.2)
that the libstdc++.so in the compiler directory (/usr/lib/gcc/x86_64-redhat-linux6E/4.4.7, where I expected to find a libstdc++-6.0.13) is not a link to a shared object of any sort, but a text file containing INPUT ( -lstdc++_nonshared /usr/lib64/libstdc++.so.6 )
What kind of magic is going on here?
Specifically:
How could they provide a gcc 4.4.7 that links against an older version of libstdc++? I thought it was not possible.
what is this stdc++_nonshared library?
I didn't know a .so file could contain that text. Who parses it (dynamic linker I guess) and what are its specifications and consequences?
How far can this magic go? Can I use gcc4.7 with libstdc++ 6.0.3? What is the spectrum of compatibility
What kind of magic is going on here?
This is mostly the magic of ELF symbol versioning. The best reference I've seen on this is How to Write Shared Libraries by Ulrich Drepper, specifically section 3.
How could they provide a gcc 4.4.7 that links against an older version of libstdc++? I thought it was not possible.
The libstdc++ developers are careful about ABI compatibility. This makes it fairly straightforward to see what are the new symbols introduced between two different versions of libstdc++.
Looking at libstdc++'s ABI compatibility page, you can see that GCC 4.1's libstdc++ has GLIBCXX_3.4.8 and the stock (FSF release) of GCC 4.4 has GLIBCXX_3.4.13. It's then possible to look at the libstdc++ version scripts to see which symbols were added between these two versions.
A more empirical route for looking at symbol versions is to use a tool like readelf. E.g. on my Ubuntu system readelf --dyn-syms --wide /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | c++filt shows output like this (just a couple of selected shortish lines):
223: 000000000006dbe0 2121 FUNC GLOBAL DEFAULT 12 std::ios_base::Init::Init()##GLIBCXX_3.4
...
226: 00000000002ed920 1 OBJECT GLOBAL DEFAULT 27 std::adopt_lock##GLIBCXX_3.4.11
Note the symbol versions at the end of the symbol name, after the ##.
what is this stdc++_nonshared library?
Joining the dots from the above paragraph, stdc++_nonshared is a static library which contains the symbols which would be in the stock libstdc++.so.6.0.13 but not in libstdc++.so.6.0.8.
I didn't know a .so file could contain that text. Who parses it (dynamic linker I guess) and what are its specifications and consequences?
The regular linker parses this, not the runtime linker. See the binutils documentation for INPUT in a linker script. As a consequence, linking with this special libstdc++.so.6.0.13 will cause the linker to dynamically link against libstdc++.so.6.0.8, and statically link against the library which contains the extra symbols.
The downside of this is that an application compiled this way will be a little more bloated than the same application which is dynamically linked to only a stock libstdc++.so.6.0.13 which contains all the necessary symbols. The upside is that features from the newer standard library can be used on standard installations of older systems, without independent software vendors needing to ship their own copies of libstdc++.
How far can this magic go? Can I use gcc4.7 with libstdc++ 6.0.3? What is the spectrum of compatibility
Now that you know what the magic is, probably you can appreciate that this version of GCC 4.4 you have is a special version made just for Centos 5 (well, originally Red Hat 5). So probably you can create a GCC 4.7 which will produce binaries that only require libstdc++ 6.0.3, but it will require a non-trivial amount of work patching your GCC tree to put the correct symbols into stdc++_nonshared.a. You can at least look at the sources for the gcc44 RPM to see how Red Hat did it there.
Red Hat seems to have continued this approach with their Red Hat Developer Toolset. At the time of writing, GCC 4.8.1 is the newest compiler which can build binaries for EL5 which still only require libstdc++.so.6.0.8 to be installed on the target system. This is excellent for developers who want to write in C++11, but need to be able to deploy on EL5 or EL6.
I am planning to compile a static library (mylib.a) with gcc 4.7.1. I want to take the advantages of C++11, so -std=c++11 is used. The platform, where I compile this lib is x86_64 SLES 11 with glibc-2.8.
Then I want to link this static library on a legacy platform with a legacy code, therefore I must use gcc 4.1.2 for linking and compiling the legacy code. So in my library headers I will not use any C++11 specific code. Also I will link libstdc++.a from gcc.4.7.1. The platform, where I want to link mylib.a, libstdc++.a(gcc4.7.1) and the legacy object files is x86_64 SLES 10 with glibc-2.4.
I tried all of this mess with some dummy C++11 code (std::async()) in mylib.a and it worked. I think this is possible only becuase of the ELF requiriements. Am I thinking correctly, or ELF has nothing to do with it? What kind of errors should I expect if mylib.a will contain some truly complex logic?
Linux has a C++ Application Binary Interface (ABI), which has been around for a while. This means that the calling conventions and name mangling across compilers on Linux is fixed. Therefore, as long as the libraries are compatible, you should be able to compiler with different compilers (or different versions of the same compiler) and have code which correctly and reliably links together.
Not entirely the ELF requirements per se...
GCC guarantees binary compatibility all the way back to some ancient version of 3. As long as the libstdc++ you're linking to has the new library features, there's no reason you can't use them. You will just have to stay away from the new language and library features in code compiled with GCC 4.1.2.