1

My C++ Library function is int RFD_startBackgroundThread() My code in the overlay.js is

uri = addon.getResourceURI("components/mac/libReverbFirefoxExtensionLib.dylib");
this.extensionLib = ctypes.open(uri.path);
this.startBackgroundThread = this.extensionLib.declare("RFD_startBackgroundThread", ctypes.default_abi, ctypes.unsigned_int);

The code throws an exception on the last line. It says "Couldn't find function symbol in library".

The library is a "fat dylib binary" combining both i386 and x86_64 (but not PPC arch) on OS X Lion (10.7). Firefox version 11.

Desperately need help. Thanks. Rahul.

Noitidart
  • 35,443
  • 37
  • 154
  • 323
Rahul Jiresal
  • 1,006
  • 13
  • 24
  • 1
    if you do a "`nm`" dump of the library, how does that "`RFD_startBackgroundThread`" symbol appear? Is it "`RFD_startBackgroundThread`" or is it something else, like "`___RFD_startBackgroundThread`" or something more obfuscated? – Michael Dautermann Jul 11 '12 at 22:51
  • Checked the dump. There is a line that says "`00000000000010a0 T __Z25RFD_startBackgroundThreadv`". Is that what I'm supposed to use as the function name? – Rahul Jiresal Jul 11 '12 at 22:57
  • I tried `this.startBackgroundThread = this.extensionLib.declare("__Z25RFD_startBackgroundThreadv", ctypes.default_abi, ctypes.unsigned_int);` instead. Didn't work. Same exception. – Rahul Jiresal Jul 11 '12 at 23:06
  • 1
    Try knocking one underscore off. – abarnert Jul 11 '12 at 23:17
  • Worked! Thanks!! Why is there no documentation of this? – Rahul Jiresal Jul 11 '12 at 23:18
  • But you realize, you're calling C++ code, not C code, so all kinds of other things can go wrong beyond just name mangling. See https://bugzilla.mozilla.org/show_bug.cgi?id=505907 for more. – abarnert Jul 11 '12 at 23:18
  • There's plenty of documentation on this, but you have to know where to look. Do you understand the basics about C++ name mangling, and mapping between C functions and symbols in shared libraries? – abarnert Jul 11 '12 at 23:21
  • Not really. Didn't know about the name mangling stuff. Not very old C++ programmer. – Rahul Jiresal Jul 11 '12 at 23:34
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/13761/discussion-between-rahul-jiresal-and-abarnert) – Rahul Jiresal Jul 11 '12 at 23:40

2 Answers2

1

Well, the problem was, the library does not store the symbol as-is. To see the actual names of the symbols dump the library using nm library-name (optionally redirecting it to a txt file, easier to read).

The symbol in my case was written as __Z25RFD_startBackgroundThreadv. Apparently, I had to know off one underscore and use only _Z25RFD_startBackgroundThreadv.

Thanks to Michael Dautermann!

Rahul Jiresal
  • 1,006
  • 13
  • 24
1

In most Unix platforms, including OS X, C functions are mapped to symbols just by prefixing with an underscore, so int foo(int) ends up as just _foo.

But that doesn't work for C++, because in C++, you can have two different functions with the same name, in a variety of different ways—you can have int foo(int) and double foo(double), or int MyClass::foo(int), or int foo<int>(int), and so on. So, C++ functions have to be "mangled" to give a unique string. (And then, that unique string is treated like a C function—that is, prefixed with an "_".)

jsctypes knows about knocking off the _, but it can't know how to mangle your function, because you're just giving it a name, not a full prototype. So, you have to figure out in some other way that the mangled name of your function is _Z25RFD_startBackgroundThreadv.

There's no portable standard for how names get mangled. However, the C++ ABI that Apple uses is based on the Itanium C++ API, which requires an API to mangle and demangle C++ functions. Xcode comes with a tool called c++filt that wraps up that API for use at the command line—but it only handles demangling, not mangling. So, it can tell you that _Z25RFD_startBackgroundThreadv means RFD_startBackgroundThread(), but it can't get the other way around.

One way to get the mangled name is to start with nm libfoo.dylib, then use c++filt to check the ones that look like good candidates, until you find one that matches the prototype you're looking for.

Another way is to automate that. Something like this:

nm libfoo.dylib | awk 'NF==2 {printf "%s ",$1; system("c++filt " $2)} NF!=2{print $0}'

… will print the demangled names of all of your symbols.

But probably the best way to go about it is to create a tiny .cpp file that has nothing in it but that one prototype, compile it, and use "otool -SV tiny.a" to see the mangled name.

So, it's not that hard to get the name of the symbol for the C++ function you want to call.

But that doesn't mean you can just call it as if it were a C function. For one pretty obvious example, if you want to call (non-static) Foo::bar(int), you'd better have a valid thing to pass as a "this" pointer, and know how to pass it. See https://bugzilla.mozilla.org/show_bug.cgi?id=505907 for details on what jsctypes in Mozilla can't do, and why.

abarnert
  • 354,177
  • 51
  • 601
  • 671