ограничения при динамической загрузке общего объекта из другого общего объекта? - PullRequest
6 голосов
/ 30 августа 2010

Я динамически загружаю (с dlopen()) общий объект (с именем libprofile1.so) из main.

В libprofile1.so Я определил фабричную функцию CreateProfile и класс Profile.Функция CreateProfile создает экземпляр класса Profile и возвращает на него указатель.Класс Profile имеет метод pMethod.

В основном после загрузки libprofile1.so я вызываю метод CreateProfile, который возвращает указатель на объект класса Profile (назовите его p).
Впоследствии я 'm вызывает pMethod метод для объекта p (p->pMethod).В этом методе я динамически загружаю другой общий объект (libdatasources.so).

В этом общем объекте у меня есть фабричная функция CreateDataSource и функция класса DataSource.
CreateDataSource, создающая экземпляр класса DataSource и возвращающая на него указатель.DataSource класс имеет метод dsMethod.

Как вы можете заметить, структуры обоих общих объектов похожи.

С pMethod после загрузки libdatasources.so Я вызываю CreateDataSource метод, который возвращает мне указатель наэкземпляр класса DataSource, назовите его ds.Затем я звоню dsMethod из ds объекта
(ds->dsMethod).


Теперь проблема заключается в следующем.

Когда я пытаюсь вызвать dsMethod объекта ds, общий объект, который я загружаю в первый раз (libprofile1.so), не загружается.На самом деле dlopen() возвращает NULL.Когда я читаю dlerror после dlopen, я получаю:

./libprofile1.so: undefined symbol: _ZN18DataSource13dsMethod

Так что если у меня есть вызов ds->Method, то первый общий объект не загружается!
Если я закомментирую вызов ds->dsMethod из источника, то мои libprofile1.so и libdatasources.so загружаются без проблем.
Я не вижу связи между вызовом метода из второго SO, с загрузкойпервый SO ???

Может быть, я не знаю, но есть ли ограничения при динамической загрузке общего объекта, из общего объекта, который также был динамически загружен?

Кстати, dlopen используется с RTLD_NOW|RTLD_GLOBAL.Я пробовал с RTLD_LAZY, но все та же проблема.

ОБНОВЛЕНИЕ:

Библиотеки построены в Eclipse.Опции компилятора и компоновщика G ++ одинаковы для обеих библиотек.
Вот компилятор G ++:

-O0 -g3 -Wall -c -fmessage-length=0

и компоновщик G ++:

-shared

опции, вставленные из Project Properties -> Settings -> Tool Settings

Заранее спасибо.

Ответы [ 2 ]

4 голосов
/ 31 августа 2010

Как отметил Мартин Йорк, так оно и есть в Linux. При связывании с библиотекой вы также должны ссылаться на все зависимости. В Windows все по-другому, библиотеки DLL сами заботятся о своих зависимостях. При динамической загрузке библиотеки, в которой в качестве зависимости есть другая библиотека, сначала необходимо загрузить эту библиотеку с флагом RTLD_GLOBAL. Это довольно странно, imho, поскольку вы, возможно, не сможете узнать, какие зависимости требуются другим разделяемым объектам, или зависимости могут измениться с более новой версией, которая иначе совместима с двоичной. Из того, что я знаю (и из чтения man-страниц g ++ и ld), невозможно создать поведение, подобное DLL-библиотекам Windows. Вот маленький тестовый пример:

two.cpp:

#include <iostream>

extern "C"
{
   void bar()
   {
      std::cout << "bar()\n";
   }
}

one.cpp:

#include <iostream>

extern "C"
{
   void bar();

   void foo()
   {
      std::cout << "foo()\n";
      bar ();
   }
}

test.cpp:

#include <dlfcn.h>
#include <iostream>

int main (int argc, char *argv[])
{
   using namespace std;
//       void *libtwo = dlopen("./libtwo.so", RTLD_NOW | RTLD_GLOBAL);
   void *libone = dlopen("./libone.so", RTLD_NOW);
   if (!libone)
   {
      cout << "dlopen(libone.so) failed: " << dlerror() << "\n";
      return 1;
   }
   typedef void (*foo_t)();
   foo_t foo = reinterpret_cast<foo_t>(dlsym(libone, "foo"));
   if (!foo)
   {
      cout << "dlsym(libone.so, foo) failed\n";
      return 2;
   }
}

one.cpp компилируется в libone.so, а two.cpp в libtwo.so, test.cpp компилируется в двоичный файл test. Это не удастся и будет успешным, только если закомментированная строка не закомментирована.

3 голосов
/ 30 августа 2010

Если вы динамически загружаете DLL, вы должны убедиться, что в ней нет неразрешенных символов.

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

Так что, если libprofile1 всегда использует libdatasources, убедитесь, что они связаны друг с другом.

Если вам нужно сделать это вручную, измените порядок загрузки библиотек в обратном порядке. Чтобы при загрузке libprofile1 нужные функции уже были загружены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...