_GLIBCXX_USE_CXX11_ABI disabled on RHEL6 and RHEL7? - c++

I have gcc 5.2.1 on RHEL6 and RHEL7, and it looks like _GLIBCXX_USE_CXX11_ABI gets disabled. It's not working even if I manually run -D_GLIBCXX_USE_CXX11_ABI=1 -std=c++14. This means I won't get small string optimization feature. For example, the output of following code always have 8 and 'micro not set'. For SSO, size of std::string should be at least 16 if we look at code bits/basic_string.h. Any workaround?
#include <string>
#include <iostream>
int main()
{
std::cout << sizeof(std::string) << std::endl;
#if _GLIBCXX_USE_CXX11_ABI
std::cout << "macro set" << std::endl;
#else
std::cout << "macro not set" << std::endl;
#endif
}

bugzilla.redhat has below reply
Jakub Jelinek 2018-02-19 06:08:00 EST
We've tried hard, but it is not possible to support this, neither on
RHEL6 nor on RHEL7, which is why it is forcefully disabled. It will
work in RHEL8 (and be the default there as well).

It would depend on your libstdc++ version, make sure your include/link/runtime paths are correct. Search your system for that macro and then use that instead, just make sure you link against the correct stdlib/abi libs.
If you do not have that, you can always build it yourself, however beware that if the rest of the programs you have use the old ABI, they will not work with your new libstdc++.
Edit: Thinking about this, did you specify the correct -std= flag to g++? Have you tried -std=gnu11? It could be as trivial as that. If not, then read on. Do not manually specify that define, you will break ABI compatibility with your libstdc++ leading to cascades of wonderful crashes. The only time you can specify things like that are when you're building the stdlib yourself.
Rest of this is a bit overkill, but it explains how to build and/or pick which stdlib you want to use.
I have a similar problem when using version 2 ABI of libc++, where everything that links against it has to be rebuilt with the right headers and thus the right ABI (things like small string optimization being one of them).
For example, when building C++ objects I use the following flags to specify a location to a custom stdlib header path instead of using the OS provided one (I use Clang but the principle is similar):
-nostdinc++ -I/usr/local/sdk/llvm.6.0.1/include/c++/v1/
And then during the linking phase I use an $ORIGIN relative runtime search path since on production machines the standard library is installed in in a more sane location, but you can specify a fixed one to whichever stdlib you want. You also want to make sure the linker can find the appropriate stdlib during static linking with -L.
-Wl,-rpath,'$ORIGIN/../lib' -L/usr/local/sdk/llvm.6.0.1/lib
You will need to link against -lstdc++ and -lsupc++ (order is important if static linking), as long as you provide the correct library search path, the static linker should find them which are the GCC/GNU C++ stdlib and ABI support library.
Beware, if you replace your system libstdc+ with this any programs linked against old ABI layout will break if they're dynamically linked so be careful.

Related

Barebones C++ without standard library?

Compilers such as GCC and Clang allow to compile C++ programs without the C++ standard library, e.g. using the -nostdlib command line flag. It seems that such often fail to link thou, for example:
void f() noexcept { throw 42; }
int main() { f(); }
Usually fails to link due to undefined symbols like __cxa_allocate_exception, typeinfo for int, __cxa_throw, __gxx_personality_v0, __clang_call_terminate, __cxa_begin_catch, std::terminate() etc.
Even a simple
int main() {}
Fails to link with
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400120
and is killed by the OS upon execution. Using -c the compiler still runs the linker which blatantly fails with:
ld: error in mytest(.eh_frame); no .eh_frame_hdr table will be created.
Is it a realistic goal to program and compile C++ applications or libraries without using and linking to the standard library? How can I compile my code using GCC or Clang on Linux? What core language features would one be unable to use without the standard library?
You will basically find all of your questions answered at osdev.org, but I'll give a brief summary anyway.
When you give GCC -nostdlib, you are saying "no startup or library files". This includes:
crti.o, crtbegin.o, crtend.o and crtn.o. Generally kernel developers only care about implementing crti.o and crtend.o and let GCC supply crtbegin.o and crtend.o by passing -print-file-name= to the linker. Generally these are just stubs that consist of .init and .fini respectively, leaving room for GCC to shove the contents of crtbegin.o and crtend.o respectively. These files are necessary for calling global constructors/destructors.
You can't avoid linking libgcc (the "low-level runtime library" (-lgcc) because even if you pass -nostdlib GCC will emit calls to its functions whenever you use it, leading to inexplicable linking errors for seemingly no reason. This is the case even when you're implementing/porting a C library.
You don't "need" libstdc++ no, but typically kernel developers want it. Porting a C library then implementing the C++ standard library from scratch is an extremely difficult task.
Since you only want to get rid of the "standard library", but keeping libc (on a Linux system) you're essentially programming C++ with just a C library. Of course, there's nothing wrong with this and you do you, but ultimately I don't see the point unless you plan on developing a kernel.
Required reading:
OSDev's C++ page - If you really care about RTTI/exception support, it's more annoying to implement than it sounds. Typically people just pass -fno-rtti or -fno-exceptions and then worry about it down the line or not at all.
"Standard" is a misnomer. In this context it doesn't mean "the library (set of functions, classes etc) as defined by the C++ standard" but "the usual set of libraries and objects (compiled files in a certain format) gcc links with by default". Some of those are necessary for most or even all programs to function.
If you use this flag, it's your responsibility to provide any missing functionality. There are several ways to do so:
Cherry-pick libraries and objects that your program really needs out of the default set. (Makes little sense as the result will most probably be exactly the same as with the default link flags).
Provide your own implementation of missing functionality.
Explicitly disable, through compiler flags, language features your program isn't using. I know of two such features: exceptions and RTTI. This is needed because the compiler needs to generate exceptions-related code and RTTI info even if these features are not explicitly used in this module.

