C++ and Xcode 4.6

So, you’ve installed Xcode 4.6, and you are a C++ programmer.

You want to use the latest and greatest, so you create a new project, and add your sources to the project, and hit Build, and … guess what? Your code doesn’t build!

What’s up with that?

In Xcode 4.6 (and presumably, later versions), the default C++ compiler is clang, the default language is C++11, and the standard library is libc++.

This is a change from previous versions, where the default was gcc 4.2.1, C++03, and libstdc++.

This is good news

Clang is a much more capable compiler than gcc 4.2.1. It’s also better integrated into Xcode.

C++11 is a major upgrade in functionality from C++03. There have been lots of articles written about the new features, so I won’t belabor them here.

However, with a new language, compiler, and standard library, there are some incompatibilities. I’ll try to run through the common ones, and hopefully you will be up and running quickly.

How can I tell if I’m using libc++?

If you’re writing cross-platform code, sometimes you need to know what standard library you are using. In theory, they should all offer equivalent functionality, but that’s just theory. Sometimes you just need to know. The best way to check for libc++ is to look for the preprocessor symbol _LIBCPP_VERSION. If that’s defined, then you’re using libc++.

    #ifdef  _LIBCPP_VERSION
    //  libc++ specific code here
    #else
    //  generic code here
    #endif

Note that this symbol is only defined after you include any of the libc++ header files. If you need a small header file to include just for this, you can do:

    #include <ciso646>

The header file “ciso646” is required by both the C++03 and C++11 standards, and defined to do nothing.

What happened to TR1?

Technical Report #1 (TR1) was a set of library additions to the C++03 standard. Representing the fact that they were not part of the “official” standard, they were placed in the namespace std::tr1.

In c++11, they are officially part of the standard, and live in the namespace std, just like vector and string. The include files no longer live in the “tr1” folder, either.

So, code like this:

    #include <tr1/unordered_map>
    int main()
    {
        std::tr1::unordered_map <int, int> ma;
        std::cout << ma.size () << std::endl;
        return 0;   
    }

Needs to be changed to:

    #include <unordered_map>
    int main()
    {
        std::unordered_map <int, int> ma;
        std::cout << ma.size () << std::endl;
        return 0;   
    }

It’s probably easiest to just search your code base for references to tr1 and remove them.

Missing identifiers (include what you use)

“My code used to build with Xcode 4.5, and now I’m getting “unknown identifier” errors with stuff in the standard C (or C++) library!”

Library headers may include other library headers. Sometimes, this is required by the standard, sometimes it is done as an “implementation feature” of the library.

To be portable, you should explicitly include the header files that define the routines that you use. That way, you’re not dependent on the internal details of libc++ (or libstdc++).

For example, if you are calling std::malloc (or malloc), you should really #include <cstdlib> (or #include <stdlib.h>) to make sure that it is defined.

[ Updated 03-03 ]  In a Xcode-Users mailing list posting, Todd Heberlein writes:

I have my own C++ library. When I link against it in a Cocoa app (with the appropriate files set to .mm), everything works fine.

But when I start a new "Command Line Tool" project and try to link against the library, I get a lot of errors about missing STL symbols.

This is almost certainly because his library was built with gcc/stdlibc++, and his new tool with clang/libc++.

More to come.

As I find other differences, I will be adding to this document. If you come across things, please let me know in the comments and I will add them.

Clang and standard libraries on Mac OS X

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 setup. 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)