Adopting libc++, hitting problems on Mac OS X

I'm trying to switch the products I work on, which are already built with Clang
on Mac OS X, to libc++. But there's a problem. If you use the Framework on Mac
OS X, you have a dependency on:

/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices

That depends on:

/System/Library/Frameworks/CFNetwork.framework/Versions/A/CFNetwork

and that depends on

/usr/lib/libstdc++.6.dylib

As best I understand it, you can't use both libc++ and libstdc++ in the same
process. But you can't avoid using libstdc++ if you use the Framework, as far
as I can see. This is on Mac OS X 10.8.

Am I missing something, or should I be giving Apple a bug report against
the OS as a whole?

thanks,

You understand incorrectly. Libc++ is specifically designed so that you can use it in the same process as libstdc++. What you can not do is use it interchangeably with libstdc++. For example, if you define a function that takes a std::string, then you must pass it a std::string from the same STL that it was compiled with (libstdc++ or libc++). Libc++ puts all of its code in a non-standard namespace and then imports it into the std namespace, so you will get a linker error if you try this.

David

You understand incorrectly.

Oh, good!

Libc++ is specifically designed so that you can use it in the same process
as libstdc++. What you can not do is use it interchangeably with libstdc++.

Right ... so having a process "pure" one library or the other is definitely
safe, but one can be safe with them both in if one does things right.

Now I have to try to write some rules for this for developers who believe C++
is magic and always works right. For applications where large numbers of dylibs
are supplied by third parties. This could be fiddly, since my own understanding
of C++ is not of the very finest.

For example, if you define a function that takes a std::string, then you
must pass it a std::string from the same STL that it was compiled with
(libstdc++ or libc++). Libc++ puts all of its code in a non-standard
namespace and then imports it into the std namespace, so you will get a
linker error if you try this.

So "if it links, it will work (in this respect)?"

As regards writing a rule, it sounds like this should work:

  If two separately linked modules (executables or dylibs) have a C++ call
  interface between them, then they must be compiled for the same C++ run-
  time; if they aren't, it (usually) won't link. If C++ is used behind the
  scenes to implement an API that has a C call interface, and C++ objects
  are *never* passed across the interface, then the process can have a
  mixture of libc++ and libstdc++.

thanks very much,

Now I have to try to write some rules for this for developers who believe C++
is magic and always works right. For applications where large numbers of dylibs
are supplied by third parties. This could be fiddly, since my own understanding
of C++ is not of the very finest.

I wrote some for FreeBSD developers here:

http://wiki.freebsd.org/NewC%2B%2BStack

For example, if you define a function that takes a std::string, then you
must pass it a std::string from the same STL that it was compiled with
(libstdc++ or libc++). Libc++ puts all of its code in a non-standard
namespace and then imports it into the std namespace, so you will get a
linker error if you try this.

So "if it links, it will work (in this respect)?"

Yes, unless they do unsafe things with function pointer casts.

As regards writing a rule, it sounds like this should work:

If two separately linked modules (executables or dylibs) have a C++ call
interface between them, then they must be compiled for the same C++ run-
time; if they aren't, it (usually) won't link. If C++ is used behind the
scenes to implement an API that has a C call interface, and C++ objects
are *never* passed across the interface, then the process can have a
mixture of libc++ and libstdc++.

Please say STL implementation rather than runtime: all C++ code must be using the same C++ runtime (typically libsupc++ or libcxxrt, possibly libc++abi). It is also safe to pass non-STL objects across C++ library boundaries.

David

I wrote some for FreeBSD developers here:
NewC++Stack - FreeBSD Wiki

Thanks.

> So "if it links, it will work (in this respect)?"
Yes, unless they do unsafe things with function pointer casts.

OK.

Please say STL implementation rather than runtime: all C++ code
must be using the same C++ runtime (typically libsupc++ or libcxxrt,
possibly libc++abi). It is also safe to pass non-STL objects across
C++ library boundaries.

The Mac OS X 10.8 versions of libstdc++ and libc++ both use libc++abi,
as do the Mac OS X 10.7 versions. So that's OK, and this has got a lot
easier than I thought was necessary. So the incompatibility is just
with the STL implementation?

thanks again,

> So "if it links, it will work (in this respect)?"
Yes, unless they do unsafe things with function pointer casts.

Presumably embeddeding STL objects within non-STL objects, or within
C-style stucts, would also be a way to get past the linker checks?

thanks,

I think you'll get past the linker checks, but not past the ABI incompatibilities. It's best to stick to a C interface between dylibs unless they are both compiled with the same std::lib.

Howard

I think you'll get past the linker checks, but not past the
ABI incompatibilities.

Oh, yes. I was attempting to anticipate things that developers who
don't understand this kind of problem would think of.

It's best to stick to a C interface between dylibs unless they
are both compiled with the same std::lib.

Definitely!

thanks, everyone,