代码之家  ›  专栏  ›  技术社区  ›  Lukas S.

使用gcc[关闭]构建共享库

  •  5
  • Lukas S.  · 技术社区  · 14 年前

    解决了的。请参阅下面的更正(标记为“已修复”)。

    我无法使用gcc创建共享库。

    我创建了一个小的示例项目,它与我正在处理的实际项目的结构非常相似。我已将其作为tar.gz存档提供:

    http://209.59.216.197/libtest.tar.gz

    修正:我在这里提供了修正版本:
    http://209.59.216.197/libtest_fixed.tar.gz

    在这个示例项目中,我有一个应用程序(app),它加载我在运行时编写的共享库(lib shared.so),并调用共享库定义的函数:function_inside_shared_lib()。

    反过来,这个共享库使用在静态库(lib static.a)中定义的函数:在静态库()中定义的函数。

    问题是当我构建共享库时,“在共享库中的函数”符号不会被导出。我用“nm”检查了共享库,但符号不在那里。我想知道我用来创建共享库的命令是否正确:

    g++-g-ggdb-fpic-rdynamic-i../static-c shared.cpp-o shared.o
    g++-g-ggdb-fpic-rdynamic-shared-l../static-l static-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-l static

    我使用和不使用-rdynamic以及-fpic尝试了这些命令。结果总是一样的。

    我将Ubuntu10.04(64位)与G++4.4.3版结合使用。

    接下来是完整的示例项目。(或者你可以使用我帖子顶部的链接下载归档文件)。

    serg@啮齿动物:~/libtest$ls
    应用程序共享静态

    以下是三个组成部分:

    组件1:一个静态库,它定义了一个在静态库()内名为函数_的函数。 .

    这包括以下内容:

    serg@rodent:~/libtest$ cd static/  
    serg@rodent:~/libtest/static$ ls  
    static.cpp  static.h
    

    静态的

    // Header file for the static library
    
    int function_inside_static_lib(int arg1, int arg2);
    

    静力触探

    // 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@啮齿动物:~/libtest$cd共享
    serg@啮齿动物:~/libtest/共享$ls
    共享CPP

    共享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@啮齿动物:~/libtest$cd app
    serg@啮齿动物:~/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:建立静态库。我觉得这一步很好:

    serg@啮齿动物:~/libtest/static$g+-g-ggdb-c static.cpp-o static.o请参见下面的固定版本
    serg@啮齿动物:~/libtest/static$ar rcs libstatic.a static.o
    serg@啮齿动物:~/libtest/static$ls
    libstatic.a static.cpp static.h静态.o

    修正:上面的第一个命令也必须包括-fpic。正确的命令是

    G++-G-GGDB-FPIC-C static.cpp-O static.O(静态)

    2:建立共享库。我很确定这就是我要出错的地方。

    serg@啮齿动物:~/libtest/shared$g+-g-ggdb-fpic-rdynamic-i../static-c shared.cpp-o shared.o
    serg@啮齿动物:~/libtest/shared$g+-g-ggdb-fpic-rdynamic-shared-l../static-l static-o libshared.so固定版本见下文 serg@啮齿动物:~/libtest/共享$ls
    libshared.so shared.cpp共享.o

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

    g++-g-ggdb-fpic-rdynamic-shared-l./static-o libshared.so shared.o-l static

    此时,如果我运行nm来检查lib shared.so中的符号,我在任何地方都看不到函数_shared_lib(),即使有nm的-a和-d选项。(不过,我确实在shared.o中看到了它)。

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

    3:构建应用程序:

    首先,将共享库复制到应用程序文件夹中:

    serg@啮齿动物:~/libtest$cp共享/libshared.so应用程序/
    serg@啮齿动物:~/libtest$cd app
    serg@啮齿动物:~/libtest/app$ls
    app.cpp libshared.so版本

    现在编译:

    serg@啮齿动物:~/libtest/app$g++-g-ggdb-ldl-l.-lshared app.cpp-o app
    serg@啮齿动物:~/libtest/app$ls
    应用app.cpp libshared.so

    如果我尝试跑步:

    serg@啮齿动物:~/libtest/app$/app
    应用:加载共享库。
    应用程序:在共享库中查找函数
    错误:找不到函数。
    /home/serg/libtest/app/lib shared.so:未定义的符号:在共享库中的函数_

    这是有意义的,因为我也看不到使用nm的_shared_lib()中的函数_,这意味着我可能在步骤2中错误地构建了共享库。

    如何在第二步修复我的命令,以便正确导出共享库中的函数_?

    如果你注意到我在做一些奇怪的事情,也可以给我其他的建议。我还是个初学者。

    2 回复  |  直到 14 年前
        1
  •  9
  •   nos    14 年前

    这里有一些错误:

    libshared.so为空

    您的makefile实际上没有链接到共享的.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++代码中创建共享库时,函数名和类似的 mangeled 这意味着没有任何函数名与您试图动态加载的字符串“函数库内部”匹配。在静态库上运行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
  •  2
  •   vladmihaisima    14 年前

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

    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是before-lstatic。否则链接器将找不到该函数,并将其设为“未定义”。