C++11

Some machines that we compile on, such as lcls-dev3, run older version of RedHat (RHEL6).  Yet sometimes we need newer versions of the binutils tools (gcc, ld, etc.) because the modules we want to build require newer features that come with C++11.  RedHat has a tool that allows you to switch to a binutils toolchain of your choosing.  The tool is called scl.

To see a list of binutils toolchains you can install and switch to:

$ yum list devtoolset*-toolchain

After installing it (if needed), switch to that binutils toolchain:

$ scl enable devtoolset-8 bash
$ which gcc
/opt/rh/devtoolset-8/root/usr/bin/gcc

Now you can run your build like you normally would, and C++11 semantics and definitions are in play.  After your application is successfully built, you can most likely run it in the normal RHEL6 environment (i.e., non-scl).

You probably want to know which version of gcc is contained in your devtoolset, and you can do this by searching for the package (devtoolset8-toolchain) and finding information about it on RedHat's website.  From there, you'll find the version of gcc, and from the version of gcc you can discover if that version of gcc has C++11 support.

The caveat to running your scl-built application in a non-C++11 environment is that you may not have the best version of C++11 functions and classes.  Your application may have built in bugs and issues that were present when RHEL6 was released with a provisional version of C++11.  Building on a machine that has native support for C++11 is preferable, but unfortunately is not always possible.

I built a program called scl_undef and used a C++11 feature named error_code.  The stdc++ library is almost never statically linked (same as libc), so when I check to see if the symbol is in the executable, I get a W which means it is in the executable but only weakly.  This means if the run-time linker finds a different version, the run-time linker will use it at run time.

$ nm -C scl_undef | grep error_code
0000000000401fd2 W std::error_code::value() const
0000000000401ff4 W std::error_code::message() const
0000000000401fe2 W std::error_code::category() const
00000000004020b0 T std::_V2::error_category::equivalent(std::error_code const&, int) const
0000000000401fa8 W std::error_code::error_code()
0000000000401fa8 W std::error_code::error_code()

Let's discover if the run-time linker will find a different version:

$ ldd scl_undef             
        linux-vdso.so.1 =>  (0x00007fff22c49000)
        libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007f7c42d90000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f7c42b0c000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f7c428f6000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f7c42562000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f7c43096000)

$ nm -D -C /usr/lib64/libstdc++.so.6 | grep error_code
0000000000069cc0 T std::error_code::default_error_condition() const
0000000000069ca0 T std::error_category::equivalent(std::error_code const&, int) const
00000000000623d0 T std::hash<std::error_code>::operator()(std::error_code) const

In my case, while some symbols with error_code do exist, the class error_code does not exist in libstdc++, so the weakly-linked error_code in the executable will be used, and this is the behavior we desire.

  • No labels