Horrid error with strtod(): glibc-2.13 NOT backwards compatible with glibc-2.9?

I'm working on C and C++ programs which need to run on several different embedded platforms, for which I have cross-complilers so I can do the build on my x86 desktop.
I have a horrible problem with certain functions, e.g. "strtod()". Here's my simple test program:
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv)
{
if ( (argc < 2) || (NULL == argv[1]) ) return 0;
double myDouble = strtod(argv[1], NULL);
printf("\nValue: %f\n\n", myDouble);
return 0;
}
Normally I build all programs with dynamic linking to keep the binaries as small as possible. The above works fine on the x86 and Power PC. However, on the Arm system (BeagleBoard xM with Debian) strtod() misbehaves (the program always outputs "0.000000").
I tried building the program with the option '-static', and that worked on the Beagle:
root#beaglexm:/app# ./test.dynamic 1.23
Value: 0.000000
[Dynamic linked version - WRONG!!]
root#beaglexm:/app# ./test.static 1.23
Value: 1.230000
[Correct!!]
I also tested on a BeagleBone Black, which has a slightly different distribution. Both versions (static and dynamic) worked fine on the BBB.
Digging around in the libraries, I found the following version numbers:
Cross Compiler Toolchain: libc-2.9.so
BeagleBoard XM (DOESN'T WORK): libc-2.13.so
BeagleBone Black (WORKS!): libc-2.16.so
So my cross compiler is building against an older version of glibc. I've read in several places that glibc should be backwards-compatible.
I thought about static linking only libc, but according to this question it's a bad idea unless all libraries are statically linked.
Static linking everything does work, but there are serious constraints on the system which mean I need to keep the binaries as small as possible.
Any ideas what would cause horrible problems with strtod() (and similar functions) and/or why glibc 2.13 is not backwards compatible?
EDIT:
I didn't mention that the "soname" (i.e. top level name) is the same on all platforms: "libc.so.6" From my reading of the docs, the number AFTER the .so in the "soname" is the major version and only changes if the interface changes - hence all these versions should be compatible. The number BEFORE the .so which appears in the actual file name (shown above, and found by following the symlink) is the minor version. See: link
Generally version numbers reflect compatibility. The number that appears between the .so and the next dot represents a MAJOR revision, not guaranteed compatible with any other major revision.
The number(s) that that follow that, which you'll only see if you follow the symbolic links, represents a MINOR revision. These can be used interchangably, and symlinks are used to do just that. The program links against libc.so.6 or whatever, and on the actual filesystem, libc.so.6 is a symbolic link to (for example) libc.so.6.12.
glibc tries to maintain compatibility even across major revisions, but there are times when they simply have to accept a breaking change. Typically this would be when a new version of the C or POSIX standards are released and function signatures get updated in a way that breaks binary compatibility.
Any numbers that appear before the .so will also break compatibility if changed; these usually represent a complete rewrite of a program. For example glib vs glib2. Not of concern for libc.
The tool ldd is very useful for investigating library dependencies and discovering while exact version of the library is actually being loaded.

How to detect the libstdc++ version in Clang?

I would like to write a "portable" C++ library in Clang. "Portable" means that I detect (in C preprocessor) what C++ features are available in the compilation environment and use these features or provide my workarounds. This is similar to what Boost libraries are doing.
However, the presence of some features depends not on the language, but on the Standard Library implementation. In particular I am interested in:
type traits (which of them are available and with what spelling)
if initializer_list being constexpr.
I find this problematic because Clang by default does not use its own Standard Library implementation: it uses libstdc++. While Clang has predefined preprocessor macros __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__, they are hardcoded to values 4, 2, 1 respectively, and they tell me little about the available libstdc++ features.
How can I check in Clang preprocessor what version of libstdc++ it is using?
Clang does come with its own standard library implementation, it's called libc++. You can use it by adding -stdlib=libc++ to your compile command.
That being said, there are various ways to check Clang/libstdc++ C++ support:
Clang has the __has_feature macro (and friends) that can be used to detect language features and language extenstions.
Libstdc++ has its own version macros, see the documentation. You'll need to include a libstdc++ header to get these defined though.
GCC has its version macros which you already discovered, but those would need to be manually compared to the documentation.
And also, this took me 2 minutes of googling.
This is what I think would help. It prints the value of the _LIBCPP_VERSION macro:
#include <iostream>
#include <string>
using namespace std;
int main(int argc, const char * argv[])
{
cout<<"Value = "<<_LIBCPP_VERSION<<endl;
return 0;
}
Compile it again the version of clang you want the info for.

Create automatic C wrapper for C++ library?

Let say I have a C++ DLL. AFAIK, there is no widely-adopted ABI standard for C++, therefore to make sure it works and does not depend on the compiler of the target application I would need to wrap my library in a C interface.
Are there any tools that can automatically generate such interface? Would also be nice if they could generate wrappers around C interface to look as if they are original C++ objects, e.g.
Foo* f = new Foo(); // FooWrapper* fw = Foo_create();
f->bar("test"); // Foo_bar(fw, "test")
translates into C functions that are invoked in my library using generated C ABI. I understand that C++ is fairly complicated language and not everything can be easily wrapped in a C interface, but I was wondering if there are any such solutions that even support a subset of the C++ language (maybe with the help of some manually written IDL/XML files)?
there is no widely-adopted ABI standard for C++
I'm pretty sure that is a bit exaggerated - there aren't THAT many different compilers available for any given platform, so it would probably be easier to just produce a DLL for each vendor (e.g. Microsoft, GCC on Windows, GCC on Linux, Sun and GCC for Solaris, GCC for MacOS - CLANG is compatible with GCC as far as I know).
To add a C layer interface basically means that the interface layer must not:
1. Use any objects of that require special copy/assignment/construction behaviour.
2. Use any "throw" exceptions.
3. Use virtual functions.
across that interface.
It is my opinion that it's easier to "fix" the problems caused by "lack of ABI" than it is to make a good interface suitable for C++ use with a C interface in the middle of it.
If you want a way to make C++ code callable from other compilers/standard libraries, you can use cppcomponents from https://github.com/jbandela/cppcomponents. Full disclosure - I am the author of the library.
Here is a simple hello world example
First make a file called library.h
In this file you will define the Component
#include <cppcomponents/cppcomponents.hpp>
struct IPerson
:public cppcomponents::define_interface<cppcomponents::uuid<0xc618fd04,0xaa62,0x46e0,0xaeb8,0x6605eb4a1e64>>
{
std::string SayHello();
CPPCOMPONENTS_CONSTRUCT(IPerson,SayHello);
};
inline std::string PersonId(){return "library!Person";}
typedef cppcomponents::runtime_class<PersonId,cppcomponents::object_interfaces<IPerson>> Person_t;
typedef cppcomponents::use_runtime_class<Person_t> Person;
Next create library.cpp
In this file you will implement the interface and component
#include "library.h"
struct PersonImplementation:cppcomponents::implement_runtime_class<PersonImplementation,Person_t>
{
std::string SayHello(){return "Hello World\n";}
};
CPPCOMPONENTS_DEFINE_FACTORY(PersonImplementation);
Finally here is you main program (call it example1.cpp) that uses your implementation
#include "library.h"
#include <iostream>
int main(){
Person p;
std::cout << p.SayHello();
}
To build the program you will need to download cppcomponents (just clone from the git link above). It is a header only library and needs only a c++11 compiler.
Here is how you would build it on Windows
cl /EHsc example1.cpp /I pathtocppcomponents
g++ -std=c++11 library.cpp -o library.dll -shared -I pathtocppcomponents
where pathocppcomponents is the directory of cppcomponents.
I am assuming you have cl and g++ in your path.
To run the program, make sure library.dll is in the same directory as example1.exe and run example1.exe
This library requires fairly compliant c++11 support, so it needs MSVC 2013 Preview, and at least g++ 4.7. This library works on both Windows and Linux.
As far as I know the answer is no and you are supposed to handle this by yourself with a little bit of "hacking" and modifications, for example your t variable which is an std::string can possibly be "externed" to a C interface by t.c_str() because c_str returns a const char * which is a type that C understands without any problem at all.
I personally don't find C++ complicated, I can't see that "ABI issue" either, I mean nothing is perfect but you are externalizing to C your entire code base to "solve" this issue ? Just use C in the first place, also C it's no easy language to deal with either, for example in C there is not even the notion of "string", and problems that are trivial to solve in C++ while keeping everything type-safe, are really challenging in C if you want to meet the same goal.
I think that you are going a little bit too far with this, and you are complicating things, as it is now you have 3 + 1 main options on the most popular platforms :
libsupc++
libcxxrt
libc++abi
plus the whetever ABI is for the MSVC of your choice ( aka "only god knows")
for me, on linux, libsupc++ works very well, I'm following the libc++abi project and I don't see any big problem either, the only real problem with this is that llvm is basically an Apple oriented project for now, so there isn't that real and good support for the other platforms, but libc++abi compiles and works quite well on linux too ( although it's basically useless and pointless, on linux there is libsupc++ already.) .
I also would never ever use MSVC under Windows, in my opinion it's better to stick with a GCC-like compiler such as mingw, you got bleeding edge features, and you can simplify your codebase and your building phase a lot.

