Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect whether clang is compiling using c++11 or legacy libstdc++ standard library

Tags:

xcode

c++11

clang

I've got an Xcode project that I'm migrating to use with clang's option -stdlib libc++, to enable C++11 support. Some of my source files need to know which library is being used, for instance so that I do things like this:

#ifdef HAVE_CPP11_LIB_SUPPORT
  #include <memory>
#else 
  #include <tr1/memory>
#endif

#ifdef HAVE_CPP11_LIB_SUPPORT
  vector.emplace_back(newValue);
#else 
  vector.push_back(newValue);
#endif

I'm having trouble though finding the preprocessor macros (if indeed there are any) that are set for this option. I've tried dumping the outputs of clang with:

clang -x c++ -std=c++11 -stdlib=libc++ -dM -E - < /dev/null

to compare with:

clang -x c++ -std=c++11 -stdlib=libstdc++ -dM -E - < /dev/null

but this gives the same results. Note that I don't want to switch on whether we're using the c++11 language setting, but whether we're using the c++11 library. Is there any reliable way of detecting this in the code?

like image 915
the_mandrill Avatar asked Mar 20 '14 11:03

the_mandrill


1 Answers

I don't know of any sure way that is guaranteed to be portable, but this is what I use for now:

// libc++ detected:     _LIBCPP_VERSION
// libstdc++ detected:  __GLIBCXX__
#if defined(__clang__)
#   if __has_include(<__config>) // defines _LIBCPP_VERSION
#       include <__config>
#   elif __has_include(<bits/c++config.h>) // defines __GLIBCXX__
#       include <bits/c++config.h>
#   else
#       include <ios>
#   endif
#elif defined(__GNUC__) // gcc does not have __has_include
#   include <ios> // ios should include the c++config.h which defines __GLIBCXX__
#endif

It's not great, but works for me for now.

libc++ defines _LIBCPP_VERSION and stdc++ defines __GLIBCXX__ which is nice, but unfortunately these macros are not defined by the compiler. Instead, they're defined in a non-standard header file, and you cannot test their definition unless that header has been included.

Note: Apparently stdc++ defined __GLIBCPP__ in older versions instead. Since you require c++11, this isn't going to be a problem.

Clang (Edit: Standard since C++17) has a nice feature __has_include which can be used to test for these but if neither header is found, the macro falls back to just including a standard header which hopefully uses the internal header under the hood. I have <ios> here, but the choice of standard header to include is up to you. You can look for headers that include the internal header with something like (this is for gcc on linux):

grep -Rl '#include <bits/c++config.h>' /usr/include/c++

Pick any header that you're likely to use in the project anyway.

Since this isn't guaranteed to work for any given past or future compiler/standard library version, I wouldn't rely on these defines for anything but optional features like:

#ifdef __GLIBCXX__
    std::set_terminate(__gnu_cxx::__verbose_terminate_handler);
#endif
like image 56
eerorika Avatar answered Sep 19 '22 22:09

eerorika