the_mandrill
the_mandrill

Reputation: 30842

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

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?

Upvotes: 3

Views: 1919

Answers (4)

eerorika
eerorika

Reputation: 238401

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

Upvotes: 5

Jonathan Wakely
Jonathan Wakely

Reputation: 171373

#ifdef __has_include
# if __has_include(<ciso646>)
#  include <ciso646>
#  if defined(_LIBCPP_VERSION)
#   define USING_LIBCPP 1
#  endif
# endif
#endif

#if !USING_LIBCPP
# define USING_LIBSTDCXX 1
#endif

Upvotes: 1

Maxim Kholyavkin
Maxim Kholyavkin

Reputation: 4573

I use next code:

#include <cstddef> // for __GLIBCXX__

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

source

Upvotes: 0

rubenvb
rubenvb

Reputation: 76721

If you're writing these kinds of checks I suggest you choose a compiler/library version and require that or newer. It makes no sense to half-use C++11 library features. On Mac OS X, just require compilation with clang++ -stdlib=libc++.

Upvotes: 0

Related Questions