2010-08-27 148 views
4

已解決。請參閱下面的更正(標記爲FIXED)。使用gcc構建共享庫

我在使用gcc創建共享庫時遇到了問題。

我創建了一個小樣本項目,它與我正在處理的實際項目的結構非常接近。我做了它可以作爲一個tar.gz檔案位置:

http://209.59.216.197/libtest.tar.gz

固定:我已經提供了固定的版本在這裏:
http://209.59.216.197/libtest_fixed.tar.gz

在此示例項目,我有一個應用程序(app)加載我在運行時編寫的共享庫(libshared.so),並調用共享庫定義的函數:function_inside_shared_lib()。

反過來,此共享庫使用靜態庫(libstatic.a)中定義的函數:function_inside_static_lib()。

問題是當我構建共享庫時,符號「function_inside_shared_lib」不能被導出。我使用「nm」檢查了共享庫,但符號不存在。我想知道如果我使用創建的共享庫的命令是正確的:

g++ -g -ggdb -fPIC -rdynamic -I ../static -c shared.cpp -o shared.o
g++ -g -ggdb -fPIC -rdynamic -shared -L ../static -lstatic -o libshared.so

FIXED:正確的命令是:

g++ -g -ggdb -fPIC -rdynamic -I../static -c shared.cpp -o shared.o
g++ -g -ggdb -fPIC -rdynamic -shared -L../static -o libshared.so shared.o -lstatic

我試圖與不-rdynamic這些命令,以及帶和不帶-fPIC。結果總是一樣的。

我使用Ubuntu 10.04(64位)與g ++版本4.4.3。

下面是完整的示例項目。 (或者您可以使用我的文章頂部的鏈接下載該檔案)。

[email protected]:~/libtest$ ls
app shared static

這裏有三個組成部分:

組分1:定義一個函數調用function_inside_static_lib()靜態庫。

這包括以下的:

[email protected]:~/libtest$ cd static/ 
[email protected]:~/libtest/static$ ls 
static.cpp static.h 

static.h

// Header file for the static library 

int function_inside_static_lib(int arg1, int arg2); 

static.cpp

// Source file for the static library 

#include <iostream> 
using namespace std; 

#include "static.h" 

int function_inside_static_lib(int arg1, int arg2) 
{ 
    cout << "In function_inside_static_lib()" << endl; 

    // Return the sum 
    int result = arg1 + arg2; 
    return result; 
} 

組件2:使用靜態庫並定義新功能的共享庫。

[email protected]:~/libtest$ cd shared
[email protected]:~/libtest/shared$ ls
shared.cpp

shared.cpp

// The shared library only has one source file. 

// The shared library uses the static one. 
#include "static.h" 

#include <iostream> 
using namespace std; 

int function_inside_shared_lib(int arg1, int arg2) 
{ 
    cout << "In function_inside_shared_lib()" << endl; 

    cout << "Calling function_inside_static_lib()" << endl; 
    int result = function_inside_static_lib(arg1, arg2); 

    return result; 
} 

組分3:使用共享庫中的應用。

[email protected]:~/libtest$ cd app
[email protected]:~/libtest/app$ ls
app.cpp

app.cpp

修正:由於C++符號得到錯位,正確的函數名稱搜索是_Z26function_inside_static_libii,而不是function_inside_static_lib

// The application loads the shared library at runtime. 

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

using namespace std; 

int main(int argc, char **argv) 
{ 
    void *handle; 
    int (*function_inside_shared_lib)(int, int); 
    char *error; 

    int arg1 = 3; 
    int arg2 = 7; 

    cout << "app: loading the shared library." << endl; 
    handle = dlopen ("libshared.so", RTLD_LAZY); 
    if (!handle) { 
     cout << "Error: Failed to open shared library." << endl; 
     cout << dlerror() << endl; 
     return -1; 
    } 

    cout << "app: Looking for function_inside_shared_lib" << endl; 

    // The next line is now FIXED: 
    function_inside_shared_lib = (int (*)(int, int))dlsym(handle, "_Z26function_inside_static_libii"); 

    if ((error = dlerror()) != NULL) { 
     cout << "Error: Could not find the function." << endl; 
     cout << error << endl; 
     return -1; 
    } 

    cout << "app: Calling function_inside_shared_lib(" << arg1 << ", " << arg2 << ")" << endl; 
    int result = (*function_inside_shared_lib)(arg1, arg2); 

    cout << "app: The result is " << result << endl; 

    dlclose(handle); 
    return 0; 
} 

這裏是我用來構建所有的命令se組件。請注意,我希望調試符號在最終生成的應用程序中可用。理想情況下,我希望能夠在應用程序內部進行回溯,並查看共享庫和靜態庫中的符號。

1:構建靜態庫。我覺得我很好用此步驟:

