Linux动态库热加载驱动插件机制-示例

🎯 目标

构建一个插件式驱动系统,使主程序能够动态加载外部 .so 驱动,并通过接口调用相应功能。驱动类的注册通过工厂实现,支持 C++ 标准类型和继承体系。


📦 插件机制原理

  • 使用 dlopen() 加载 .so 插件
  • 插件通过静态对象构造自动注册驱动到单例工厂
  • 工厂类存储驱动构造函数(Lambda)
  • 主程序根据名字获取驱动指针并调用接口

🧩 插件结构设计(以相机为例)

1. 驱动接口基类(CameraDriver.h)

#pragma once
#include <vector>
#include <cstdint>

class CameraDriver {
public:
    virtual ~CameraDriver() = default;
    virtual void start() = 0;
    virtual std::vector<uint8_t> capture_image() = 0;
};

2. 工厂注册类模板(CameraRegistry.h)

#pragma once
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>

template <typename T>
class CameraRegistry {
public:
    static CameraRegistry& instance() {
        static CameraRegistry inst;
        return inst;
    }

    void register_driver(const std::string& name, std::function<std::unique_ptr<T>()> creator) {
        creators_[name] = std::move(creator);
    }

    T* get(const std::string& name) {
        if (creators_.count(name)) {
            instances_[name] = creators_[name]();
            return instances_[name].get();
        }
        return nullptr;
    }

private:
    std::unordered_map<std::string, std::function<std::unique_ptr<T>()>> creators_;
    std::unordered_map<std::string, std::unique_ptr<T>> instances_;
};


3. 插件注册辅助模板(RegisterMacro.h)

#pragma once
#include "CameraRegistry.h"
#include <string>

template <typename T>
struct CameraRegister {
    CameraRegister(const std::string& name) {
        CameraRegistry<CameraDriver>::instance().register_driver(name, []() {
            return std::make_unique<T>();
        });
    }
};

// 使用宏简化写法
#define REGISTER_CAMERA_DRIVER(CLASS) \\
    static CameraRegister<CLASS> reg_##CLASS(#CLASS);


4. 插件实现(如 libusb_camera.so)

#include "CameraDriver.h"
#include "RegisterMacro.h"
#include <iostream>

class UsbCamera : public CameraDriver {
public:
    void start() override {
        std::cout << "UsbCamera started\\n";
    }

    std::vector<uint8_t> capture_image() override {
        return {42, 43, 44};
    }
};

REGISTER_CAMERA_DRIVER(UsbCamera)

  • 这里的 REGISTER_CAMERA_DRIVER(UsbCamera) 定义了一个全局静态对象 reg_UsbCamera

  • 动态库被 dlopen 加载时,该静态对象的构造函数会自动执行,完成注册。

  • 主程序无需调用注册函数。

🚀 主程序加载插件并调用

#include "CameraDriver.h"
#include "CameraRegistry.h"
#include <dlfcn.h>
#include <iostream>

int main() {
    void* handle = dlopen("libusb_camera.so", RTLD_LAZY);
    if (!handle) {
        std::cerr << "Failed to load plugin: " << dlerror() << "\\n";
        return 1;
    }

    // 不需要 dlsym 调用注册函数,加载动态库时自动注册
    // 使用注册的驱动
    CameraDriver* driver = CameraRegistry<CameraDriver>::instance().get("UsbCamera");
    if (driver) {
        driver->start();
        auto img = driver->capture_image();
        std::cout << "Image size: " << img.size() << "\\n";
    } else {
        std::cerr << "Driver not found\\n";
    }

    dlclose(handle);
    return 0;
}

🔧 常用系统函数说明

函数名说明
dlopen加载 .so 文件,返回句柄
dlsym获取动态库中的函数地址
dlclose卸载动态库
dlerror获取最近一次 dl 操作的错误信息
dlmopen支持加载多个命名空间的变种 dlopen

✅ 总结

  • 动态库加载时,全局静态对象构造自动注册驱动。
  • 主程序直接通过工厂单例获取驱动实例。
  • 避免手动调用注册函数和暴露 C 符号。
  • 代码更简洁,符合现代 C++ 插件设计理念。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值