Loading shared libraries and classes dynamically at runtime.

Poco sharelibrary提供了在运行时加载动态库的方式
概述:
->Shared Lirbrary
->The Class Loader

shared library

  • ->Most modern platforms provide facilities to load program modules in the form of shared libraries (dynamic link libraries) at runtime.
    大多数现代平台都提供了在运行时以共享库(动态链接库)的形式加载程序模块的工具。

  • ->Windows provides a LoadLibrary() function, most Unix platforms have dlopen().
    windows 平台提供了 loadlibrary()函数,大多数unix平台提供了dlopen()函数

  • ->To use a dynamically loaded shared library, an entry point (address of a function) into the library must be found. The address can then be casted to an appropriate function pointer,and the function can be called.
    使用动态的加载动态库,必须找到库的一个入口点(函数地址),然后可以将地址转化成为适当的函数指针,并且可以调用该函数

The SharedLibrary Class

  • -> Poco::SharedLibrary is POCO’s interface to the operating system’s dynamic linker/loader.
    Poco :: SharedLibrary是POCO与操作系统动态链接器/加载器的接口。

  • -> #include “Poco/SharedLibrary.h”
    包含头文件

  • -> Poco::SharedLibrary provides low-level functions for loading a shared library, for looking up the address of a symbol, and for unloading a shared library.
    Poco :: SharedLibrary提供了用于加载共享库,查找符号地址和卸载共享库的低级函数。

SharedLibrary Functions

  • -> void load(const std::string& path)
    从给定路径加载共享库

  • ->void unload()
    卸载动态库

  • ->bool hasSymbol(const std::string& name)
    如果库包含具有给定名称的链接符号,则返回true

  • ->void* getSymbol(const std::string& name)
    返回具有给定名称的符号的地址。 对于函数,这是函数的入口点。 要调用该函数,强制转换为函数指针并通过它调用。

使用例子

#include <iostream>
#if defined(_WIN32)
#define LIBRARY_API __declspec(dllexport)
#else
#define LIBRARY_API
#endif
extern "C" void LIBRARY_API hello();
void hello()
{
    std::cout << "Hello, world!" << std::endl;
}
// LibraryLoaderTest.cpp
#include "Poco/SharedLibrary.h"
using Poco::SharedLibrary;
typedef void (*HelloFunc)(); // function pointer type
int main(int argc, char** argv)
{
    std::string path("TestLibrary");
    path.append(SharedLibrary::suffix()); // adds ".dll" or ".so"
    SharedLibrary library(path); // will also load the library
    HelloFunc func = (HelloFunc) library.getSymbol("hello");
    func();
    library.unload();
    return 0;
}

The Class Loader

  • ->Poco::ClassLoader is POCO’s high level interface for loading classes from shared libraries. It is well suited for implementing typical plug-in architectures.
    Poco :: ClassLoader是POCO的高级接口,用于从共享库加载类。 它非常适合实现典型的插件架构。

  • ->#include “Poco/ClassLoader.h”

  • ->All classes loaded with a specific class loader must be subclasses of a common base class. Poco::ClassLoader is a class template that must be instantiated for the base class.
    所有加载了特定类加载器的类都必须是公共基类的子类。 Poco :: ClassLoader是一个必须为基类实例化的类模板。

  • ->A base class is necessary because the application loading a plugin needs an interface to access it.
    基类是必需的,因为加载插件的应用程序需要一个接口来访问它。

The Class Loader (cont’d)

  • ->A shared library that is used with the class loader can only export classes that have a common base class.
    与类加载器一起使用的共享库只能导出具有公共基类的类。

  • ->However, this is not really a restriction, because the exported class can be a factory for objects of arbitrary classes.
    但是,这并不是一个限制,因为导出的类可以是任意类对象的工厂。

  • ->A shared library used with the class loader exports a Manifest describing all classes exported by the library.
    与类加载器一起使用的共享库导出一个Manifest,用于描述库导出的所有类。

  • ->Furthermore, the shared library must export specific functions that are used by the class loader.
    此外,动态库必须导出特殊的的函数在用类加载的时候

  • ->POCO provides macros that automate the implementation of these functions.
    POCO提供自动执行这些功能的宏。

Manifest and MetaObject

  • ->A library’s Manifest maintains a list of all classes contained in a dynamically loadable class library.
    库的Manifest维护一个动态可加载类库中包含的所有类的列表。

  • ->It manages that information as a collection of meta objects
    它将该信息作为元对象的集合进行管理

  • ->A MetaObject manages the lifetime of objects of a given class. It is used to create instances of a class, and to delete them.
    MetaObject管理给定类的对象的生命周期。 它用于创建类的实例,并删除它们。

  • ->As a special feature, class libraries can export singletons.
    作为一个特殊功能,类库可以导出单例。

