Linux 上的 C++ 动态共享库

2024-10-09 09:10:00
admin
原创
244
摘要:问题描述:这是使用 g++ 进行动态共享库编译的后续。我正在尝试在 Linux 上用 C++ 创建一个共享类库。我能够编译该库,并且可以使用我在这里和这里找到的教程调用一些(非类)函数。当我尝试使用库中定义的类时,我的问题就开始了。我链接到的第二个教程展示了如何加载用于创建库中定义的类的对象的符号,但没有使用...

问题描述:

这是使用 g++ 进行动态共享库编译的后续。

我正在尝试在 Linux 上用 C++ 创建一个共享类库。我能够编译该库,并且可以使用我在这里和这里找到的教程调用一些(非类)函数。当我尝试使用库中定义的类时,我的问题就开始了。我链接到的第二个教程展示了如何加载用于创建库中定义的类的对象的符号,但没有使用这些对象来完成任何工作。

有谁知道创建共享 C++ 类库的更完整的教程,其中还展示了如何在单独的可执行文件中使用这些类?一个非常简单的教程,展示对象的创建、使用(简单的 getter 和 setter 就足够了)和删除,那就太好了。一个链接或一些开源代码的参考,说明如何使用共享类库,也同样不错。


尽管codelogic和nimrodm的答案确实有效,但我只想补充一点,自从问了这个问题后,我拿起了一本《Linux 编程入门》,它的第一章有示例 C 代码,以及创建和使用静态和共享库的良好解释。这些示例可通过 Google 图书搜索在该书的旧版本中找到。


解决方案 1:

我的类名

#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

我的班级

#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;
}

类用户.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。您的主应用程序无需进行任何更改。

解决方案 2:

下面显示了共享类库 shared.[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)

解决方案 3:

除了以前的答案之外,我想提高人们对这样一个事实的认识:您应该使用RAII(资源获取即初始化)习语来确保处理程序销毁的安全。

这是一个完整的工作示例:

接口声明Interface.hpp::

class Base {
public:
    virtual ~Base() {}
    virtual void foo() const = 0;
};

using Base_creator_t = Base *(*)();

共享库内容:

#include "Interface.hpp"

class Derived: public Base {
public:
    void foo() const override {}
};

extern "C" {
Base * create() {
    return new Derived;
}
}

动态共享库处理程序Derived_factory.hpp::

#include "Interface.hpp"
#include <dlfcn.h>

class Derived_factory {
public:
    Derived_factory() {
        handler = dlopen("libderived.so", RTLD_NOW);
        if (! handler) {
            throw std::runtime_error(dlerror());
        }
        Reset_dlerror();
        creator = reinterpret_cast<Base_creator_t>(dlsym(handler, "create"));
        Check_dlerror();
    }

    std::unique_ptr<Base> create() const {
        return std::unique_ptr<Base>(creator());
    }

    ~Derived_factory() {
        if (handler) {
            dlclose(handler);
        }
    }

private:
    void * handler = nullptr;
    Base_creator_t creator = nullptr;

    static void Reset_dlerror() {
        dlerror();
    }

    static void Check_dlerror() {
        const char * dlsym_error = dlerror();
        if (dlsym_error) {
            throw std::runtime_error(dlsym_error);
        }
    }
};

客户端代码:

#include "Derived_factory.hpp"

{
    Derived_factory factory;
    std::unique_ptr<Base> base = factory.create();
    base->foo();
}

笔记:

  • 为了简洁起见,我将所有内容都放在头文件中。在实际生活中,您当然应该将代码拆分到.hpp.cpp文件之间。

  • new为了简化,我忽略了您想要处理/过载的情况delete

两篇清晰的文章可以了解更多详细信息:

  • C++ dlopen 迷你指南

  • C++ 运行时动态加载共享对象

解决方案 4:

基本上,您应该在要使用共享库中的类的代码中包含类的头文件。然后,在链接时,使用“-l”标志将您的代码与共享库链接。当然,这要求 .so 位于操作系统可以找到它的地方。请参阅3.5. 安装和使用共享库

使用 dlsym 适用于您在编译时不知道要使用哪个库的情况。这听起来不像是这种情况。也许令人困惑的是,无论您是在编译时还是运行时进行链接(使用类似的方法),Windows 都会调用动态加载的库?如果是这样,那么您可以将 dlsym 视为 LoadLibrary 的等价物。

如果您确实需要动态加载库(即,它们是插件),那么这个常见问题解答应该会有所帮助。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用