1

我正在编写一个 pty 本机扩展并希望链接 libutil 以便我可以使用 forkpty 和 openpty from <pty.h>.

我正在使用从官方指南中获取的两个命令:

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;
}
4

2 回答 2

1

复制自https://code.google.com/p/dart/issues/detail?id=22257#c4

问题是libutil, 的一部分libc6需要在链接命令行上链接到您的本机扩展共享库,而不是编译命令行。

首先,-lutil库规范应该放在链接行,而不是编译行: gcc -shared -Wl,-soname,libpty.so -o libpty.so pty.o -lutil

这会将共享库的依赖libutil.so项放入您的共享库中,当它被 dlload 加载时,依赖项也会被加载和链接。

除非该-lutil选项放在pty.o命令
行之后,否则这将失败,因为链接库必须在链接器命令行上以反向依赖顺序放置。

完成此操作后,libpty.so 上 objdump 的输出包括:

   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 不再失败。

如果您不想将共享库链接到您的库中,那么您需要一个静态库,但是这样做有很多问题——这并非不可能,但要困难得多。然后,问题是您的系统上可能只有 libutil.so ,而不是libutil.a,因此您的共享库在加载时需要加载 libutil 。

dlopenDart 用来加载共享库的函数应该递归
地加载它所依赖的其他共享库,但这可能会也可能不会起作用。当我-lutil在链接步骤中编译时,ldd libpty.so 显示的共享库只是 libc.so.6,以及一些标准链接器 ld-linux-.. 和 linux-vdso。所以我在那里看不到 libutil 。

要将您需要的函数静态链接到您的共享库中,您
需要类似

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,所以它不能链接到共享库中:

/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工作。

于 2015-02-05T10:53:29.457 回答
1

如果被报告:

/home/crunchex/work/pty/bin/packages/pty/libpty.so: undefined symbol: forkpty

那么该工具肯定需要您的 libpty提供此符号,或者请求链接到另一个提供它的库。所以这:

gcc -shared -Wl,-soname,libpty.so -o libpty.so pty.o

绝对是不完整的。

通常,当这样的工具允许您创建自己的库时,可能需要调用“库的用户”提供的某些功能,那么它至少需要链接到“存根”库。通常提供一个名为libXXXXstubVV.a的库(VV 可能是版本号或其他东西)。

可能与静态库中发生的问题有关。对于静态库,除了将库按正确的顺序放置之外,没有其他方法可以解决此问题。对于动态库,它通常通过提供一个链接到某个依赖库的请求来解决,该依赖库预计会提供缺少的符号——这个“存根”库应该做到这一点。

于 2015-02-03T12:44:24.790 回答