How to debug GCC/LD linking process for STL/C++

I'm working on a bare-metal cortex-M3 in C++ for fun and profit. I use the STL library as I needed some containers. I thought that by simply providing my allocator it wouldn't add much code to the final binary, since you get only what you use.
I actually didn't even expect any linking process at all with the STL
(giving my allocator), as I thought it was all template code.
I am compiling with -fno-exception by the way.
Unfortunately, about 600KB or more are added to my binary. I looked up what symbols are included in the final binary with nm and it seemed a joke to me. The list is so long I won't try and past it. Although there are some weak symbols.
I also looked in the .map file generated by the linker and I even found the scanf symbols
.text
0x000158bc 0x30 /CodeSourcery/Sourcery_CodeBench_Lite_for_ARM_GNU_Linux/bin/../arm-none-linux-gnueabi/libc/usr/lib/libc.a(sscanf.o)
0x000158bc __sscanf
0x000158bc sscanf
0x000158bc _IO_sscanf
And:
$ arm-none-linux-gnueabi-nm binary | grep scanf
000158bc T _IO_sscanf
0003e5f4 T _IO_vfscanf
0003e5f4 T _IO_vfscanf_internal
000164a8 T _IO_vsscanf
00046814 T ___vfscanf
000158bc T __sscanf
00046814 T __vfscanf
000164a8 W __vsscanf
000158bc T sscanf
00046814 W vfscanf
000164a8 W vsscanf
How can I debug this? For first I wanted to understand what exactly GCC is using for linking (I'm linking through GCC). I know that if symbol is found in a text segment, the
whole segment is used, but still that's too much.
Any suggestion on how to tackle this would really be appreciated.
Thanks
Using GCC's -v and -Wl,-v options will show you the linker commands (and version info of the linker) being used.
Which version of GCC are you using? I made some changes for GCC 4.6 (see PR 44647 and PR 43863) to reduce code size to help embedded systems. There's still an outstanding enhancement request (PR 43852) to allow disabling the inclusion of the IO symbols you're seeing - some of them come from the verbose terminate handler, which prints a message when the process is terminated with an active exception. If you're not using execptions then some of that code is useless to you.
The problem is not about the STL, it is about the Standard library.
The STL itself is pure (in a way), but the Standard Library also includes all those streams packages and it seems that you also managed to pull in the libc as well...
The problem is that the Standard Library has never been meant to be picked apart, so there might not have been much concern into re-using stuff from the C Standard Library...
You should first try to identify which files are pulled in when you compile (using strace for example), this way you can verify that you only ever use header-only files.
Then you can try and remove the linking that occurs. There are options to pass to gcc to precise that you would like a standard library-free build, something like --nostdlib for example, however I am not well versed enough in those to instruct you exactly here.