are gcc-3 binaries compatible with gcc-4 - c++

I have a static library that has been compiled with gcc 3.4.3 .I would like to use this in code that will now be compiled with gcc-4.
I've read vaguely that gcc-3 and gcc-4 binaries are not compatible and that the library will need to be recompiled , but just want confirmation on this.
Isn't there anyway a gcc-3 library can be used with gcc-4 ?

Getting someone else in the organization, or at a vendor, to update their library to gcc 4 is not always an option, especially if they've abandoned it.
If C++: assuming that are able to link, at runtime you can blow up in C++ standard library template code that uses streams, as symbols generated by g++ 4 are resolved against definitions generated by g++ 3.
You might see this warning when linking:
/usr/bin/ld: warning: libstdc++.so.5, needed by (legacy static lib), may conflict with libstdc++.so.6
Here's an example you can get into: base class destructor ~basic_stringbuf() (actually a template) can be defined in your module compiled under g++ 3, which mistakenly gets called by the destructor ~basic_ostringstream() in libstdc++so.6, which is invoked by the g++ 4 compiled module. Ka-Boom.
I tried compat-libstdc++-33 but had no luck with that.
That said, I still link 32-bit gcc 3 era C libraries into my gcc 4.1.2 C++ programs.

Related

How to avoid errors when linking C++ shared libs into C programs

I'm using a library that comes with the usual AutoTools generated configure && make && make install procedure. The library contains a main (shared) library and some tools and is mostly written in C.
Now I am running into a problem, where one of the builds of one of the tools fails when using an instrumenter (Score-P which wraps compiler calls to do its magic).
I narrowed it down to the following facts:
libMain uses C files and 1 C++ file, C files get compiler with gcc and C++ file with g++. The library gets linked with g++ as a shared lib.
binTool uses C files only but links against libMain.
This works without the instrumenter. However when used, it adds extra libs when linking with g++ that use C++ features. Linking binTool with gcc then gives undefined reference to 'operator delete[](void*)' (and a few similar ones)
First: Could someone explain to me, why I have to be careful when linking against a shared library (use g++ even though the binary is only using C code)? I was under the impression, that linking of shared binaries is finalized so linking that should not pull in any new dependencies or that the dependencies are already resolved (in this case libMain would know it needs libc++ and have it already referenced/stored/whatever-elf-is-doing)
Second: From reading the AutoTools docu I found that the linker for a program is chosen based on its source files. As libMain uses a C++ file it is linked with g++. binTool uses C files only hence it is linked with gcc. But binTool links also libMain which was C++-linked and seems to require to be linked with g++.
So where is the culprit? Is it AutoTools issuing the wrong linker command for binTool? Or should g++ have done something different when linking libMain?
For reference: gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)
ldd libMain:
linux-vdso.so.1
librt.so.1
libpthread.so.0
libm.so.6
libc.so.6
libgcc_s.so.1
libdl.so.2
libnuma.so.1
libltdl.so.7
As I commented, you can link a shared library (when building that library) with another one. See this answer for details. Read Drepper's How To Write Shared Libraries paper.
Probably, you should re-configure and re-compile and re-build your libMain. You want to link it explicitly with -lstdc++ .
Perhaps passing some LDFLAGS=-lstdc++ or LIBES=-lstdc++ to the configure of that libMain might help. See this.
BTW, there are some autoconf-ed libraries coded in C++ and callable from a pure C program (for example libgccjit), and they are linked with -lstdc++
The idea to accomplish your problem is to write a wrapper library which its header is in C and the body internally is compiled with C++ compiler so that it can call your C++ library functions.
Later you can link your C++ library with its C header to your application
I found a solution (TL&DR jump down to the fat SOLUTION):
The situation was far more difficult than I thought. What happens is:
binTool links to shared library libMain which links to a shared library libExtraCxx.
binTool is a C program, hence linked with gcc
libMain contains a C++ file and is hence linked with g++. But it does not use any C++ library features so the linker omits libstdc++ from the libMain link process.
libExtraCxx is a C library intended to be linked into C programs by means of an automatic wrapper script. As libMain uses g++ it gets libExtraCxx linked in. This library is supposed to intercept the C++ new/delete calls and does so by using the GNU -wrap linker command and internally defines (manually) mangled versions of new/delete prefixed by __wrap_ and declares mangled versions of those prefixed by __real_.
Usually this works, because when a C++ linker would be used by binTool the wrapper would issue the -wrap commands and the libstdc++ provides the __real_ functions.
However the mistake is, that the libstdc++ does never get linked: libExtraCxx is a C library that just hooks into C++ functions. libMain does not use any C++ library functions and binTool is again a C program and no shared library linked into it has libstdc++ linked into that.
So one could point to 2 problems:
libExtraCxx should have been a C++ library and links libstdc++ but I guess this "tricks" are done to explicitly avoid the dependency on a C++ library so it can be used by the GNU, Intel or Clang C++ compiler which might have different standard libraries.
libMain should have libstdc++ not omitted. This can usually be done by passing -Wl,--no-as-needed to the compiler/linker as explained here.
I can't change libExtraCxx due to the amount of work involved, but I can pass arguments to the compiler, so I went with 2.
However simply doing configure <...> LDFLAGS=-Wl,--no-as-needed did not work. The flag was used but libstdc++ was not present.
I found the culprit to be libtool which is used by libMain: libtool 2.4.2 does not pass the flag at the right position AFAIK this bug#12880 is not fixed yet, so I was searching for more.
SOLUTION
I found a hack here: Simply use CXX="$CXX -Wl,--no-as-needed". This basically makes libtool think, that the flag is part of the compiler command and it won't reorder it leaving it at the beginning.
For reference: I was using starPU so libMain was actually libstarpu-1.2.so. The failed binary (binTool) is starpu_perfmodel_display. The "fake"-C++-Library is from Score-P libscorep_adapter_memory_event_cxx.so.5 I just changed the names to simplify them.
For SCORE-P the solution is a bit more complicated as one cannot simply change CXX. So full solution to compile starPU with ScoreP is:
SCOREP_WRAPPER=off ~/Downloads/starpu-1.2.3/configure --prefix /usr/local CC=scorep-gcc CXX=scorep-g++ FC=scorep-gfortran --with-mpicc=scorep-mpicc --with-mpifort=scorep-mpif77
And
make SCOREP_WRAPPER_INSTRUMENTER_FLAGS="--opencl --thread=pthread" SCOREP_WRAPPER_COMPILER_FLAGS="-Wl,--no-as-needed"
Explanation: SCOREP_WRAPPER_COMPILER_FLAGS will cause the wrapper to pass the flags to the compiler. As libTool is using the scorep wrapper it does not even see those flags so they get transparently added.

