5

I am trying to wrap a C++ library (for Sybase Ultralite) with Objective-C so that the library can be imported into MonoTouch. I have created an Objective-C library and included the compiled C++ library in this project, libulrt.a. To get my project to compile I set the path to the User Header Search Path to point to the directory where the C++ header files are located. I then had to set compile source as to Objective-C++.

The problem now is that, although the wrapper library compiles correctly, once I include it in another Xcode project I have to again set compile source as to Objective-C++ otherwise the project consuming my wrapper library gives linking errors. I don't understand why this is, because the header file for my wrapper library contains only Objective-C code and not C++ code at all. C++ code is only found in the implementation (*.mm file) of the wrapper library. What do I need to do to make the C++ implementation completely transparent to the project consuming the wrapper library? In other words, I want to be able to include my wrapper library and compile with compile source as set to Objective-C. Anyone got any ideas how to do this?

The linking errors that I am getting when compiling the project consuming my wrapper are as follows: (I have abridged the error listing because it is LONG!)

"operator delete(void*)", referenced from:
zc3db40339fee::~zc3db40339fee()in libUltralite.a(ee39bf4763.o)
zb4297ee7d543::~zb4297ee7d543()in libUltralite.a(747e80fdad.o)
z33836a0a6f46::~z33836a0a6f46()in libUltralite.a(f240efda30.o)
"___cxa_pure_virtual", referenced from:
vtable for ze78b0ec59364in libUltralite.a(2c50e8e8ff.o)
vtable for ze78b0ec59364in libUltralite.a(2c50e8e8ff.o)
vtable for ze78b0ec59364in libUltralite.a(2c50e8e8ff.o)

The header file for my wrapper library is as follows:

#import <Foundation/Foundation.h>

@interface DataAccess : NSObject {}

// Release objects.
- (void)dealloc;

// Singleton instance of the DataAccess class. 
+ (DataAccess*)sharedInstance; 

// Finalize the Database Manager when done with the DB.
+ (void)fini;

// Adds the given name to the database. 
- (void)addName:(NSString *)name;
@end 

Anyone have any idea how I can compile this as Objective-C++ but still have the projects consuming this library see it as Objective-C?

BruceHill
  • 6,954
  • 8
  • 62
  • 114

3 Answers3

6

@Mark Bessey is on the right track here, but he's incorrect that there is little difference between setting the language and adding the C++ library. Adding the C++ library is cheap and required (one way or another). Changing the language is expensive because the ObjC++ compiler is slower, and the resulting code is in my experience a bit of a pain to deal with in gdb through Xcode.

All you should need is to add -lstdc++ to your LD_FLAGS (Other Linker Flags) in your consuming project. Do make sure that "C++ Standard Library Type" is set to Dynamic.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • I removed that first paragraph, because it wasn't well phrased. Given that Bruce wants to have a library without dangling references to libstdc++, he needs to use the static version. See my edited response. – Mark Bessey Mar 16 '11 at 00:48
  • I don't believe he wants to link with the static C++ library. I'm pretty sure he wants to link with the dynamic C++ library. That just needs to be done at the final link step, not in the library build. A static library can't link with anything (static libraries are basically just a bunch of .o's concatenated together). – Rob Napier Mar 16 '11 at 01:13
  • Thanks. This is **exactly** the information I needed. What I was needing to do was to get my wrapper library consumed by a MonoTouch project, and in MonoTouch there is no option to select _compile souces as_ to be _Objective-C++_. That is why I needed the consuming project compiling with ObjC compiler. I tested this in Xcode first and found that it worked. Then, because MonoTouch also has a project option for extra linker flags, I added -lstdc++ to this option and my MonoTouch project compiled. :) Thanks for your help with this. – BruceHill Mar 17 '11 at 07:28
  • Sweat. Being punished for wrapping a C++ library neatly enough that the C++ stdlib goes out of the window wasn't fun. Thanks for the tip. –  Jul 20 '11 at 21:25
1

Seems like you'd need to statically link the C++ runtime library with your wrapper library to really get around this. I think then you might run into problems if a client of the library used Objective-C++, and you ended up with two versions of the C++ standard library in the same program.


A quick test with a MacOS project seems to indicate that you need to set the C++ library type to "static", and maybe set "symbols hidden by default" also.

Mark Bessey
  • 19,598
  • 4
  • 47
  • 69
  • Hi Mark. Thanks for the answer. What you said about needing to statically line the C++ runtime library does seem to make sense. It is just that I am very new to Objective C and Xcode and have no idea what flag to add to the _linker flags_ to accomplish this. If you could please let me know how I would go about doing this, I will give that a try. The problem with the client using Objective-C++ wouldn't be an issue at all as the client in my case will be the MonoTouch btouch tool which only works with Objective-C. – BruceHill Mar 15 '11 at 22:54
  • Setting symbols hidden by default is often good hygiene, but I don't believe it's part of solving this problem. His problem is that he can't find the symbols, not that too many symbols are visible. – Rob Napier Mar 16 '11 at 01:14
1

You'll have to build your wrapper as a shared object, not a static library. A static library is not linked, resolution of functions (and specifically the C++ standard library functions used by the code you are wrapping) happens at link time.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • This is iPhone so he cannot use a shared library. On Mac, he only *should* not use a shared library. Shared libraries in the bundle carry a lot of headache and increase the bundle size (since you can't dead-code strip). In my experience, static libraries are far preferred if you are not actually sharing the code between programs. – Rob Napier Mar 16 '11 at 00:18
  • @Rob: Well, unless Mac is very different from other flavors of BSD, the required functions simply aren't going to become part of his static wrapper library, since it hasn't been linked. So the client will need to provide them. In Visual C++ I can do `#pragma comment(lib, "libname")` to automatically link with prerequisite libraries, do the Apple compilers have anything similar? – Ben Voigt Mar 16 '11 at 01:11
  • On Mac (and BSD), static libraries are just bundles of .o's glued together. So you need to have all the other libraries listed in the final link of the app (unlike dynamic libraries which can include references to their own dependencies). In this case you do that by passing -lstdc++. There's no equivalent to the `#pragma` you list unfortunately. The question is about iPhone, though, which does not support 3rdparty shared libraries in any case. – Rob Napier Mar 16 '11 at 01:17
  • @Rob: Dynamic libraries are created by linking, so they often don't "include references to their own dependencies", they incorporate the dependencies (unless the dependency is itself a shared library, but everyone here is talking about static libstdc++). And I'm just going to bow to your expertise on iPhone... I don't have one, don't develop for one, I just try to infer behavior based on the BSD heritage of Apple's current OSes. – Ben Voigt Mar 16 '11 at 01:21
  • And "just a bunch of object files" is a good description of static libraries on all major platforms. There's often a symbol directory besides, for linker efficiency, but that doesn't fundamentally change the behavior. – Ben Voigt Mar 16 '11 at 01:22
  • @Ben +1 for helping me understand what was going wrong. I was under the mistaken impression that the c++ library was being linked at compile time of the wrapper library. This discussion helped clear up that misconception. – BruceHill Mar 17 '11 at 07:18