The MetaObject Class

  • ->MetaObject<Class, Base> is a class template, instantiated with the class it maintains, and its lowest base class.
    MetaObject <Class,Base>是一个类模板,使用它维护的类进行实例化,以及它的最低基类。

  • ->MetaObject<Class, Base> is derived from AbstractMetaObject.
    MetaObject<Class, Base> 是继承自 AbstractMetaObject

  • ->A MetaObject can be used to create new instances of a class (unless the class is exported as a singleton)
    MetaObject可用于创建类的新实例(除非将类导出为单例)

  • ->Like a AutoReleasePool, a MetaObject can take care of no longer needed objects.
    与AutoReleasePool一样,MetaObject可以处理不再需要的对象。

  • ->A MetaObject can manage singletons
    MetaObject可以管理单例

The MetaObject Class (cont’d)

  • ->const char* name()
    返回类的名字

  • -> Base* create() const
    创建一个新的Class实例,除非它是一个单例。

  • -> Base& instance() const
    返回对单例的唯一实例的引用。

  • -> bool canCreate() const
    如果可以创建新实例,则返回true;如果类是单例,则返回false。

  • -> Base* autoDelete(Base* pObject)
    将对象的所有权赋予MetaObject。 MetaObject将删除它在销毁时拥有的所有对象。

  • ->bool isAutoDelete(Base* pObject)
    如果MetaObject拥有pObject,则返回true,否则返回false。
  • ->void destroy(Base* pObject)
    如果MetaObject拥有pObject,它将立即被删除

The MetaSingletonClass

  • ->This is a sister class of MetaObject used for managing singletons.
    这是用于管理单例的MetaObject的相关类。

  • ->It has the same interface as MetaObject.
    它与MetaObject具有相同的接口。

The Manifest Class

  • ->Poco::Manifest basically is a collection of meta objects.
    Poco :: Manifest基本上是元对象的集合。

  • ->#include “Poco/Manifest.h”

  • ->Poco::Manifest::Iterator is used to iterate over its meta objects.
    Poco :: Manifest :: Iterator用于迭代其元对象。

  • ->Manifest::Iterator find(const std::string& className)
    返回指向给定类的元对象的迭代器,如果找不到类,则返回结束迭代器。

  • ->Manifest::Iterator begin() const

  • Manifest::Iterator end() const
    分别返回begin和end迭代器。

Writing a Class Library

  • ->For a class library to work with the class loader, it must export a manifest.
    对于使用类加载器的类库,它必须导出清单。

  • ->The class library must provide a function
    bool pocoBuildManifest(ManifestBase* pManifest)
    that builds a manifest for the library

    类库必须提供一个函数,为库构建清单。

  • ->The Poco/ClassLibrary.h header file provides macros to automatically implement this function for a class library
    Poco / ClassLibrary.h头文件提供了自动为类库实现此功能的宏

  • ->Optionally, a class library can export an initialization and a clean up function.
    或者,一个类库可以导出初始化和清理功能。

Writing a Class Library (cont’d)

  • -> These macros are used as follows:
    POCO_BEGIN_MANIFEST(MyBaseClass)
    POCO_EXPORT_CLASS(MyFirstClass)
    POCO_EXPORT_CLASS(MySecondClass)
    POCO_EXPORT_SINGLETON(MySingleton)
    POCO_END_MANIFEST

  • -> A class library can export a setup and a cleanup function:
    void pocoInitializeLibrary()
    void pocoUninitializeLibrary()
    which will be called by the class loader, if present.

The Class Loader (again)

  • -> A ClassLoader maintains a collection of class libraries, as well as their manifests.
    ClassLoader维护一个类库集合及其清单。

  • ->void loadLibrary(const std::string& path)
    将类库添加到内存中并运行设置功能(如果存在)。

  • ->void unloadLibrary(const std::string& path)
    卸载类库。

  • ->!!Never unload a class library if there are still objects from this library around in memory.
    如果内存中仍有来自此库的对象,则永远不要卸载类库。

The Class Loader (again, cont’d)

  • ->const Meta* findClass(const std::string& className) const
    在所有已加载的库中查找给定类的元对象。如果找到则返回指向元对象的指针,否则返回null。

  • ->const Meta& classFor(const std::string& className)
    类似于findClass(),但如果该类未知,则抛出NotFoundException。

  • ->Base* create(const std::string& className)
    如果类未知,则创建类的新实例或抛出NotFoundException。

  • ->Base& instance(const std::string& className)
    如果类未知,则返回对单例类的唯一实例的引用或抛出NotFoundException。

  • -> Iterator begin() const
    Iterator end() const

    返回一个开始/结束迭代器,用于迭代所有已加载库的清单。 取消引用迭代器将返回一个指向std :: pair的指针,该对包含类库的路径和指向其清单的指针。

示例代码:

