diff options
| -rw-r--r-- | libadhocutil/Jamfile.jam | 2 | ||||
| -rw-r--r-- | libadhocutil/plugins.cpp | 24 | ||||
| -rw-r--r-- | libadhocutil/plugins.h | 9 | ||||
| -rw-r--r-- | libadhocutil/unittests/testPluginsRuntime.cpp | 50 | 
4 files changed, 80 insertions, 5 deletions
diff --git a/libadhocutil/Jamfile.jam b/libadhocutil/Jamfile.jam index 45bbeec..861509a 100644 --- a/libadhocutil/Jamfile.jam +++ b/libadhocutil/Jamfile.jam @@ -6,6 +6,7 @@ lib Ice : ;  lib IceUtil ;  lib pthread ;  lib curl ; +lib dl ;  alias iceall : : : : <library>Ice <library>IceUtil <library>pthread ; @@ -15,6 +16,7 @@ lib adhocutil :  	<include>.  	<library>iceall  	<library>curl +	<library>dl  	<cflags>-fvisibility=hidden  	<variant>release:<cflags>-flto  	: : diff --git a/libadhocutil/plugins.cpp b/libadhocutil/plugins.cpp index 6caf34f..a1eef70 100644 --- a/libadhocutil/plugins.cpp +++ b/libadhocutil/plugins.cpp @@ -1,5 +1,6 @@  #include "plugins.h"  #include <string.h> +#include <dlfcn.h>  #include <boost/multi_index_container.hpp>  #include <boost/multi_index/ordered_index.hpp>  #include "buffer.h" @@ -73,6 +74,11 @@ namespace AdHoc {  	{  	} +	LoadLibraryException::LoadLibraryException(const std::string & f, const char * msg) : +		std::runtime_error(stringbf("Failed to load library [%s]; %s", f, msg)) +	{ +	} +  	PluginManager::PluginManager() :  		plugins(new PluginStore()),  		resolvers(new TypePluginResolvers()) @@ -111,12 +117,30 @@ namespace AdHoc {  	PluginManager::get(const std::string & n, const std::type_info & t) const  	{  		auto r = plugins->get<2>().equal_range(boost::make_tuple(n, std::cref(t))); +		if (r.first == r.second) { +			auto tr = resolvers->find(t.hash_code()); +			if (tr != resolvers->end()) { +				if (auto lib = tr->second(t, n)) { +					loadLibrary(*lib); +				} +			} +			r = plugins->get<2>().equal_range(boost::make_tuple(n, std::cref(t))); +		}  		if (r.first != r.second) {  			return (*r.first);  		}  		throw NoSuchPluginException(n, t);  	} +	void +	PluginManager::loadLibrary(const std::string & f) +	{ +		void * handle = dlopen(f.c_str(), RTLD_NOW); +		if (!handle) { +			throw LoadLibraryException(f, dlerror()); +		} +	} +  	std::set<PluginPtr>  	PluginManager::getAll() const  	{ diff --git a/libadhocutil/plugins.h b/libadhocutil/plugins.h index 8b8efac..03d59fb 100644 --- a/libadhocutil/plugins.h +++ b/libadhocutil/plugins.h @@ -63,6 +63,13 @@ namespace AdHoc {  			DuplicateResolverException(const std::type_info &);  	}; +	/// Thrown when an attempt to load a library fails. +	class LoadLibraryException : public std::runtime_error { +		public: +			/// Constuctor taking syscall error details. +			LoadLibraryException(const std::string & f, const char * msg); +	}; +  	template <typename T>  	/// Typed plugin and handle to implementation.  	class DLL_PUBLIC PluginOf : public Plugin { @@ -171,6 +178,8 @@ namespace AdHoc {  			static PluginManager * getDefault();  		private: +			static void loadLibrary(const std::string &); +  			typedef boost::multi_index_container<PluginPtr,  							boost::multi_index::indexed_by<  								boost::multi_index::ordered_non_unique<boost::multi_index::member<Plugin, const std::string, &Plugin::name>>, diff --git a/libadhocutil/unittests/testPluginsRuntime.cpp b/libadhocutil/unittests/testPluginsRuntime.cpp index 2b13913..aa1dcf1 100644 --- a/libadhocutil/unittests/testPluginsRuntime.cpp +++ b/libadhocutil/unittests/testPluginsRuntime.cpp @@ -13,7 +13,9 @@ auto variant	= selfExe.parent_path().leaf();  auto toolset	= selfExe.parent_path().parent_path().leaf();  auto lib = rootDir / "bin" / toolset / variant / "libutilTestClasses.so"; -static boost::optional<std::string> resolver(const std::type_info &, const std::string &); +static boost::optional<std::string> nullResolver(const std::type_info &, const std::string &); +static boost::optional<std::string> badResolver(const std::type_info &, const std::string &); +static boost::optional<std::string> goodResolver(const std::type_info &, const std::string &);  BOOST_AUTO_TEST_CASE( ready )  { @@ -36,20 +38,58 @@ BOOST_AUTO_TEST_CASE( loadAndUnloadlib )  }  boost::optional<std::string> -resolver(const std::type_info &, const std::string &) +nullResolver(const std::type_info &, const std::string &)  { -	return std::string(); +	return nullptr; +} + +boost::optional<std::string> +badResolver(const std::type_info &, const std::string &) +{ +	return std::string("dontexist"); +} + +boost::optional<std::string> +goodResolver(const std::type_info & t, const std::string & n) +{ +	BOOST_REQUIRE_EQUAL(typeid(BaseThing), t); +	BOOST_REQUIRE_EQUAL("ImplOfThing", n); +	return lib.string();  }  BOOST_AUTO_TEST_CASE( addAndRemoveResolver )  {  	auto pm = AdHoc::PluginManager::getDefault();  	BOOST_REQUIRE_EQUAL(0, pm->countResolvers()); -	pm->addResolver<BaseThing>(resolver); +	pm->addResolver<BaseThing>(nullResolver);  	BOOST_REQUIRE_EQUAL(1, pm->countResolvers()); -	BOOST_REQUIRE_THROW(pm->addResolver<BaseThing>(resolver), DuplicateResolverException); +	BOOST_REQUIRE_THROW(pm->addResolver<BaseThing>(nullResolver), DuplicateResolverException);  	BOOST_REQUIRE_EQUAL(1, pm->countResolvers());  	pm->removeResolver<BaseThing>();  	BOOST_REQUIRE_EQUAL(0, pm->countResolvers());  } +BOOST_AUTO_TEST_CASE( null ) +{ +	auto pm = AdHoc::PluginManager::getDefault(); +	pm->addResolver<BaseThing>(nullResolver); +	BOOST_REQUIRE_THROW(pm->get<BaseThing>("ImplOfThing"), AdHoc::NoSuchPluginException); +	pm->removeResolver<BaseThing>(); +} + +BOOST_AUTO_TEST_CASE( bad ) +{ +	auto pm = AdHoc::PluginManager::getDefault(); +	pm->addResolver<BaseThing>(badResolver); +	BOOST_REQUIRE_THROW(pm->get<BaseThing>("ImplOfThing"), AdHoc::LoadLibraryException); +	pm->removeResolver<BaseThing>(); +} + +BOOST_AUTO_TEST_CASE( good ) +{ +	auto pm = AdHoc::PluginManager::getDefault(); +	pm->addResolver<BaseThing>(goodResolver); +	BOOST_REQUIRE(pm->get<BaseThing>("ImplOfThing")); +	pm->removeResolver<BaseThing>(); +} +  | 
