首页 文章

Linux上的C动态共享库

提问于
浏览
145

这是Dynamic Shared Library compilation with g++的后续行动 .

我'm trying to create a shared class library in C++ on Linux. I'能够编译库,我可以使用我找到的herehere教程调用一些(非类)函数 . 当我尝试使用库中定义的类时,我的问题开始了 . 我链接的第二个教程展示了如何加载符号来创建库中定义的类的对象,但是没有使用这些对象来完成任何工作 .

有没有人知道更完整的创建共享C类库的教程,该教程还展示了如何在单独的可执行文件中使用这些类?一个非常简单的教程,显示对象创建,使用(简单的getter和setter会很好),删除将是太棒了 . 一些链接或对一些开源代码的引用说明了共享类库的使用同样很好 .


尽管codelogicnimrodm的答案确实有效,但我只是想补充一下,自从提出这个问题后我拿起了Beginning Linux Programming的副本,其第一章有示例C代码以及创建和使用静态库和共享库的良好解释 . 这些示例可在an older edition of that book中通过Google图书搜索获得 .

3 回答

  • 133

    下面显示了共享的共享类库的示例 . [h,cpp]和使用该库的main.cpp模块 . 这是一个非常简单的例子,makefile可以做得更好 . 但它有效并可能对您有所帮助:

    shared.h定义了类:

    class myclass {
       int myx;
    
      public:
    
        myclass() { myx=0; }
        void setx(int newx);
        int  getx();
    };
    

    shared.cpp定义了getx / setx函数:

    #include "shared.h"
    
    void myclass::setx(int newx) { myx = newx; }
    int  myclass::getx() { return myx; }
    

    main.cpp使用该类,

    #include <iostream>
    #include "shared.h"
    
    using namespace std;
    
    int main(int argc, char *argv[])
    {
      myclass m;
    
      cout << m.getx() << endl;
      m.setx(10);
      cout << m.getx() << endl;
    }
    

    以及生成libshared.so并将main链接到共享库的makefile:

    main: libshared.so main.o
        $(CXX) -o main  main.o -L. -lshared
    
    libshared.so: shared.cpp
        $(CXX) -fPIC -c shared.cpp -o shared.o
        $(CXX) -shared  -Wl,-soname,libshared.so -o libshared.so shared.o
    
    clean:
        $rm *.o *.so
    

    要实际运行'main'并与libshared.so链接,您可能需要指定加载路径(或将其放在/ usr / local / lib或类似文件中) .

    以下指定当前目录作为库的搜索路径并运行main(bash语法):

    export LD_LIBRARY_PATH=.
    ./main
    

    要查看程序是否与libshared.so链接,您可以尝试ldd:

    LD_LIBRARY_PATH=. ldd main
    

    在我的机器上打印:

    ~/prj/test/shared$ LD_LIBRARY_PATH=. ldd main
        linux-gate.so.1 =>  (0xb7f88000)
        libshared.so => ./libshared.so (0xb7f85000)
        libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb7e74000)
        libm.so.6 => /lib/libm.so.6 (0xb7e4e000)
        libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0xb7e41000)
        libc.so.6 => /lib/libc.so.6 (0xb7cfa000)
        /lib/ld-linux.so.2 (0xb7f89000)
    
  • 49

    基本上,您应该在要在共享库中使用该类的代码中包含类的头文件 . 然后,当您链接时,use the '-l' flag将您的代码链接到共享库 . 当然,这需要.so是操作系统可以找到它的地方 . 见3.5. Installing and Using a Shared Library

    使用dlsym是为了在编译时不知道要使用哪个库 . 这听起来不像是这里的情况 . 也许混淆是Windows调用动态加载的库,无论你是在编译还是运行时进行链接(使用类似的方法)?如果是这样,那么您可以将dlsym视为LoadLibrary的等价物 .

    如果你真的需要动态加载库(即它们是插件),那么this FAQ应该有所帮助 .

  • 8

    myclass.h

    #ifndef __MYCLASS_H__
    #define __MYCLASS_H__
    
    class MyClass
    {
    public:
      MyClass();
    
      /* use virtual otherwise linker will try to perform static linkage */
      virtual void DoSomething();
    
    private:
      int x;
    };
    
    #endif
    

    myclass.cc

    #include "myclass.h"
    #include <iostream>
    
    using namespace std;
    
    extern "C" MyClass* create_object()
    {
      return new MyClass;
    }
    
    extern "C" void destroy_object( MyClass* object )
    {
      delete object;
    }
    
    MyClass::MyClass()
    {
      x = 20;
    }
    
    void MyClass::DoSomething()
    {
      cout<<x<<endl;
    }
    

    class_user.cc

    #include <dlfcn.h>
    #include <iostream>
    #include "myclass.h"
    
    using namespace std;
    
    int main(int argc, char **argv)
    {
      /* on Linux, use "./myclass.so" */
      void* handle = dlopen("myclass.so", RTLD_LAZY);
    
      MyClass* (*create)();
      void (*destroy)(MyClass*);
    
      create = (MyClass* (*)())dlsym(handle, "create_object");
      destroy = (void (*)(MyClass*))dlsym(handle, "destroy_object");
    
      MyClass* myClass = (MyClass*)create();
      myClass->DoSomething();
      destroy( myClass );
    }
    

    在Mac OS X上,使用以下命令编译:

    g++ -dynamiclib -flat_namespace myclass.cc -o myclass.so
    g++ class_user.cc -o class_user
    

    在Linux上,编译:

    g++ -fPIC -shared myclass.cc -o myclass.so
    g++ class_user.cc -ldl -o class_user
    

    如果这是针对插件系统的,那么您将使用MyClass作为基类并将所有必需的函数定义为虚拟 . 然后,插件作者将从MyClass派生,覆盖虚拟并实现 create_objectdestroy_object . 您的主应用程序无需以任何方式进行更改 .

相关问题