Как вы связываете внешние общие библиотеки с собственным расширением?

Я пишу собственное расширение pty и хочу связать libutil, чтобы я мог использовать forkpty и openpty из <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;
}

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 по вашей команде
строка, поскольку связанные библиотеки должны быть расположены в обратном порядке зависимости в командной строке компоновщика.

После этого выходные данные 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 больше не дает сбоя.

Если вы не хотите связывать разделяемую библиотеку с вашей библиотекой, вам нужна статическая библиотека, но с этим много проблем — это не невозможно, но гораздо сложнее.
Тогда проблема в том, что в вашей системе может быть только libutil.so, а не libutil.aпоэтому ваша общая библиотека должна будет загрузить libutil, когда она будет загружена.

dlopen Функция, используемая Dart для загрузки вашей общей библиотеки, должна
рекурсивно загружать другие разделяемые библиотеки, от которых это зависит, но это может работать, а может и не работать. Когда я собираю с -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 Работа.

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 (ВВ может быть номер версии или что-то).

Может случиться так, что это как-то связано с проблемой, которая возникает в статических библиотеках. Для статических библиотек это не может быть решено иначе, чем в правильном порядке. Для динамических библиотек это обычно решается путем предоставления запроса на связывание с некоторой зависимой библиотекой, которая, как ожидается, предоставит недостающие символы — и эта библиотека-заглушка должна это сделать.

1