// AbstractPlugin.h
//
// This is used both by the class library and by the application.
#ifndef AbstractPlugin_INCLUDED
#define AbstractPlugin_INCLUDED
class AbstractPlugin
{
    public:
    AbstractPlugin();
    virtual ~AbstractPlugin();
    virtual std::string name() const = 0;
};
#endif // AbstractPlugin.h
// AbstractPlugin.cpp
//
// This is used both by the class library and by the application.
#include "AbstractPlugin.h"
AbstractPlugin::AbstractPlugin()
{
}
AbstractPlugin::~AbstractPlugin()
{
}
// PluginLibrary.cpp
#include "AbstractPlugin.h"
#include "Poco/ClassLibrary.h"
#include <iostream>
class PluginA: public AbstractPlugin
{
    public:
    std::string name() const
    {
    return "PluginA";
    }
};
class PluginB: public AbstractPlugin
{
    public:
    std::string name() const
    {
    return "PluginB";
    }
};
POCO_BEGIN_MANIFEST(AbstractPlugin)
POCO_EXPORT_CLASS(PluginA)
POCO_EXPORT_CLASS(PluginB)
POCO_END_MANIFEST
// optional set up and clean up functions
void pocoInitializeLibrary()
{
    std::cout << "PluginLibrary initializing" << std::endl;
}
void pocoUninitializeLibrary()
{
    std::cout << "PluginLibrary uninitializing" << std::endl;
}
// main.cpp
#include "Poco/ClassLoader.h"
#include "Poco/Manifest.h"
#include "AbstractPlugin.h"
#include <iostream>
typedef Poco::ClassLoader<AbstractPlugin> PluginLoader;
typedef Poco::Manifest<AbstractPlugin> PluginManifest;
int main(int argc, char** argv)
{
    PluginLoader loader;
    std::string libName("PluginLibrary");
    libName += Poco::SharedLibrary::suffix(); // append .dll or .so
    loader.loadLibrary(libName);
    PluginLoader::Iterator it(loader.begin());
    PluginLoader::Iterator end(loader.end());
    for (; it != end; ++it)
    {
        std::cout << "lib path: " << it->first << std::endl;
        PluginManifest::Iterator itMan(it->second->begin());
        PluginManifest::Iterator endMan(it->second->end());
        for (; itMan != endMan; ++itMan)
            std::cout << itMan->name() << std::endl;
    }
    AbstractPlugin* pPluginA = loader.create("PluginA");
    AbstractPlugin* pPluginB = loader.create("PluginB");
    std::cout << pPluginA->name() << std::endl;
    std::cout << pPluginB->name() << std::endl;
    loader.classFor("PluginA").autoDelete(pPluginA);
    delete pPluginB;
    loader.unloadLibrary(libName);
    return 0;
}

具体使用思路:
我们在程序进行模块化开发过程中,可以使用poco的sharelibrary来实现。下面有个简单的例子,使用Qt开发。

这里相当于我们动态库

shareFunction.h
#ifndef SHAREDFUNCTION_H
#define SHAREDFUNCTION_H

#include "sharedFunction_global.h"
#include <string>

extern "C" void SHAREDFUNCTIONSHARED_EXPORT hello(const std::string &name );

class SHAREDFUNCTIONSHARED_EXPORT SharedFunction {
public:
    SharedFunction();
};

#endif // SHAREDFUNCTION_H

shareFunction.cpp
#include "sharedfunction.h"
#include <iostream>
#include <QDebug>
void hello(const std::string &name )
{
    if(name == "function")
    {
        SharedFunction* func = new SharedFunction();
    }
}

SharedFunction::SharedFunction()
{

qDebug ()<<"this is shardFunciton";
}
shareFunction_global
#ifndef SHAREDFUNCTION_GLOBAL_H
#define SHAREDFUNCTION_GLOBAL_H

#include <QtCore/qglobal.h>

#if defined(SHAREDFUNCTION_LIBRARY)
#  define SHAREDFUNCTIONSHARED_EXPORT Q_DECL_EXPORT
#else
#  define SHAREDFUNCTIONSHARED_EXPORT Q_DECL_IMPORT
#endif

#endif // SHAREDFUNCTION_GLOBAL_H

这里为我们的客户端

main.cpp
#include <QtCore/QCoreApplication>
#include "Poco/SharedLibrary.h"
#include <iostream>
#include <QDebug>

#include "Poco/ClassLoader.h"
#include "Poco/Manifest.h"
#include "shareClass/shareclass.h"


/***   导出函数  *****/
using  Poco::SharedLibrary;

typedef void (*helloFunc)(const std::string&name);

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    std::string path("/home/ning/test/shareLibrary/sharedFunction/libsharedFunction");//库存放的目录
    //std::string pathA("/home/ning/test/shareLibrary/sharedFunctionA/libsharedFunctionA");

    path.append (SharedLibrary::suffix());//根据平台返回类库名称
    //pathA.append (SharedLibrary::suffix());
    Poco::SharedLibrary library(path);
    //Poco::SharedLibrary libraryA(pathA);

    //根据函数名称返回函数地址
    helloFunc func = (helloFunc)library.getSymbol ("hello");
    //func = (helloFunc)libraryA.getSymbol ("hello");

    //去实例化我们库
    func("function");


    library.unload ();

    return a.exec();
}

以上只是个简单的应用,在实际应用中,我们要写好类库的管理的代码,将每个实例化的库放到一个容器里面去保存,方便后续的继续调用。这里只是记录下思路,不做具体的代码.

发表评论

电子邮件地址不会被公开。 必填项已用*标注