overridding glibc function in shared library to downgrade glibc required version in cross compilation

I have a C++ 3rd party library in source code. It is self-contained and does not refer to any other library. It uses C++14, hence it requires a modern gcc compiler.
I want to use some of its functions in a software application compiled for RHEL5 with an old version of gcc, which does not understand modern C++.
To solve the problem I am creating with gcc 7.2 a shared library (.so) which exposes a plain and simple C api. I would like the so file to be self contained hence I use the link line:
g++ -shared -static-libstdc++ -static-libgcc
I am not using the option -static, as I could not get it to work, despite I used -fPIC when generating my object files. Probably because the static libraries for libstdc++ might be compiled without fPIC. So ldd shows that my so has some dependencies on libc and libm. objectdump -T shows that most of these dependencies are compatible with RHEL5, because they require a version of GLIBC older than 2.5. However there is one dependency on memcpy which requires GLIBC 2.14. This does not come directly from my source code, but probably from libstdc++ or libgcc, which are being statically linked.
Is there any way I can provide my own implementation of memcpy and tell the linker to use that everywhere, instead of the one from glibc?

How can I deploy a C++11 program (with dependencies) on CentOS 6, whose GCC is C++03?

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.

Compiling and linking with a different versions of gcc on linux

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.

Any difference in linking with gcc vs. g++?

Are there any differences in the linking process between gcc and g++?
I have a big C project and I just switched part of the code to C++. The code isn't using std C++ library yet, so -llibstdc++ isn't needed for now.
The main difference is that (assuming the files are detected as C++) g++ sets up the flags needed for linking with the C++ standard library. It may also set up exception handling. I wouldn't rely on the fact that just because your application doesn't use the standard library that it isn't needed when compiled as C++ (for example the default exception handler).
EDIT: As pointed out in comments you'll have trouble with any constructors (that do work) for static objects as well as not getting virtual function tables (so if you're using those features of C++ you still need to link that library).
EDIT2: Unless you're using C99 specific code in your C project I would actually just switch to compiling the whole thing as C++ as the first step in your migration process.
gcc and g++ are both just driver programs that don't do anything other than calling other programs, so you can use the -v option to see exactly what they do -- what other programs they invoke with what args. So you can see exactly what the difference is between linking with gcc and g++ for the specific version and architecture of gcc that you happen to have installed. You can't rely on that staying the same if you want portability, however.
Depending on what you are doing, you might also be interested in the -### argument
I think that the g++ linker will look for the CPP mangled function names, and it is different from the C ones. I'm not sure gcc can cope with that. (Provided you can explicitly use the C version rather than the C++ one).
Edit:
It should work if you have
extern "C" {
<declarations of stuff that uses C linkage>
}
in your code and the object file has been compiled with g++ -c. But I won't bet on this.