2014-09-29 3 views
4

Этот вопрос тесно связан с dlopen a dynamic library from a static library linux C++, но содержит дополнительную сложность (и использует C++ вместо C):dlopen динамической библиотеки из статической библиотеки, когда динамическая библиотека использует символы статической одной

У меня есть приложение, которое ссылается на статическую библиотеку (.a), и эта библиотека использует функцию dlopen для загрузки динамических библиотек (.so). Кроме того, динамические библиотеки вызывают функции, определенные в статическом.

Есть ли способ скомпилировать это, не связывая динамические библиотеки со статическим или наоборот?

вот что я пытался до сих пор, немного изменив пример из связанный с этим вопрос:

app.cpp:

#include "staticlib.hpp" 
#include <iostream> 
int main() 
{ 
    std::cout << "and the magic number is: " << doSomethingDynamicish() << std::endl; 
    return 0; 
} 

staticlib.hpp:

#ifndef __STATICLIB_H__ 
#define __STATICLIB_H__ 

int doSomethingDynamicish(); 
int doSomethingBoring(); 
#endif 

staticlib.cpp :

#include "staticlib.hpp" 
#include "dlfcn.h" 
#include <iostream> 
int doSomethingDynamicish() 
{ 
    void* handle = dlopen("./libdynlib.so",RTLD_NOW); 
    if(!handle) 
    { 
     std::cout << "could not dlopen: " << dlerror() << std::endl; 
     return 0; 
    } 

    typedef int(*dynamicfnc)(); 
    dynamicfnc func = (dynamicfnc)dlsym(handle,"GetMeANumber"); 
    const char* err = dlerror(); 
    if(err) 
    { 
     std::cout << "could not dlsym: " <<err << std::endl; 
     return 0; 
    } 
    return func(); 
} 

staticlib2.cpp:

#include "staticlib.hpp" 
#include "dlfcn.h" 
#include <iostream> 

int doSomethingBoring() 

{ 
    std::cout << "This function is so boring." << std::endl; 
    return 0; 

} 

dynlib.cpp:

#include "staticlib.hpp" 

extern "C" int GetMeANumber() 
{ 
    doSomethingBoring(); 
    return 1337; 
} 

и построить:

g++ -c -o staticlib.o staticlib.cpp 
g++ -c -o staticlib2.o staticlib2.cpp 
ar rv libstaticlib.a staticlib.o staticlib2.o 
ranlib libstaticlib.a 
g++ -rdynamic -o app app.cpp libstaticlib.a -ldl 
g++ -fPIC -shared -o libdynlib.so dynlib.cpp 

Когда я запускаю его с ./app я получаю

could not dlopen: ./libdynlib.so: undefined symbol: _Z17doSomethingBoringv 
and the magic number is: 0 
+1

Когда речь идет о статических библиотеках в среде POSIX, только сшивание участия, когда ваше приложение ссылка с статической библиотекой. Сама статическая библиотека не связана. Фактически, статическая библиотека представляет собой не что иное, как архив объектных файлов, которые связаны в вашем приложении, как и любой другой объектный файл. Кроме того, целью использования 'dlopen' является загрузка модуля во время выполнения, поэтому вам не нужно связываться с модулями, которые вы' dlopen'. –

+0

Спасибо за разъяснение, я довольно новичок в мире ссылок. Однако остается мой вопрос: как сделать символы, определенные в этом архиве (или в любом объектном файле) доступными для динамически загружаемой библиотеки? – Johanna

+1

О, кстати, помните, что [C++ использует * name mangling *] (http://en.wikipedia.org/wiki/Name_mangling#Name_mangling_in_C.2B.2B). Это означает, что символ 'GetMeANumber' не будет называться как в объектном файле. Чтобы пропустить манипулирование именами, вы должны сделать функцию 'extern 'C" ', как в' extern' C "int GetMeANumber() {...}' –

ответ

4

С dlopen manual page:

If the executable was linked with the flag "-rdynamic" (or, synonymously, "--export-dynamic"), then the global symbols in the executable will also be used to resolve references in a dynamically loaded library.

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


Помимо проблемы, описанной выше, есть еще одна проблема, и что нужно делать со статической библиотекой: Проблема заключается в том именно, что так как функция doSomethingBoring не вызывается в основной программе, объектный файл staticlib2.o из статическая библиотека не связана.

Ответ можно найти, например. this old question, который говорит вам, чтобы добавить флаг --whole-archive компоновщика:

g++ -rdynamic -o app app.cpp -L. \ 
    -Wl,--whole-archive -lstaticlib \ 
    -Wl,--no-whole-archive -ldl 
+0

Я уже наткнулся и попробовал этот флаг. К сожалению, привязка приложения к «g ++ -rdynamic -o app app.cpp libstaticlib.a -ldl» приводит к точно такой же ошибке для моего примера. – Johanna

+0

@Lea У меня нет большого опыта работы с 'dlopen' и друзьями (просто некоторые эксперименты), но вы пробовали передать флаг' RTLD_LAZY' на 'dlopen'? –

+0

@ Joachim Pileborg: Спасибо за ваш постоянный интерес. Да, я также пробовал это, он просто делает ошибку в другом месте: './app: ошибка поиска символа: ./libdynlib.so: undefined symbol: _Z17doSomethingBoringv'. – Johanna