May 7, 2012

LLVM/clang and standard libraries on Mac OS X

Update 2013-Mar-1: This post has been moved to http://cplusplusmusings.wordpress.com/2012/07/05/clang-and-standard-libraries-on-mac-os-x/ All further updates will be there, not here.

I've seen several people on the boost developers list (and the boost users list) using clang to build their programs. This generally goes pretty well; the diagnostics that clang produces are much better than gcc's (though gcc 4.7 has made great strides in improving their error messages), but there's a common problem when people try to turn on c++11 support.

For the first step, they just add -std=c++11 to their compiler options (Xcode configuration, makefile, command-line, whatever) to turn on c++11 language support. This generally works well for their existing code base. Then they start adding things like auto and range-based for loops, and this works great as well.

Then they start to use library features such as std::move or std::forward or #include <chrono> (and so on). And it all comes crashing down.

    ../boost/test/tools/assertion.hpp:386:36: error: no member named 'forward' in namespace 'std'
    return value_expr<T>( std::forward<T>( v ) );

The problem is that the standard library that clang uses is the gcc standard (libstdc++) library that Apple ships (which is based on gcc 4.2).

The advantage of this is that you can "mix and match" your code; compiling some parts with gcc and other parts with clang, and link them all together and they will work.

The disadvantage is that libstdc++ 4.2 predates the c++11 standard; it does not support most of the c++11 features. So, your code that uses std::forward, etc will not compile with this library, even if you turn on c++11 support in clang - this switch only controls what language the compiler will accept.

The second step that you have to do is to add -stdlib=libc++ to your command-line (Xcode settings, makefile, whatever). This tells clang to use libc++ as the standard library.

You have to tell the linker to link against libc++ instead of libstdc++ as well.

Here's how to add a clang-11 toolset to your boost.

In your "user-config.jam", put this:

using clang : 11
    : "/usr/bin/clang++"
    : <cxxflags>"-std=c++11 -stdlib=libc++" <linkflags>"-stdlib=libc++""
    ;

Now you can run b2 like this b2 toolset=clang-11

On the boost list, Julian reminded me that if you're building your clang yourself (instead of getting it through Xcode), you'll need to get/install libc++ as well. (MacPorts is good for this)