[email protected]:~/libtest/static$ g++ -g -ggdb -c static.cpp -o static.o # See the FIXED version just below
[email protected]:~/libtest/static$ ar rcs libstatic.a static.o
[email protected]:~/libtest/static$ ls
libstatic.a static.cpp static.h static.o

固定:上面的第一個命令必須包含-fPIC爲好。正確的命令是

g++ -g -ggdb -fPIC -c static.cpp -o static.o

2:構建共享庫。我很確定這是我出錯的地方。

[email protected]:~/libtest/shared$ g++ -g -ggdb -fPIC -rdynamic -I ../static -c shared.cpp -o shared.o
[email protected]:~/libtest/shared$ g++ -g -ggdb -fPIC -rdynamic -shared -L ../static -lstatic -o libshared.so # See just below for FIXED version [email protected]:~/libtest/shared$ ls
libshared.so shared.cpp shared.o

FIXED:上述第二個命令應該是:

g++ -g -ggdb -fPIC -rdynamic -shared -L../static -o libshared.so shared.o -lstatic

此時,如果用完納米至檢查內部libshared.so符號,我沒有看到function_inside_shared_lib()在任何地方,即使使用nm的-a和-D選項。 (但是,我確實在shared.o中看到它)。

編輯:與上面的修復程序,該符號顯示爲_Z26function_inside_shared_libii

3:構建應用程序:

首先,共享庫複製到應用程序文件夾:

[email protected]:~/libtest$ cp shared/libshared.so app/
[email protected]:~/libtest$ cd app
[email protected]:~/libtest/app$ ls
app.cpp libshared.so

現在編譯:

[email protected]:~/libtest/app$ g++ -g -ggdb -ldl -L. -lshared app.cpp -o app
[email protected]:~/libtest/app$ ls
app app.cpp libshared.so

如果我嘗試運行:

[email protected]:~/libtest/app$ ./app
app: loading the shared library.
app: Looking for function_inside_shared_lib
Error: Could not find the function.
/home/serg/libtest/app/libshared.so: undefined symbol: function_inside_shared_lib

這很有道理,因爲我看不到使用nm的function_inside_shared_lib(),這意味着我可能在第2步中錯誤地構建了共享庫。

如何在第二步修復我的命令以便function_inside_shared_lib正確導出?

如果你發現我做了什麼奇怪的事情,還可以給我任何其他建議。我還是個初學者。

+0

http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries。html – Anycorn 2010-08-27 22:27:44

+0

構建共享對象庫的命令看起來不正確 - 它沒有提到shared.o。你輸入的內容是否正確? – Beta 2010-08-27 23:08:43

+0

這是一個問題還是十七個問題或十七個答案?我不能告訴任何更多... – 2012-12-27 22:05:32

回答

9

這裏有幾個誤區:

libshared.so是空

你的Makefile不會在shared.o實際上鍊接,它只是創建一個空的共享庫。 變化

g++ -g -ggdb -fPIC -rdynamic -shared -Lstatic -lstatic -o shared/libshared.so 

g++ -g -ggdb -fPIC -rdynamic -shared -Lstatic -o shared/libshared.so shared/shared.o -lstatic 

的-lstatic要來共享/ shared.o後,你在他們的依賴性相反的順序來指定靜態庫。在共享庫

您創建一個靜態庫鏈接共享庫,需要對所有的目標文件

-fPIC。該靜態庫也必須使用-fPIC進行編譯,否則您將創建一個共享庫,其中某些部分無法重新定位。更改

g++ -g -ggdb -c static/static.cpp -o static/static.o 

g++ -fPIC -g -ggdb -c static/static.cpp -o static/static.o 

C++符號得到錯位

當您正在從C++代碼,函數名的共享庫和類似得到mangeled 這意味着沒有函數名稱與您嘗試動態加載的字符串「function_inside_static_lib」匹配。在靜態庫上運行nm,你會看到它實際上被命名爲「_Z26function_inside_static_libii」。你可以運行nm -C來打印C++的名字。

這意味着app.cpp你的代碼必須是:

function_inside_shared_lib = (int (*)(int, int))dlsym(handle, "_Z26function_inside_static_libii"); 

這是它往往preferrable從用C代替C++,如果你想動態共享對象導出功能的原因之一(dlopen的)從共享庫中獲取某些內容。過去的C++名稱在編譯器和編譯器中各不相同,儘管目前它們似乎已經同意一個不會改變的標準。使用C更簡單,共享庫中的符號與源代碼中的符號相同。

+0

謝謝!這做到了! – 2010-08-28 00:47:19

2

因此,在第2步中,您不指定shared.o。因此,而不是:

g++ -g -ggdb -fPIC -rdynamic -shared -L ../static -lstatic -o libshared.so 

你應該這樣做:

g++ -g -ggdb -fPIC -rdynamic -shared -L ../static shared.o -lstatic -o libshared.so 

還有一點很重要的是shared.o是前-lstatic。否則,鏈接器將不會找到該函數並讓它'未定義'。