使用gcc构建共享库

12

已解决。请参见以下更正 (标有 FIXED)。

我在使用gcc创建共享库时遇到了问题。

我创建了一个小样本项目,它与我正在工作的实际项目的结构非常相似。我已将其制作成tar.gz存档,并上传至以下地址:

http://209.59.216.197/libtest.tar.gz

FIXED: 我已将修正版放在以下地址:
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的这些命令。结果总是一样。

我正在使用g ++版本4.4.3的Ubuntu 10.04 (64位)。

以下是完整的示例项目。(或者您可以使用我的文章顶部的链接下载档案)。

serg@rodent:~/libtest$ ls
app shared static

以下是三个组件:

组件1:定义名为function_inside_static_lib()的函数的静态库

它由以下内容组成:

serg@rodent:~/libtest$ cd static/  
serg@rodent:~/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:一个共享库,使用静态库并定义了一个新函数。

serg@rodent:~/libtest$ cd shared
serg@rodent:~/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: 使用共享库的应用程序。

serg@rodent:~/libtest$ cd app
serg@rodent:~/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;
}
这是我用于构建所有组件的命令。请注意,我希望在最终生成的应用程序中提供调试符号。理想情况下,我希望能够在应用程序内部进行回溯,并查看共享库和静态库中的符号。
1:构建静态库。我认为这一步没问题:
```bash serg@rodent:~/libtest/static$ g++ -g -ggdb -c static.cpp -o static.o serg@rodent:~/libtest/static$ ar rcs libstatic.a static.o serg@rodent:~/libtest/static$ ls libstatic.a static.cpp static.h static.o ```
**修正:上面的第一个命令也必须包括 -fPIC。正确的命令是:**
```bash g++ -g -ggdb -fPIC -c static.cpp -o static.o ```
2:构建共享库。我很确定这是我出错的地方。
```bash serg@rodent:~/libtest/shared$ g++ -g -ggdb -fPIC -rdynamic -I ../static -c shared.cpp -o shared.o serg@rodent:~/libtest/shared$ g++ -g -ggdb -fPIC -rdynamic -shared -L ../static -lstatic -o libshared.so serg@rodent:~/libtest/shared$ ls libshared.so shared.cpp shared.o ```
**修正:上面的第二个命令应该是:**
```bash g++ -g -ggdb -fPIC -rdynamic -shared -L../static -o libshared.so shared.o -lstatic ```
此时,如果我运行 nm 命令来检查 libshared.so 中的符号,我无论是否使用 nm 的 -a 和 -D 选项,都看不到 `function_inside_shared_lib()` 函数的任何信息(但是,我可以在 shared.o 文件中看到它)。
编辑:使用上面的修正,符号将显示为 `_Z26function_inside_shared_libii`。
3:构建应用程序:
首先将共享库复制到应用程序文件夹中:
```bash serg@rodent:~/libtest$ cp shared/libshared.so app/ serg@rodent:~/libtest$ cd app serg@rodent:~/libtest/app$ ls app.cpp libshared.so ```
现在进行编译:serg@rodent:~/libtest/app$ g++ -g -ggdb -ldl -L. -lshared app.cpp -o app serg@rodent:~/libtest/app$ ls app app.cpp libshared.so
如果我尝试运行: serg@rodent:~/libtest/app$ ./app app:正在加载共享库。 app:查找function_inside_shared_lib。 错误:找不到该函数。 /home/serg/libtest/app/libshared.so:未定义的符号:function_inside_shared_lib。
这是因为在步骤2中,我可能没有正确地构建共享库,使用nm也看不到function_inside_shared_lib(),因此需要修复第二步命令以使其正确导出function_inside_shared_lib。如果您注意到我执行任何奇怪操作,请随时给予建议。我还是初学者。

http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html - Anycorn
那个用于构建共享对象库的命令看起来不对,它没有提及 shared.o。你输入正确了吗? - Beta
这是一个问题还是十七个问题或者十七个答案?我已经分不清了... - Lightness Races in Orbit
类似问题 - https://dev59.com/IWUp5IYBdhLWcg3w_rkl - sashoalm
2个回答

14

这里有几个错误:

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/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++代码创建共享库,因此函数名称等内容会被重整。 这意味着当你尝试动态加载名为“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");

如果您想要从共享库中动态地(dlopen)获取某些内容,那么使用C语言将函数导出到共享对象比使用C++更好的原因之一是,C++名称重载以前曾经因编译器而异,尽管现在它们似乎已经达成了一个不会改变的标准。使用C语言更简单,共享库中的符号与您在源代码中给定的符号相同。


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

同样重要的是,在-lstatic之前需要放置shared.o。否则,链接器将找不到该函数并将其视为“未定义”。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接