2010-08-27 104 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。否则,链接器将不会找到该函数并让它'未定义'。