"Couldn't find function symbol in library" - JS-Ctypes



我的C++库函数是int RFD_startBackgroundThread()我在overlay.js中的代码是

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);

代码在最后一行引发异常。上面写着"Couldn't find function symbol in library"。

该库是一个"fat-dylib二进制文件",结合了OS X Lion(10.7)上的i386和x86_64(但不是PPC-arch)。Firefox版本11。

急需帮助。谢谢拉胡尔。

在包括OS X在内的大多数Unix平台中,C函数只需在前缀中加一个下划线即可映射到符号,因此int foo(int)最终仅为_foo

但这对C++不起作用,因为在C++中,可以用各种不同的方式,有两个同名的不同函数——可以有int foo(int)double foo(double),或者int MyClass::foo(int)int foo<int>(int),等等。(然后,该唯一字符串被视为C函数——也就是说,前缀为"_"。)

jsctypes知道如何去掉_,但它不知道如何破坏你的函数,因为你只是给它一个名字,而不是一个完整的原型。因此,您必须以其他方式计算出您的函数的损坏名称是_Z25RFD_startBackgroundThreadv

对于名字如何被篡改,没有可移植的标准。然而,苹果使用的C++ABI是基于安腾C++API的,它需要一个API来破坏和分解C++函数。Xcode附带了一个名为c++filt的工具,它将API封装起来,以便在命令行中使用,但它只处理解映射,而不处理变形。所以,它可以告诉你_Z25RFD_startBackgroundThreadv的意思是RFD_startBackgroundThread(),但它不能反过来。

获得损坏名称的一种方法是从nm libfoo.dylib开始,然后使用c++filt检查那些看起来很好的候选名称,直到找到与您要查找的原型匹配的名称。

另一种方法是自动化。类似这样的东西:

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

…将打印所有符号的名称。

但最好的方法可能是创建一个小.cpp文件,其中除了一个原型之外什么都没有,对其进行编译,然后使用"otool-SV tiny.a"来查看损坏的名称。

因此,为您想要调用的C++函数获取符号的名称并不难。

但这并不意味着你可以把它当作一个C函数来调用。举一个很明显的例子,如果你想调用(非静态)Foo::bar(int),你最好有一个有效的东西作为"this"指针传递,并知道如何传递它https://bugzilla.mozilla.org/show_bug.cgi?id=505907有关Mozilla中jsctypes不能做什么以及为什么不能做的详细信息。

问题是,库没有按原样存储符号。要查看符号的实际名称,请使用nm library-name转储库(可以选择将其重定向到txt文件,更易于阅读)。

在我的例子中,符号写为__Z25RFD_startBackgroundThreadv。显然,我必须去掉一个下划线,只使用_Z25RFD_startBackgroundThreadv

感谢迈克尔·道特曼!

最新更新