问题
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.
回答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.
回答2:
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!
来源:https://stackoverflow.com/questions/11442509/couldnt-find-function-symbol-in-library-js-ctypes