5

I think I've found myself in a situation where things are quickly spiraling out of control, and I'd like to get some feedback to select a way to proceed.

BACKGROUND

I'm working with a library based upon C++03. The library is cross-platform and supports multiple compilers. There are no external dependencies or prerequisites (i.e., no need for Autotools, Cmake, Boost, etc). We started testing with std=c++11 and found some things needed to be fixed. For example, auto_ptr was deprecated, so we needed to switch to unique_ptr if __cplusplus >= 201103L.

The switch to unique_ptr was relatively easy, except on OS X. OS X advertises __cplusplus as 201103L, but its a woefully deficient C++11 runtime library (I'm not even going to use the word "standard" in that sentence). Worse, if someone builds the latest LLVM/Clang from sources on OS X without libcxx, then the same deficiencies exist because the new Clang uses the old libraries.

To resolve the auto_ptr issue, we jumped through some hoops that ended in the following code. While the code below looks clean, the preprocessor is working overtime to determine when it should to defined MYLIB_HAVE_UNIQUE_PTR and MYLIB_HAVE_TEMPLATE_ALIAS due to OS X.

// The result is MyLib::auto_ptr in both cases
#if defined(MYLIB_HAVE_UNIQUE_PTR) && defined(MYLIB_HAVE_TEMPLATE_ALIAS)
  template<typename T>
    using auto_ptr = std::unique_ptr<T>;
#else
  using std::auto_ptr;
#endif

We are now trying to provide move semantics guarded on __cplusplus because there are two to five classes that would benefit. However, OS X is giving us trouble again because it lacks std::move. I suspect its going to have problems with Rvalues and Rvalue References, too.

We asked the Clang developers how to feature test for std::move at How to test for std::move (intersection of Apple and Clang). One of the Clang developers suggested we roll our own, but I'm beginning to think its a losing battle based upon GNU's source code for move.h. For example a quick grep -IR is_lvalue_reference /usr/include/c++/4.2.1/ reveals no hits.

STRATEGIES

I think our choices are (1) drop support for OS X altogether; (2) treat OS X as C++03; (3) roll our own implementation for missing C++11 features on OS X; or (4) switch to Autotools or Cmake for feature detection.

(1) is categorically not going to happen. (2) seems reasonable. (3) seems like a lot of work. (4) is not going to happen because it introduces external dependencies.

For (2), I believe the test is as easy as:

//  For Microsoft's cl.exe, pivot on _MSC_VER, not __cplusplus.
#if (_MSC_VER >= 1600) || (__cplusplus >= 201103L)
# define MYLIB_CXX11 1
#endif

// Ancient C++ runtime library; unset it because its too much trouble.
// Thanks to Jonathan Wakely for the `__has_include(<forward_list>)`
//     test. See http://stackoverflow.com/q/31655462.
// TODO: test under Xcode 3, where g++ is really g++.
#if defined(__clang__)
#    if !(__has_include(<forward_list>))
#        undef MYLIB_CXX11
#    endif
#endif

Then back to canonicalized feature detection:

#if MYLIB_CXX11

  // Everyone appears to provide this list
  #define MYLIB_CXX11_UNIQUE_PTR 1
  ...

  // template aliases: MS at VS 2015 (v19.00); GCC at 4.7; Clang at 3.0; and Intel 12.1.
  #if (_MSC_VER >= 1900) || (__INTEL_COMPILER >= 1210)
  #  define MYLIB_CXX11_TEMPLATE_ALIAS 1
  #elif defined(__clang__)
  #  if (__has_feature(cxx_alias_templates))
  #    define MYLIB_CXX11_TEMPLATE_ALIAS 1
  #  endif
  #elif (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
  #  define MYLIB_CXX11_TEMPLATE_ALIAS 1
  #endif // template aliases

#endif // MYLIB_CXX11

QUESTIONS

Are there any other strategies to deal with C++11 and OS X?

Has anyone tried strategy (3)? If so, how much work was it?


TESTING

If you have access to OS X, then try the following to test the built in compiler, the standard, and GNU's libstdc++ versus LLVM's libc++. After that, then test with a modern compiler by exporting CXX=/opt/local/bin/clang++.

$ cat test-clapple.cxx

// c++ -c test-clapple.cxx
// c++ -stdlib=libc++ -c test-clapple.cxx
// c++ -std=c++11 -c test-clapple.cxx
// c++ -std=c++11 -stdlib=libc++ -c test-clapple.cxx

# include <memory>

// Manage auto_ptr warnings and deprecation in C++11
#if (__cplusplus >= 201103L) || (_MSC_VER >= 1900)
  template<typename T>
    using auto_ptr = std::unique_ptr<T>;
#else
    using std::auto_ptr;
#endif // C++11

int main(int argc, char* argv[])
{
    return argc;
}
  • I'm nowhere near qualified to write a proper answer to this question, but #2 does seem like the best choice by far. Since you have to keep supporting C++03 anyway, it's not a catastrophe if one platform is stuck on only C++03. #3 seems like it'd be an absolute nightmare, though if you were to do it it'd probably be better to fix clang directly rather than hack around it. – Ixrec Aug 2 '15 at 1:24
  • 1
    Even option #3 does not give you the ability to interoperate with C++11 rvalue references. If you have to support C++03, it is likely that you have to be stuck with C++03. – rwong Aug 2 '15 at 1:26
  • @rwong - yeah, I think you are right. That probably requires compiler support... – user118658 Aug 2 '15 at 2:12
  • Are you using an old version of Xcode, OS X, or Clang? I use Xcode 5 on 10.9 and I'm pretty sure it is C++11 complete. unique_ptr works std::move works, etc. is it possible you are not passing the correct flag to Clang to make it use C++11 features? – Matthew James Briggs Aug 2 '15 at 3:36
  • 1
    If your Xcode command line tools don't use the latest version you are doing something wrong. See developer.apple.com/library/ios/technotes/tn2339/_index.html – gnasher729 Aug 2 '15 at 9:35
2

It is not MacOSX, it is the compiler that you use on it.

So, simply upgrade your compiler, perhaps by building from their source code a recent version of Clang/LLVM and/or GCC compiler(s).

(you don't need permission from Apple to compile and use a newer compiler. You just need to take time to read and follow the build instructions; in a few hours you can get the latest release of GCC or of Clang running on your computer)

In december 2015, the current GCC is GCC 5.3, and the current Clang is Clang 3.7; and you could configure them so that the compiler would be called g++-mine or clang++-mine if you want so.

  • Thanks, I get what you are saying. The problem is Apple supplies and maintains both of them (I probably shouldn't use "maintain" in that sentence since it appears Apple does not do that). So we don't control what/how most users configure their systems. Many simply use what Apple supplies. – user118658 Dec 9 '15 at 21:47
  • My point is that you should yourself build the compilers from the distributed source code. You don't need Apple's permission to do that. – Basile Starynkevitch Dec 10 '15 at 5:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy