我试图了解 GCC 在构建共享库(
.so
或 .dll
)时如何决定导出哪些函数,而没有提供任何明确的导出指令(例如 .def
文件或 __attribute__((visibility("default")))
注释)。
考虑 Node.js 本机插件的以下 C 代码:
#include <assert.h>
#include <node/node_api.h>
napi_value Method(napi_env env, napi_callback_info info) {
napi_status status;
napi_value world;
status = napi_create_string_utf8(env, "world", NAPI_AUTO_LENGTH, &world);
assert(status == napi_ok);
return world;
}
#define DECLARE_NAPI_METHOD(name, func) \
{ name, 0, func, 0, 0, 0, napi_default, 0 }
napi_value napi_register_module_v1(napi_env env, napi_value exports) {
napi_status status;
napi_property_descriptor desc = DECLARE_NAPI_METHOD("hello", Method);
status = napi_define_properties(env, exports, 1, &desc);
assert(status == napi_ok);
return exports;
}
使用 GCC 编译此代码时(例如,
gcc -shared -fPIC hello.c -lnode -o hello.node
),会导出 napi_register_module_v1
函数,但不会导出 Method
函数。我听说 GCC 默认导出所有内容。但在这种情况下却不然,为什么?
$ cat hello.def
;
; Definition file of hello.node
; Automatic generated by gendef
; written by Kai Tietz 2008
;
LIBRARY "hello.node"
EXPORTS
Method
napi_register_module_v1
我的问题是:在这种情况下,GCC 使用什么启发法或约定来决定导出
napi_register_module_v1
而不是 Method
?
gcc 的默认行为是导出所有未声明为静态的符号。可以使用命令行参数 -fvisibility 更改此行为。将其设置为“隐藏”会使默认情况下不导出所有符号。除了隐藏之外,还有其他几种可能性。
-fvisibility=[default|internal|hidden|protected]
在代码中,可以使用visibility属性设置符号的可见性:
void __attribute__((visibility("default"))) myFunction()
{
// ...
}
此外,可以使用链接器脚本来指定导出哪些函数,但在这里描述它是如何工作的有点偏离主题。
鉴于此信息,我没有理由明白为什么 Method() 没有被导出。
您可以使用 readelf 程序确认正在导出哪些函数。下面将列出lib.so中导出的函数。确认所有地方的“Method”符号拼写正确。
readelf -s lib.so