Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top