你如何 link 外部共享库到本机扩展?
How do you link external shared libraries to a native extension?
我正在编写一个 pty 本机扩展并想要 link libutil 以便我可以使用来自 <pty.h>
.
的 forkpty 和 openpty
我正在使用来自 the official guide 的两个命令:
g++ -fPIC -lutil -I/home/crunchex/work/dart-sdk -c pty.cc -o pty.o
gcc -shared -Wl,-soname,libpty.so -o libpty.so pty.o
我收到以下错误:
/home/crunchex/work/dart-sdk/bin/dart: symbol lookup error: /home/crunchex/work/pty/bin/packages/pty/libpty.so: undefined symbol: forkpty
这可能更像是一个 g++/gcc 问题,但据我所知,我通过添加 -lutil 并包括 <pty.h>
来正确地完成这部分工作。 libutil.so 安装在我的 Ubuntu 14.04 系统上,所以我很确定它在那里。
这是我的测试扩展:
#include <string.h>
#include <pty.h>
#include "include/dart_api.h"
Dart_NativeFunction ResolveName(Dart_Handle name,
int argc,
bool* auto_setup_scope);
DART_EXPORT Dart_Handle pty_Init(Dart_Handle parent_library) {
if (Dart_IsError(parent_library)) {
return parent_library;
}
Dart_Handle result_code =
Dart_SetNativeResolver(parent_library, ResolveName, NULL);
if (Dart_IsError(result_code)) {
return result_code;
}
return Dart_Null();
}
Dart_Handle HandleError(Dart_Handle handle) {
if (Dart_IsError(handle)) {
Dart_PropagateError(handle);
}
return handle;
}
//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\//
//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\//
void PtyFork(Dart_NativeArguments args) {
Dart_EnterScope();
struct winsize winp;
winp.ws_col = 80;
winp.ws_row = 24;
winp.ws_xpixel = 0;
winp.ws_ypixel = 0;
int master = -1;
char name[40];
pid_t pid = forkpty(&master, name, NULL, &winp);
Dart_ExitScope();
}
//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\//
//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\//
struct FunctionLookup {
const char* name;
Dart_NativeFunction function;
};
FunctionLookup function_list[] = {
{"PtyFork", PtyFork},
{NULL, NULL}};
Dart_NativeFunction ResolveName(Dart_Handle name, int argc, bool* auto_setup_scope) {
if (!Dart_IsString(name)) return NULL;
Dart_NativeFunction result = NULL;
Dart_EnterScope();
const char* cname;
HandleError(Dart_StringToCString(name, &cname));
for (int i=0; function_list[i].name != NULL; ++i) {
if (strcmp(function_list[i].name, cname) == 0) {
result = function_list[i].function;
break;
}
}
Dart_ExitScope();
return result;
}
如果被举报:
/home/crunchex/work/pty/bin/packages/pty/libpty.so: undefined symbol: forkpty
那么该工具肯定需要您的 libpty 提供 这个符号,或者请求链接到提供它的另一个库。所以这个:
gcc -shared -Wl,-soname,libpty.so -o libpty.so pty.o
肯定是不完整的。
通常当这样的工具允许您创建自己的库时可能需要调用 "user of your library" 提供的一些函数,那么它至少需要链接到 "stub"图书馆。通常提供一个名为 libXXXXstubVV.a 的库(VV 可能是版本号或其他内容)。
可能和静态库出现的问题有关。对于静态库,除了按正确的顺序放置库之外,没有其他方法可以解决这个问题。对于动态库,通常通过提供链接请求来解决一些依赖库的问题,这些依赖库预计会提供缺少的符号 - 这个 "stub" 库应该做到这一点。
复制自https://code.google.com/p/dart/issues/detail?id=22257#c4
问题是 libc6
的一部分 libutil
需要在 link 命令行上 linked 到您的本机扩展共享库中,而不是编译命令行。
首先,-lutil
库规范应该在 linking 行,而不是编译行:
gcc -shared -Wl,-soname,libpty.so -o libpty.so pty.o -lutil
这会将共享库 libutil.so
的依赖项放入您的共享库中,当它被 dlload 加载时,依赖项也会被加载并 linked。
这会失败,除非 -lutil
选项放在 pty.o
之后
行,因为 linked 库必须在 linker 命令行上以相反的依赖顺序放置。
执行此操作后,objdump 在 libpty.so 上的输出包括:
objdump -x libpty.so
Dynamic Section:
NEEDED libutil.so.1
NEEDED libc.so.6
SONAME libpty.so
INIT 0x00000000000009c0
FINI 0x0000000000000db4
INIT_ARRAY 0x0000000000201dd0
....
Version References:
required from libutil.so.1:
0x09691a75 0x00 04 GLIBC_2.2.5
required from libc.so.6:
0x09691a75 0x00 03 GLIBC_2.2.5
0x0d696914 0x00 02 GLIBC_2.4
....
0000000000000000 w *UND* 0000000000000000
_ITM_registerTMCloneTable
0000000000000000 F *UND* 0000000000000000
forkpty@@GLIBC_2.2.5
0000000000000000 w F *UND* 0000000000000000
__cxa_finalize@@GLIBC_2.2.5
00000000000009c0 g F .init 0000000000000000 _init
和运行测试程序main.dart不再失败。
如果你不想 link 一个共享库到你的库中,那么你需要一个静态库,但这有很多问题 - 这不是不可能,但更难。
然后,问题是你的系统上可能只有libutil.so,没有libutil.a
,所以你的共享库在加载的时候需要加载libutil。
Dart 用来加载你的共享库的 dlopen
函数应该
递归加载它所依赖的其他共享库,但这可能有效也可能无效。当我在 link 步骤中使用 -lutil
编译时,ldd libpty.so 显示的共享库只是 libc.so.6,而一些标准的 linker ld -linux-.. 和 linux-vdso。所以我在那里没有看到 libutil。
要link将你需要的函数静态地放入你的共享库中,你
需要像
这样的东西
gcc -shared -Wl,-whole-archive /usr/lib/x86_64-linux-gnu/libutil.a
-Wl,-no-whole-archive -Wl,-soname,libpty.so -o libpty.so pty.o
但由于发行版中的 libutil.a
未使用 -wPIC
编译,因此无法 link 编辑到共享库中:
/usr/bin/ld: /usr/lib/x86_64-linux-gnu/libutil.a(login.o): relocation
R_X86_64_32 against `.rodata.str1.1' can not be used when making a shared object; recompile with -fPIC
/usr/lib/x86_64-linux-gnu/libutil.a(login.o): error adding symbols: Bad
value
我认为最好的办法是使共享库依赖于
libutil.so
工作。
我正在编写一个 pty 本机扩展并想要 link libutil 以便我可以使用来自 <pty.h>
.
我正在使用来自 the official guide 的两个命令:
g++ -fPIC -lutil -I/home/crunchex/work/dart-sdk -c pty.cc -o pty.o
gcc -shared -Wl,-soname,libpty.so -o libpty.so pty.o
我收到以下错误:
/home/crunchex/work/dart-sdk/bin/dart: symbol lookup error: /home/crunchex/work/pty/bin/packages/pty/libpty.so: undefined symbol: forkpty
这可能更像是一个 g++/gcc 问题,但据我所知,我通过添加 -lutil 并包括 <pty.h>
来正确地完成这部分工作。 libutil.so 安装在我的 Ubuntu 14.04 系统上,所以我很确定它在那里。
这是我的测试扩展:
#include <string.h>
#include <pty.h>
#include "include/dart_api.h"
Dart_NativeFunction ResolveName(Dart_Handle name,
int argc,
bool* auto_setup_scope);
DART_EXPORT Dart_Handle pty_Init(Dart_Handle parent_library) {
if (Dart_IsError(parent_library)) {
return parent_library;
}
Dart_Handle result_code =
Dart_SetNativeResolver(parent_library, ResolveName, NULL);
if (Dart_IsError(result_code)) {
return result_code;
}
return Dart_Null();
}
Dart_Handle HandleError(Dart_Handle handle) {
if (Dart_IsError(handle)) {
Dart_PropagateError(handle);
}
return handle;
}
//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\//
//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\//
void PtyFork(Dart_NativeArguments args) {
Dart_EnterScope();
struct winsize winp;
winp.ws_col = 80;
winp.ws_row = 24;
winp.ws_xpixel = 0;
winp.ws_ypixel = 0;
int master = -1;
char name[40];
pid_t pid = forkpty(&master, name, NULL, &winp);
Dart_ExitScope();
}
//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\//
//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\//
struct FunctionLookup {
const char* name;
Dart_NativeFunction function;
};
FunctionLookup function_list[] = {
{"PtyFork", PtyFork},
{NULL, NULL}};
Dart_NativeFunction ResolveName(Dart_Handle name, int argc, bool* auto_setup_scope) {
if (!Dart_IsString(name)) return NULL;
Dart_NativeFunction result = NULL;
Dart_EnterScope();
const char* cname;
HandleError(Dart_StringToCString(name, &cname));
for (int i=0; function_list[i].name != NULL; ++i) {
if (strcmp(function_list[i].name, cname) == 0) {
result = function_list[i].function;
break;
}
}
Dart_ExitScope();
return result;
}
如果被举报:
/home/crunchex/work/pty/bin/packages/pty/libpty.so: undefined symbol: forkpty
那么该工具肯定需要您的 libpty 提供 这个符号,或者请求链接到提供它的另一个库。所以这个:
gcc -shared -Wl,-soname,libpty.so -o libpty.so pty.o
肯定是不完整的。
通常当这样的工具允许您创建自己的库时可能需要调用 "user of your library" 提供的一些函数,那么它至少需要链接到 "stub"图书馆。通常提供一个名为 libXXXXstubVV.a 的库(VV 可能是版本号或其他内容)。
可能和静态库出现的问题有关。对于静态库,除了按正确的顺序放置库之外,没有其他方法可以解决这个问题。对于动态库,通常通过提供链接请求来解决一些依赖库的问题,这些依赖库预计会提供缺少的符号 - 这个 "stub" 库应该做到这一点。
复制自https://code.google.com/p/dart/issues/detail?id=22257#c4
问题是 libc6
的一部分 libutil
需要在 link 命令行上 linked 到您的本机扩展共享库中,而不是编译命令行。
首先,-lutil
库规范应该在 linking 行,而不是编译行:
gcc -shared -Wl,-soname,libpty.so -o libpty.so pty.o -lutil
这会将共享库 libutil.so
的依赖项放入您的共享库中,当它被 dlload 加载时,依赖项也会被加载并 linked。
这会失败,除非 -lutil
选项放在 pty.o
之后
行,因为 linked 库必须在 linker 命令行上以相反的依赖顺序放置。
执行此操作后,objdump 在 libpty.so 上的输出包括:
objdump -x libpty.so
Dynamic Section:
NEEDED libutil.so.1
NEEDED libc.so.6
SONAME libpty.so
INIT 0x00000000000009c0
FINI 0x0000000000000db4
INIT_ARRAY 0x0000000000201dd0
....
Version References:
required from libutil.so.1:
0x09691a75 0x00 04 GLIBC_2.2.5
required from libc.so.6:
0x09691a75 0x00 03 GLIBC_2.2.5
0x0d696914 0x00 02 GLIBC_2.4
....
0000000000000000 w *UND* 0000000000000000
_ITM_registerTMCloneTable
0000000000000000 F *UND* 0000000000000000
forkpty@@GLIBC_2.2.5
0000000000000000 w F *UND* 0000000000000000
__cxa_finalize@@GLIBC_2.2.5
00000000000009c0 g F .init 0000000000000000 _init
和运行测试程序main.dart不再失败。
如果你不想 link 一个共享库到你的库中,那么你需要一个静态库,但这有很多问题 - 这不是不可能,但更难。
然后,问题是你的系统上可能只有libutil.so,没有libutil.a
,所以你的共享库在加载的时候需要加载libutil。
Dart 用来加载你的共享库的 dlopen
函数应该
递归加载它所依赖的其他共享库,但这可能有效也可能无效。当我在 link 步骤中使用 -lutil
编译时,ldd libpty.so 显示的共享库只是 libc.so.6,而一些标准的 linker ld -linux-.. 和 linux-vdso。所以我在那里没有看到 libutil。
要link将你需要的函数静态地放入你的共享库中,你
需要像
gcc -shared -Wl,-whole-archive /usr/lib/x86_64-linux-gnu/libutil.a
-Wl,-no-whole-archive -Wl,-soname,libpty.so -o libpty.so pty.o
但由于发行版中的 libutil.a
未使用 -wPIC
编译,因此无法 link 编辑到共享库中:
/usr/bin/ld: /usr/lib/x86_64-linux-gnu/libutil.a(login.o): relocation
R_X86_64_32 against `.rodata.str1.1' can not be used when making a shared object; recompile with -fPIC
/usr/lib/x86_64-linux-gnu/libutil.a(login.o): error adding symbols: Bad
value
我认为最好的办法是使共享库依赖于
libutil.so
工作。