Using boost library with different compiler version - c++

I compiled boost 1.54 with gcc version 4.6.3( in 3.2.0-29-generic #46-Ubuntu ).
Then, I developed my library using this boost library. Since I don't want to recompile boost every time I change my library, I added compiled static libraries of boost to my git repo.
Now, I am trying to compile my library in a different machine with different version compiler (tried with gcc 4.4 and gcc 4.7). My library compiles fine, but when it comes to linking it is printing following errors.
`.text._ZN5boost16exception_detail10bad_alloc_D2Ev' referenced in section `.text._ZN5boost16exception_detail10bad_alloc_D1Ev[boost::exception_detail::bad_alloc_::~bad_alloc_()]' of ../external/lib/linux/64/libboost_thread.a(thread.o): defined in discarded section `.text._ZN5boost16exception_detail10bad_alloc_D2Ev[_ZN5boost16exception_detail10bad_alloc_D5Ev]' of ../external/lib/linux/64/libboost_thread.a(thread.o)
`.text._ZN5boost16exception_detail14bad_exception_D2Ev' referenced in section `.text._ZN5boost16exception_detail14bad_exception_D1Ev[boost::exception_detail::bad_exception_::~bad_exception_()]' of ../external/lib/linux/64/libboost_thread.a(thread.o): defined in discarded section `.text._ZN5boost16exception_detail14bad_exception_D2Ev[_ZN5boost16exception_detail14bad_exception_D5Ev]' of ../external/lib/linux/64/libboost_thread.a(thread.o)
`.text._ZN5boost16exception_detail19error_info_injectorINS_21thread_resource_errorEED2Ev' referenced in section `.text._ZN5boost16exception_detail19error_info_injectorINS_21thread_resource_errorEED1Ev[boost::exception_detail::error_info_injector<boost::thread_resource_error>::~error_info_injector()]' of ../external/lib/linux/64/libboost_thread.a(thread.o): defined in discarded section `.text._ZN5boost16exception_detail19error_info_injectorINS_21thread_resource_errorEED2Ev[_ZN5boost16exception_detail19error_info_injectorINS_21thread_resource_errorEED5Ev]' of ../external/lib/linux/64/libboost_thread.a(thread.o)
`.text._ZN5boost16exception_detail19error_info_injectorINS_10lock_errorEED2Ev' referenced in section `.text._ZN5boost16exception_detail19error_info_injectorINS_10lock_errorEED1Ev[boost::exception_detail::error_info_injector<boost::lock_error>::~error_info_injector()]' of ../external/lib/linux/64/libboost_thread.a(thread.o): defined in discarded section `.text._ZN5boost16exception_detail19error_info_injectorINS_10lock_errorEED2Ev[_ZN5boost16exception_detail19error_info_injectorINS_10lock_errorEED5Ev]' of ../external/lib/linux/64/libboost_thread.a(thread.o)
`.text._ZN5boost16exception_detail19error_info_injectorINS_15condition_errorEED2Ev' referenced in section `.text._ZN5boost16exception_detail19error_info_injectorINS_15condition_errorEED1Ev[boost::exception_detail::error_info_injector<boost::condition_error>::~error_info_injector()]' of ../external/lib/linux/64/libboost_thread.a(thread.o): defined in discarded section `.text._ZN5boost16exception_detail19error_info_injectorINS_15condition_errorEED2Ev[_ZN5boost16exception_detail19error_info_injectorINS_15condition_errorEED5Ev]' of ../external/lib/linux/64/libboost_thread.a(thread.o)
collect2: ld returned 1 exit status
make[2]: *** [libHazelcastClientShared_64.so] Error 1
make[1]: *** [CMakeFiles/HazelcastClientShared_64.dir/all] Error 2
make: *** [all] Error 2
PS: I tried to compile with a different machine with same compiler version also. (gcc version 4.6.3 and Centos 6.4)

The c++ ABI is not gauranteed to be consistent across different compiler versions. This affects the c++ name mangling and could cause the linker errors you are seeing. You have to use the same version of gcc for all libs.
The best would be to keep your whole system on the latest supported version of gcc. If your users really require different compilers then you can supply different versions of your library - one for each compiler you want to support.
Linking with libraries compiled with different compilers is not gauranteed to work. This is true for both static and shared/dynamic c++ libs.
Also have a look at:
Have a look at Unusual C++ linker error - 'Defined in discarded section'
It seems that the accepted answer to that question was also to compile all the libraries with the same version of GCC.

Boost is riddled with conditional compilation blocks based on the availability or support of different features by the compiler. See their macro list. Different compilers (or versions) have different levels of support for different standard features (or extensions). The Boost libraries are a mix of code that tailors to the least common denominator (when it doesn't "hurt" the code), compiler-specific workarounds, and conditional use of features that, when supported, can provide a clear benefit.
I am very inclined to believe that this is what is causing the issue. When you first compiled to code for a particular compiler and platform, certain switches were turned on and others turned off depending on what that platform supported, leading to a binary library that only really works for that platform. Then, when you tried to compiler your code on another platform, different switches were turned on/off within the boost headers, leading to incompatibilities at link-time.
Long story short, you cannot do what you are trying to do, at least, not without quite a bit of work. One solution would be to figure out what boost macros (from the list I linked to) are turned on or off on the least capable platform, and then, manually define those macros in your code to enforce an identical compilation on all platforms. But this could be labour-intensive.
Boost has very good and wide-spread distribution (of binaries too). So, I wouldn't worry too much about being able to install the boost binaries on different platforms.

Related

Use Multiple Versions of GCC During Compilation & Dependency on GCC in Object File Execution

This may be a dumb question, but I am a novice in the compilation of a C or C++ project through the command line. I am currently trying to cross-compile some frameworks to run in an aarch64 device, which has a built-in gcc5.4.0. However, some of the libraries require at least gcc7.5.0. So my first question is:
Can a framework that is compiled with gcc7.5.0 version can be used in an environment where gcc5.4.0 is present?
Moreover, some processes the I try to run on the device also requires gcc7.5.0. Therefore, my second question is that:
Can an object file (.o, e.g. the output of the compiled .c / .cpp file) that is compiled with gcc7.5.0 run on a system with gcc5.4.0?
Lastly, some processes require the libraries compiled in gcc5.4.0 and gcc7.5.0 to be used together. Therefore, I have to link the .so files that are generated by both gcc5.4.0 and gcc7.5.0. Hence, my last question is:
Can one create an executable by using libraries together that are compiled with different gcc versions?
Thanks.
For your first two questions: the presence or absence of a compiler in the system does not matter. I've run software on machines where no compiler was installed (it was compiled elsewhere). I've run software on machines where a bunch of compilers are installed, included multiple version of g++.
For your last question: the thing which matter when linking (either statically, at link time, or dynamically at execution time) libraries is called ABI. There are two aspects of the ABI: for the language itself, and for the standard libraries. For both, GCC maintains forward compatibility: using the latest compiler and standard library, you can link with object files compiled with older compiler (and for older standard library) since something like 3.4. In some more restricted cases (less well documented), you can even use the older compiler and standard library.
If you want to execute a program dynamically linked (which is usually the default with GCC) with a newer version of the standard library than the one on your system, you need to ensure it is found. That's a whole other subject, but here are two key words to help you find information for Unix (I know nothing about how Windows handle this, I presume but could be wrong that MacOS is a unix for this purpose): LD_LIBRARY_PATH and rpath.
Obviously meeting bugs is always a possibility and some care is needed in some cases. So here are some relevant links with the details.
GCC Compiler option related to ABI.
Standard library documentation related to ABI.
On the use on the C++11 library ABI. C++11 put additional requirements on some types (notably std::string) which prevented GCC to keep its old ABI for those types. Thus a new ABI was introduced in GCC 5 or so and if you want to be compatible with the previous one you have to pay attention. (Note that distributers sometimes forced the old ABI even with GCC version 5 and later)
Older related SO question

G++ new ABI problems

I got a problem with the new ABI introduced for C++11 in GCC. After upgrading to GCC 5.3 my project does no longer compile. The error messages I get are simple:
undefined reference to `tokenize(std::__cxx11::basic_string' ...more characters
or
undefined reference to `extract(std::string const&)'
So, it looks like I messed something up and GCC is unable to decide whether I want the old ABI or the new one (the __cxx11:: part is missing from some error messages, and present in others)?
I tried several solutions to resolve the issue:
passing -D_GLIBCXX_USE_CXX11_ABI=0 to GCC,
passing -D_GLIBCXX_USE_CXX11_ABI=1 to GCC,
setting the macro directly in source code,
setting the abi_tag attribute on the declarations GCC complained about when passed the -Wabi-tag flag,
Unfortunately, neither of them worked (i.e. allowed the code to compile). The one thing I know is that only functions returning std::string or taking it as a parameter fail to link. Which is to be expected, given what I read about the problem on the Internet. I was unable to reproduce the issue in a simple, example program to present it here.
Is there any obvious solution to my problem, that I am missing?
This error indicates that you're linking to some code or library that has not been recompiled by gcc 5.3, and was compiled by an earlier version of gcc, using the earlier version of the ABI.
If you are linking with some external libraries, besides the standard C++ library, those external libraries need to be recompiled (and reinstalled).
If you are not linking with any external libraries, and you are only linking together your own code, some of your source modules must not've been recompiled yet. Recompile everything. Make sure to wipe all existing object modules, with make clean, or the equivalent for whatever build system you're using.

Can you mix c++ compiled with different versions of the same compiler

For example could I mix a set of libraries that have been compiled in say GCC-4.6 with GCC-4.9.
I'm aware different compilers "breeds" such as VS cannot be with MinGW but can different generations of the same compiler? Are issues likely to occur? If so what?
Different generations of the same compiler sometimes can be compatible with each other, but not always. For example, GCC 4.7.0 changed its C/C++ ABI, meaning libraries compiled with 4.7.0+ and 4.7.0- are not likely to be compatible with each other (so in your example, the library compiled with 4.6 will not be compatible with the library compiled with 4.9). There can also be ABI bugs within a given compiler release, as happened in GCC 4.7.0/4.7.1:
GCC versions 4.7.0 and 4.7.1 had changes to the C++ standard library which affected the ABI in C++11 mode: a data member was added to std::list changing its size and altering the definitions of some member functions, and std::pair's move constructor was non-trivial which altered the calling convention for functions with std::pair arguments or return types. The ABI incompatibilities have been fixed for GCC version 4.7.2 but as a result C++11 code compiled with GCC 4.7.0 or 4.7.1 may be incompatible with C++11 code compiled with different GCC versions and with C++98/C++03 code compiled with any version.
The GCC ABI Policy and Guidelines page indicates they try to maintain forward compatibility, but not backward 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.
The reverse (backwards compatibility) is not true. It is not possible to take program binaries linked with the latest version of a library binary in a release series (with additional symbols added), substitute in the initial release of the library binary, and remain link compatible.
That page also has some fairly lengthy explanations on the versioning system GCC uses to mark different versions of given components, as well as an explanation for the versioning behind GCC itself:
Allowed Changes
The following will cause the library minor version number to increase, say from "libstdc++.so.3.0.4" to "libstdc++.so.3.0.5".
Adding an exported global or static data member
Adding an exported function, static or non-virtual member function
Adding an exported symbol or symbols by additional instantiations
Other allowed changes are possible.
Prohibited Changes
The following non-exhaustive list will cause the library major version number to increase, say from "libstdc++.so.3.0.4" to "libstdc++.so.4.0.0".
Changes in the gcc/g++ compiler ABI
Changing size of an exported symbol
Changing alignment of an exported symbol
Changing the layout of an exported symbol
Changing mangling on an exported symbol
Deleting an exported symbol
Changing the inheritance properties of a type by adding or removing base classes
Changing the size, alignment, or layout of types specified in the C++ standard. These may not necessarily be instantiated or otherwise exported in the library binary, and include all the required locale facets, as well as things like std::basic_streambuf, et al.
Adding an explicit copy constructor or destructor to a class that would otherwise have implicit versions. This will change the way the compiler deals with this class in by-value return statements or parameters: instead of passing instances of this class in registers, the compiler will be forced to use memory. See the section on Function Calling Conventions and APIs of the C++ ABI documentation for further details.
Note the bolded bit. In a perfect world, GCC versions with the same major release number would be binary-compatible. This isn't a perfect world, so test very very carefully before you go mixing compiler versions like this, but in general you'll probably be okay.
You can only mix generated binary files from different compilers or different versions of the same compiler if they are ABI (Application Binary Interface) compatible.
Things like:
Calling procedure
Name mangling
Thread local storage handling
are all part of the ABI.
If one of these things change, you will find that you either get linker errors, crashes or other forms of unexpected behaviour.
As a general rule, compiler vendors will often try maintaining at least backwards compatibility with older version, but there is no guarantee of this. As other have said you must either read the documentation or just recompile everything.

mixing compiler

I am wondering if it is possible to link a c++ program compiled with gcc4.2 with a shared c++ library that is compiled in a later version like gcc4.5.
I've tried to do this, but have run into some different kind of problems.
When compiling the shared library gcc5.3 I get a message saying:
*"malloc: error for object 0x7fff707d2500: pointer being freed was not allocated
set a breakpoint in malloc_error_break to debug"*.
If I try to compile the shared library with gcc4.6 I get really strange behaviour. The std::stringstream class is not working correctly. The resulting string is empty after writing to the stream.
Is it possible to do this? Or am I trying something that is impossible? I was hoping that this was possible since I'm linking the lib dynamically. Btw I'm running on MacOSX.
BR
Beginning with gcc 3.0, g++ follows the Itanium ABI, so in theory there should be no problem. However, g++ 4.2 has CXXABI_1.3.1 whereas g++ 4.5 has CXXABI_1.3.4 (see here). Therefore I'd be careful. One does not bump up revision numbers if there are no differences.
Further, the glibc++ has gone through 5 revisions between those versions, which may be one reason why you see std::stringstream do funny things.
Lastly, there exist many config options (such as for example making strings fully dynamic or not) which affect the behaviour and compatibility of the standard library directly. Given two (random, unknown) builds, you cannot even know that they have the same config options.
In my experience the ABI compatibility means that C++ libraries can link to each-other without problems.
However, because C++ uses so many inline functions this doesn't mean much.
If the Standard C++ Library used all inline functions or used all library functions then you could use code compiled with older versions of GCC with newer versions.
But it doesn't. The library mixes inline and external library code. This means that if something is changed in std::string, or std::vector or locales or whatever, then the inlined code from the old GCC is out of sync with the library code linked from the new GCC.

Please explain this linking error: referenced in section .rodata

I am doing a build on a 32bit SLES10 machine. Using GCC 3.4.2
Here is a sample error
`.L8245' referenced in section `.rodata' of CMakeFiles/myproj.dir/c++/util/MyObj.o: defined in discarded section
`.gnu.linkonce.t._ZN5boost9re_detail9reg_grep2INS0_21grep_search_predicateIPKcSaIcEEES4_cNS_12regex_traitsIcEES5_S5_EEjT_T0_SA_RKNS_14reg_expressionIT1_T2_T3_EEjT4_' of CMakeFiles/myproj.dir/c++/util/MyObj.o
This is typically due to 2 different .cpp's being compiled with different compiler switches - but also using the same templates. The generated template instantiations may differ in what they define/reference, and if the instantiation that is selected doesn't define/refer to the exact same symbols as the ones that got discarded you may get this error.
Validate that all your .cpp's are compiled with the exact same compiler switches and defines. If this isn't possible, reorder the .obj files on the linker commandline, in particular try to move the .obj files mentioned in the error message to the end or beginning of the .obj file list.
EDIT:
Also, if you're linking against prebuilt c++ libraries, see if you can duplicate the compiler switches used for building these libraries.
This may be due to using a newer version of binutils. binutils version 2.15 treated this as a non-fatal error, but later versions of binutils changed and so the link started failing. See https://bugzilla.redhat.com/show_bug.cgi?id=191618 for a similar report.
In my case, I was able to get things to link once more by explicitly using binutils 2.16.1, instead of binutils 2.17.