使用gcc构建共享库

Ser*_*y K 5 c++ gcc shared-libraries

解决了.请参阅下面的更正(标记为FIXED).

我在使用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

修复:正确的命令是:

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.

完整的示例项目如下.(或者您可以使用我帖子顶部的链接下载档案).

serg @ rodent:〜/ libtest $ ls
app共享静态

以下是三个组成部分:

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

这包括以下内容:

serg@rodent:~/libtest$ cd static/  
serg@rodent:~/libtest/static$ ls  
static.cpp  static.h
Run Code Online (Sandbox Code Playgroud)

static.h

// Header file for the static library

int function_inside_static_lib(int arg1, int arg2);
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

组件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;
}
Run Code Online (Sandbox Code Playgroud)

组件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;
}
Run Code Online (Sandbox Code Playgroud)

以下是我用来构建所有这些组件的命令.请注意,我希望调试符号在最终生成的应用程序中可用.理想情况下,我希望能够在应用程序内部进行回溯,并查看共享库和静态库中的符号.

1:构建静态库.我觉得这一步很好:

serg @ rodent:〜/ libtest/static $ g ++ -g -ggdb -c static.cpp -o static.o#参见
serg @ rodent 下面的FIXED版本:〜/ libtest/static $ ar rcs libstatic.a static.o
serg @ rodent:〜/ libtest/static $ ls
libstatic.a static.cpp static.h static.o

修复:上面的第一个命令也必须包含-fPIC.正确的命令是

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

2:构建共享库.我很确定这是我出错的地方.

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#参见下面的FIXED版本serg @ rodent:〜/ libtest/shared $ ls
libshared.so shared.cpp shared.o

修复:上面的第二个命令应该是:

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

此时,如果我运行nm来检查libshared.so中的符号,我在任何地方都看不到function_inside_shared_lib(),即使使用nm的-a和-D选项也是如此.(但是,我确实在shared.o中看到它).

编辑:使用上面的修复程序,符号显示为_Z26function_inside_shared_libii.

3:构建应用程序:

首先,将共享库复制到app文件夹中:

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:undefined symbol:function_inside_shared_lib

这是有道理的,因为我也看不到使用nm的function_inside_shared_lib(),这意味着我可能在步骤2中错误地构建了共享库.

如何在第二步中修复命令,以便正确导出function_inside_shared_lib?

如果你注意到我做了什么奇怪的话,也可以随意给我任何其他建议.我还是个初学者.

nos*_*nos 9

这里有一些错误:

libshared.so是空的

您的Makefile实际上并不在shared.o中链接,它只是创建一个空的共享库.更改

g++ -g -ggdb -fPIC -rdynamic -shared -Lstatic -lstatic -o shared/libshared.so 
Run Code Online (Sandbox Code Playgroud)

g++ -g -ggdb -fPIC -rdynamic -shared -Lstatic -o shared/libshared.so shared/shared.o -lstatic
Run Code Online (Sandbox Code Playgroud)

-ststatic必须在shared/shared.o之后,因为你必须以它们的依赖项的相反顺序指定静态库.

共享库中的所有目标文件都需要-fPIC

您创建一个链接在静态库中的共享库.该静态库也必须使用-fPIC进行编译,否则您将创建一个共享库,其中某些部分无法重定位.更改

g++ -g -ggdb -c static/static.cpp -o static/static.o
Run Code Online (Sandbox Code Playgroud)

g++ -fPIC -g -ggdb -c static/static.cpp -o static/static.o
Run Code Online (Sandbox Code Playgroud)

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");
Run Code Online (Sandbox Code Playgroud)

如果您想动态(dlopen)从共享库中获取内容,这通常是使用C而不是C++从共享对象导出函数的原因之一.过去C++名称的变形从编译器到编译器各不相同,尽管现在它们似乎已经同意了一个不会改变的标准.使用C它更简单,共享库中的符号将与您在源代码中给出的符号相同.