2012-10-06 172 views
2

我嘗試使用dlopen()將共享庫加載到另一個共享庫時遇到問題。我檢查了所有關於如何正確使用dlopen()的教程。所以這裏是簡化的代碼:C++:使用dlopen()加載共享庫時未定義符號

主共享庫包含一個具有純共享庫(aka插件)必須實現的純虛函數的類。此外,它還有一些其他功能,這些功能是通過默認行爲來實現的。我創建了一個宏,將其添加到每個插件中,以便加載符號並創建該類。

主共享庫

plugin.h:

Class A { 
public: 
    virtual int func1() = 0; 
    virtual bool func2() const; 
} 

#define CREATE_CLASS(cls) extern "C" void *CreateClass(void) { return new cls; } 

plugin.cpp:

bool A::func2() const { return true; } 

構建和鏈接main.so

g++ -g -Wall -Woverloaded-virtual -Wno-parentheses -O2 -fPIC -c -o plugin.o plugin.cpp 
g++ -g -Wall -Woverloaded-virtual -Wno-parentheses -O2 -fPIC -rdynamic -shared plugin.o -ldl -o main-plugin.so 

子共享庫只執行純虛函數。另一個函數可以被覆蓋,儘管它是可選的。

子共享庫

插件-impl.cpp

Class B : public A { 
public: 
    virtual int func1() { return 0; } 
} 

CREATE_CLASS(B) 

這些是編譯並鏈接子共享庫的行。

構建和鏈接sub.so

g++ -g -O3 -Wall -Werror=overloaded-virtual -Wno-parentheses -fPIC -c -o subPlugin.o subPlugin.cpp 
g++ -g -O3 -Wall -Werror=overloaded-virtual -Wno-parentheses -fPIC -shared subPlugin.o -o subPlugin.so 

這是打開子共享庫行。我嘗試了懶惰,現在,現在| GLOBAL等,沒有任何影響。

的dlopen()在主共享庫的地方撥打:

handle = dlopen(file.c_str(), RTLD_LAZY); 

大部分是工作得很好。但是,當我嘗試將子共享庫加載到主共享庫時,dlopen抱怨未定義的符號bool A::func2() const。該函數只存在於主共享庫中,所以我猜它必須導出。請幫助我!我很困擾!

SOLUTION

因爲我不能改變可執行,我要通過添加下列選項的主共享庫與子共享圖書館的鏈接到g ++:

-L$(PLUGINDIR) -Wl,-R$(PLUGINDIR) -lmain-shared 

有了這個設置,則不需要設置LD_LIBRARY_PATH

+1

另一位程序員沒有通知自己有關名稱變形... – 2012-10-06 19:05:49

+0

@ H2CO3呃,這是所有的C++,沒有C這裏。名稱的修改與它沒有任何關係嗎? –

+0

@SethCarnegie糾正我,如果我錯了,但是不是名稱在C++中存在而不在C中嗎? – 2012-10-06 19:10:03

回答

3

由於您的子庫需要來自主庫的符號,因此我認爲您希望它與其鏈接。請嘗試將這樣的:

g++ -g -O3 -Wall -Werror=overloaded-virtual -Wno-parentheses -fPIC -shared 
    -lmain-plugin subPlugin.o -o subPlugin.so 

可能是你需要-L以及玩。

這是我的嘗試:加載main-library

[email protected]:/tmp$ cat executable.cpp 
#include <dlfcn.h> 
#include <stdio.h> 
int main() 
{ 
    dlopen("./main-library.so", RTLD_NOW); 
    void* handle=dlopen("./sub-library.so", RTLD_LAZY); 
    printf("%x %s", dlsym(handle, "CreateClass"), dlerror()); 
} 
[email protected]:/tmp$ cat main-library.cpp 
class A { 
public: 
    virtual int func1() = 0; 
    virtual bool func2() const; 
}; 

#define CREATE_CLASS(cls) extern "C" void *CreateClass(void) { return new cls; } 

bool A::func2() const { return true; } 
[email protected]:/tmp$ cat sub-library.cpp 
class A { 
public: 
    virtual int func1() = 0; 
    virtual bool func2() const; 
}; 

#define CREATE_CLASS(cls) extern "C" void *CreateClass(void) { return new cls; } 

class B : public A { 
public: 
    virtual int func1() { return 0; } 
}; 

CREATE_CLASS(B) 

[email protected]:/tmp$ g++ -g -Wall -Woverloaded-virtual -Wno-parentheses -O2 -fPIC -rdynamic -shared main-library.cpp -ldl -o main-library.so 
[email protected]:/tmp$ g++ -g -O3 -Wall -Werror=overloaded-virtual -Wno-parentheses -fPIC -shared -l:main-library.so sub-library.cpp -o sub-library.so 
[email protected]:/tmp$ g++ -ldl executable.cpp -o executable 
[email protected]:/tmp$ LD_LIBRARY_PATH=. ./executable 
b7713740 (null) 

另一種可能性是將RTLD_GLOBAL

[email protected]:/tmp$ cat executable.cpp 
#include <dlfcn.h> 
#include <stdio.h> 
int main() 
{ 
    dlopen("./main-library.so", RTLD_LAZY | RTLD_GLOBAL); 
    void* handle=dlopen("./sub-library.so", RTLD_LAZY); 
    printf("%x %s", dlsym(handle, "CreateClass"), dlerror()); 
} 

這樣的話,則不必main-library.so鏈接什麼。

+0

嗯,這不起作用,因爲subPlugins需要在運行時加載。另外,我只是向主共享庫提供接口,而其他人可能會動態添加子共享庫。我不知道編譯時插件的數量。 –

+0

@DenisLoh:我認爲你誤會了 - 我建議你將每個子庫鏈接到主庫,而不是將主庫(或可執行文件)與所有子庫鏈接起來。 – jpalecek

+0

啊,對不起。我只是混在一起。我會試一試。 –

相關問題