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.

About these ads

8 thoughts on “C++ and Xcode 4.6

  1. justin

    Build settings, library version and binary compatability as well.

    Although Clang recognizes many of GCC’s[1] features, it does not recognize them *all*. They can relate to optimization, code generation, or warnings and errors. For example, GCC has several C++ specific warnings which clang does not recognize. Similarly, Clang has features/options which GCC does not recognize.

    Workarounds:
    – 1) Update your build settings, using options available to both compilers. Downside: You only get a subset of the features you want.
    – 2) Just switch to Clang and don’t look back. Downside: Your builds are more likely to break when you update. Keep multiple versions of Xcode on your system or dedicate a machine to testing your builds using the latest releases before upgrading. I’m not referring to syntax errors, but issues like the linker failing/crashing without problem indicators.
    – 3) Maintain separate build settings. There are a number of ways you can do this. I use xcconfigs. The compiler and std lib can be switched in seconds. Downside: Many people who have not set up moderately complex builds in Xcode have never used this, and it can take a lot of time to figure out how to migrate existing codebases. Then migration itself takes time.

    Another complication is ensuring your program is correct when linked and loaded — consider library versions, library vendors (i.e. libc++ and libstdc++), and finally binary compatibility of the libraries you link and load. This can become sickly complicated and ultimately prohibitive, depending on the libraries you use and how they are distributed. Build settings issues described above are likely to recur. If your dependencies extend beyond 1) OS libraries 2) the C++ standard library 3) header-only libraries, and 4) libraries you’ve configured as target dependencies to be compiled, then you may be in for either a rough adoption ride or some time in adoption purgatory. This aspect was largely painless for me because I’ve grown to distrust third party dependencies over time (one benefit of having symptoms of “Not Invented Here Syndrome”). Of course, builds without dependencies are far less likely to be affected (unless you’ve defined translation-specific flags).

    Because I’ve also been integrating Clang into my Xcode builds since its initial introduction (where possible), the toolset update of Xcode 4.6 resulted in no significant additional time investment. Having said that; If anybody’s a) developing for OS X or iOS and b) not yet integrated Clang for C++ — then you’re really behind, and getting your builds to work with Clang and libc++ should be a priority. This goes far beyond getting your projects to compile and link — you also need to reserve time to test, debug, and fix issues, and nontrivial codebases whose builds have not been maintained properly will need not-so-minor updates for their build and dependency management.

    [1] By “GCC” I mean the GCC 4.2 Apple toolset which is included with Xcode rather than a modern version of GCC.

    Reply
  2. justin

    Another thing I have done is declared a namespace alias for tr1 extensions. Deleting ::tr1 from your sources is fine if you are dropping GCC/libstdc++/C++03 support all at the same time. If you want to maintain support for both, then deleting ::tr1 will break your existing builds.

    Reply
    1. Marshall Clow Post author

      If you’re moving to c++11, there’s no need to keep tr1 in your sources. If you need to compile for c++03, then you are correct.

      You can drop tr1 even if you are using gcc/libstdc++ in “C++11 mode” – but only if you’re using a more modern version than what Apple ships

      Reply
  3. justin

    Apparently, omitting the footnote which I had made in the first response from the second response was a mistake. It was really an “Oh yeah, and…”-type continuation of my first response. The footnote read: *”[1] By “GCC” I mean the GCC 4.2 Apple toolset which is included with Xcode rather than a modern version of GCC.”*. My response is within the context of compilers which are distributed with Xcode.

    Reply
  4. Robert Ramey

    Here’s my experience.

    I got a new mac mini around september of 2014. One of the intended purposes was to better support the work I do which is related to boost library development. I installed the latest version of Xcode and kept it up to date. I found the Clang compiler/build system works as advertised. (I’m not going to address the IDE here – Up until now I’ve been using Visual Studio).

    The article refers to Xcode 4.6. As far as I know I have the latest version and it’s labeled Version 5.0.2 (5A3005). The app store agrees that this is the latest version. I can’t explain this.

    My system doesn’t seem to include libstdc++ nor any version of gcc. I presume that’s intentional on the part of Apple. I don’t miss it for most of my work. But sometimes I would like to use gcc/libstc++ to test my code in this environment. I don’t need the IDE for this – boost build is sufficient. I also wanted to test a more recent version of gcc than 4.2.1. I downloaded a compiled version of gcc 4.7.2 for MAC OS and it almost worked. Turns out I had to install Xcode command line tools to make it work. After that it I was able to test all my code with gcc-4.7 (boost build requires toolset=darwin-4.7 to do this). I’m not sure what Xcode command line tools actually includes, I’ll find out someday. But I wasn’t able to reproduce behavior on “real” gcc installations. Turns out the this installation didn’t include libstc++ but rather linked against libc++ headers included with Xcode command line tools!!! – a huge surprise to me. So I still haven’t been able to really test what I want to. Oh well.

    I should say that it seems very difficult to get detailed information on this whole system in a useful way.

    Robert Ramey

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s