Poco::ClassLoader

Poco::ClassLoader を紹介します。

Poco::ClassLoader クラスは、Shared Library から C++ のクラスを実行時に動的にロードします。ロードされるクラスは、その基底クラスとしてインスタンス化しなければいけません。Shared Library からロード可能なクラスにするためには、Shared Library は自身が含む全てのクラスに対して manifest を提供しなければいけません。ヘッダファイル “Foundation/ClassLibrary.h” のマクロを使えば、簡単に manifest を作ることができます。

POCO の 1.3 から、Shared Library は複数の manifest を export できるようになりました。デフォルトの無名 manifest に加え、異なる基底クラスを持つ複数の名前付き manifest を export することができます。

1つの Poco::ClassLoader インスタンスは、1つの manifest しかロードできないという制限があることに注意してください。

Plugin.h

#ifndef PLUGIN_H
#define PLUGIN_H
 
class Plugin
{
public:
	Plugin()		{}
	virtual ~Plugin()	{}
	virtual std::string name() const = 0;
};
 
#endif // PLUGIN_H

Plugin.cpp

・これを libPlugin という名前の SharedLibrary としてビルド。

#include <Poco/ClassLibrary.h>
 
#include <string>
#include <iostream>
 
#include "Plugin.h"
 
class PluginA : public Plugin
{
public:
	PluginA()	{}
	~PluginA()	{}
	std::string name() const
	{
		return std::string("PluginA");
	}
};
 
class PluginB : public Plugin
{
public:
	PluginB()	{}
	~PluginB()	{}
	std::string name() const
	{
		return std::string("PluginB");
	}
};
 
class PluginC : public Plugin
{
public:
	PluginC()	{}
	~PluginC()	{}
	std::string name() const
	{
		return std::string("PluginC");
	}
};
 
POCO_BEGIN_MANIFEST(Plugin)
	POCO_EXPORT_CLASS(PluginA)
	POCO_EXPORT_CLASS(PluginB)
	POCO_EXPORT_SINGLETON(PluginC)
POCO_END_MANIFEST
 
void pocoInitializeLibrary()
{
	std::cout << "Plugin initializing" << std::endl;
}
 
void pocoUninitializeLibrary()
{
	std::cout << "Plugin uninitialzing" << std::endl;
}

ClassLoaderTest.cpp

・libPlugin という名前の SharedLibrary をロード。
・POCO_EXPORT_CLASS と宣言した PluginA, PluginB は create() でインスタンス化。
・POCO_EXPORT_SINGLETON と宣言した PluginC は instance() でインスタンス化。
・各 Plugin の name() を呼んで結果を表示。

#include <Poco/Format.h>
#include <Poco/ClassLoader.h>
 
#include <string>
 
#include "ScopedLogMessage.h"
#include "PrepareConsoleLogger.h"
#include "../Plugin/Plugin.h"
 
const std::string kSharedLibraryName("libPlugin");
 
const std::string kPluginNameA("PluginA");	// Note that PluginA is declared as POCO_EXPORT_CLASS in manifest
const std::string kPluginNameB("PluginB");	// Note that PluginB is declared as POCO_EXPORT_CLASS in manifest
const std::string kPluginNameC("PluginC");	// Note that PluginC is declared as POCO_EXPORT_SINGLETON in manifest
const std::string kPluginNames[] = { kPluginNameA, kPluginNameB, kPluginNameC };
 
const std::size_t kNumPlugin = sizeof(kPluginNames)/sizeof(kPluginNames[0]);
 
void TestClassLoader(	ScopedLogMessage& msg
		,	Poco::ClassLoader<Plugin>& cl
		,	const std::string& pluginName)
{
	if(cl.canCreate(pluginName))
	{
		Plugin* pPlugin = cl.classFor(pluginName).create();
		msg.Message(Poco::format(" %s created.", pPlugin->name()));
		delete pPlugin;
	}
 
	try
	{
		Plugin& plugin = cl.instance(pluginName);
		msg.Message(Poco::format(" %s instanciated.", plugin.name()));
	}
	catch(Poco::InvalidAccessException& exc)
	{
		msg.Message("  Poco::ClassLoader::instance() failed for non-singleton class.");
		msg.Message(Poco::format("   (%s \"%s\")", std::string(exc.name()), pluginName));
	}
}
 
int main(int /*argc*/, char** /*argv*/)
{
	PrepareConsoleLogger logger(Poco::Logger::ROOT, Poco::Message::PRIO_INFORMATION);
 
	ScopedLogMessage msg("ClassLoaderTest ", "start", "end");
 
	std::string path(kSharedLibraryName);
	path.append(Poco::SharedLibrary::suffix());
	Poco::ClassLoader<Plugin> cl;
	try
	{
		cl.loadLibrary(path);
		if(cl.isLibraryLoaded(path))
		{
			msg.Message(Poco::format(" Size for manifest for \"%s\": %i", path, cl.manifestFor(path).size()));
 
			for(std::size_t i=0; i<kNumPlugin; ++i)
			{
				TestClassLoader(msg, cl, kPluginNames[i]);
			}
 
			cl.unloadLibrary(path);
		}
	}
	catch(Poco::LibraryLoadException& exc)
	{
		msg.Message(Poco::format(" %s \"%s\"", std::string(exc.name()), path));
	}
 
	return 0;
}

Results of execution

・Linux/Mac 等では、libPlugin をインストールするために make install してから ClassLoaderTest
 を実行する。

– On Linux

[0] ClassLoaderTest start
Plugin initializing
[0]  Size for manifest for "libPlugin.so": 3
[0]  PluginA created.
[0]   Poco::ClassLoader::instance() failed for non-singleton class.
[0]    (Invalid access "PluginA")
[0]  PluginB created.
[0]   Poco::ClassLoader::instance() failed for non-singleton class.
[0]    (Invalid access "PluginB")
[0]  PluginC instanciated.
Plugin uninitialzing
[0] ClassLoaderTest end

– On Macintosh OSX 10.6.4

[0] ClassLoaderTest start
Plugin initializing
[0]  Size for manifest for "libPlugin.dylib": 3
[0]  PluginA created.
[0]   Poco::ClassLoader::instance() failed for non-singleton class.
[0]    (Invalid access "PluginA")
[0]  PluginB created.
[0]   Poco::ClassLoader::instance() failed for non-singleton class.
[0]    (Invalid access "PluginB")
[0]  PluginC instanciated.
Plugin uninitialzing
[0] ClassLoaderTest end

– On Windows XP sp3

[0] ClassLoaderTest start
Plugin initializing
[0]  Size for manifest for "libPlugin.dll": 3
[0]  PluginA created.
[0]   Poco::ClassLoader::instance() failed for non-singleton class.
[0]    (Invalid access "PluginA")
[0]  PluginB created.
[0]   Poco::ClassLoader::instance() failed for non-singleton class.
[0]    (Invalid access "PluginB")
[0]  PluginC instanciated.
Plugin uninitialzing
[0] ClassLoaderTest end

Downloads

ここをクリックすると、makefile や VC++ プロジェクトなど一式がダウンロードできます。
(2013.05.31 updated)
・2010年7月27日からのダウンロード数:811

Subversion

・フリーの Subversion ホスティングサービス Assemblaで、ソースコードを管理しています。

Reference

http://pocoproject.org にある Shared Libraries のプレセンテーション。(PDF)

Powered by POCO Copyright © 2010 Round Square Inc. All rights reserved.


Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>