Simbody
|
This is the base class for representing a runtime-linked dynamic library, also known as a "plugin", in a platform-independent manner. More...
#include <Plugin.h>
Public Member Functions | |
Plugin (const std::string &defaultPathname="") | |
~Plugin () | |
bool | load (const std::string &name="") |
Attempt to load a plugin of the given name if any, otherwise the default name (if any). | |
void | unload () |
If a plugin is loaded, unload it now otherwise do nothing. | |
bool | isLoaded () const |
Is there currently a DLL associated with this Plugin object? If so you can call getLoadedPathname() to find out which one. | |
const std::string & | getLoadedPathname () const |
std::string | getLastErrorMessage () const |
If anything goes wrong the last error message is stored so you can retrieve it with this method. | |
void | setSearchPath (const Array_< std::string > &pathIn) |
Provide a list of directories in the order you want them searched to find a plugin that was provided as a relative path name. | |
const Array_< std::string > & | getSearchPath () const |
void | addSearchDirectory (const std::string &directory) |
Add a directory to the end of the search path for this kind of plugin. | |
void | prependSearchDirectory (const std::string &directory) |
Put a directory on the front of the search path for this kind of plugin. | |
Static Public Member Functions | |
static void * | loadPluginByFileName (const std::string &name, std::string &errMsg) |
If this fails the return value will be null and the system's human-readable error message is in errMsg. | |
static void * | loadDebugOrReleasePlugin (const std::string &base, const std::string &extension, std::string &loadedFileName, std::string &errMsg) |
If we're in Debug mode then this method attempts first to load the Debug version of the indicated library which it constructs as base+"_d"+extension. | |
static void * | getSymbolAddress (void *handle, const std::string &name, std::string &errMsg) |
If this fails the return value will be null and the system's human-readable error message is in errMsg. | |
static void | unloadPlugin (void *handle) |
Given a handle returned by loadPluginByFileName(), unload the plugin. | |
static bool | deconstructLibraryName (const std::string &name, bool &isAbsolutePath, std::string &directory, std::string &libPrefix, std::string &baseName, std::string &debugSuffix, std::string &extension) |
Dismantle a supplied library's file or pathname into its component parts. | |
static std::string | getDynamicLibPrefix () |
This is the platform dependent string which gets prepended to a dynamic library baseName to form the fileName -- "lib" on Unix-based systems and "" (empty string) for Windows. | |
static std::string | getDynamicLibExtension () |
This is the platform dependent extension (including the ".") used by default to identify dynamically linked libraries -- ".so" on Linux, ".dylib" on Apple, and ".dll" on Windows. | |
static std::string | getDynamicLibDebugSuffix () |
Obtain the appropriate debug suffix to use. | |
Protected Attributes | |
std::string | m_defaultName |
Array_< std::string > | m_searchPath |
std::string | m_loadedPathname |
void * | m_handle |
std::string | m_lastMessage |
This is the base class for representing a runtime-linked dynamic library, also known as a "plugin", in a platform-independent manner.
For any particular kind of plugin, derive a concrete class from this one and use the macros to describe the functions or data you expect to find there. Then each plugin library you load of that type is an object of the concrete class you defined. The derived class constructor sets the search policy for plugin libraries of that type. For example:
class MyPlugin : public Plugin { public: explicit MyPlugin() : Plugin() { addSearchDirectory(Pathname::getInstallDir("SimTK_INSTALL_DIR", "SimTK") + "/lib/plugins/"); }
SimTK_PLUGIN_DEFINE_FUNCTION1(int,exportedFunctionWithOneArg,const std::string&); SimTK_PLUGIN_DEFINE_FUNCTION(SomeObjectType*,anExportedFunctionNoArgs); SimTK_PLUGIN_DEFINE_FUNCTION(void, someFunction); SimTK_PLUGIN_DEFINE_SYMBOL(SymbolType, nameOfExportedSymbol); };
Then this class is used as follows:
MyPlugin lib1; if (!lib1.load("libraryName")) { std::cerr << lib1.getLastErrorMessage() << std::endl; // exit, retry or whatever } // At this point you can call the functions and access // the symbols, e.g. int i = lib1.exportedFunctionWithOneArg("hi");
The currently available macros are:
These define methods in the derived class which can obtain the symbol address from the plugin library as needed. The methods will have the same signature as the library's exported function. In the case of the symbol, a no-argument method named the same as the symbol will be created. For example,
SimTK_PLUGIN_DEFINE_SYMBOL(int, myCounter);
says the library contains an exported external symbol of type int named "myCounter". If the Plugin object is "plugin" then you can access this symbol (read only) as
const int& counter = plugin.myCounter();
The macros also define another method of the same name as the symbol or function, but prepended with "has_". This returns true if the named object is exported by the library, otherwise false. If you try to access a method or symbol without checking first, an exception will be thrown if the library doesn't export the symbol.
SimTK::Plugin::Plugin | ( | const std::string & | defaultPathname = "" | ) | [explicit] |
SimTK::Plugin::~Plugin | ( | ) |
bool SimTK::Plugin::load | ( | const std::string & | name = "" | ) |
Attempt to load a plugin of the given name if any, otherwise the default name (if any).
If the name is relative it will be subject to the search rule associated with this Plugin object. In any case the filename will be deconstructed to find the library baseName to which we will add the "lib" prefix if necessary, the "_d" suffix if appropriate, and the platform-specific suffix.
load() returns true if it succeeds, otherwise you can call getLastErrorMessage() to find out what's wrong. If a library is already loaded, this returns false without checking to see whether you are trying to reload the same library. Call isLoaded() to check whether a plugin has already been loaded, getLoadedPathname() to get a canonicalized absolute pathname for the loaded library.
void SimTK::Plugin::unload | ( | ) |
If a plugin is loaded, unload it now otherwise do nothing.
Note that whether the corresponding DLL is actually unloaded from the address space is up to the operating system, however, this Plugin object will be disassociated from it regardless.
bool SimTK::Plugin::isLoaded | ( | ) | const [inline] |
Is there currently a DLL associated with this Plugin object? If so you can call getLoadedPathname() to find out which one.
const std::string& SimTK::Plugin::getLoadedPathname | ( | ) | const [inline] |
std::string SimTK::Plugin::getLastErrorMessage | ( | ) | const [inline] |
If anything goes wrong the last error message is stored so you can retrieve it with this method.
void SimTK::Plugin::setSearchPath | ( | const Array_< std::string > & | pathIn | ) | [inline] |
Provide a list of directories in the order you want them searched to find a plugin that was provided as a relative path name.
This is ignored if an absolute path name is given. Each of the directory names will be immediately expanded to an absolute path name if it isn't already.
const Array_<std::string>& SimTK::Plugin::getSearchPath | ( | ) | const [inline] |
void SimTK::Plugin::addSearchDirectory | ( | const std::string & | directory | ) | [inline] |
Add a directory to the end of the search path for this kind of plugin.
This will be expanded immediately to an absolute path name if it isn't already. If the directory is blank it is ignored.
void SimTK::Plugin::prependSearchDirectory | ( | const std::string & | directory | ) | [inline] |
Put a directory on the front of the search path for this kind of plugin.
This will be expanded immediately to an absolute path name if it isn't already. If the directory name is blank it is ignored.
static void* SimTK::Plugin::loadPluginByFileName | ( | const std::string & | name, |
std::string & | errMsg | ||
) | [static] |
If this fails the return value will be null and the system's human-readable error message is in errMsg.
static void* SimTK::Plugin::loadDebugOrReleasePlugin | ( | const std::string & | base, |
const std::string & | extension, | ||
std::string & | loadedFileName, | ||
std::string & | errMsg | ||
) | [static] |
If we're in Debug mode then this method attempts first to load the Debug version of the indicated library which it constructs as base+"_d"+extension.
If that fails (or if we're not in Debug mode) it will try to load the Release version (base+extension) instead.
static void* SimTK::Plugin::getSymbolAddress | ( | void * | handle, |
const std::string & | name, | ||
std::string & | errMsg | ||
) | [static] |
If this fails the return value will be null and the system's human-readable error message is in errMsg.
static void SimTK::Plugin::unloadPlugin | ( | void * | handle | ) | [static] |
Given a handle returned by loadPluginByFileName(), unload the plugin.
Nothing happens until the last reference is unloaded.
static bool SimTK::Plugin::deconstructLibraryName | ( | const std::string & | name, |
bool & | isAbsolutePath, | ||
std::string & | directory, | ||
std::string & | libPrefix, | ||
std::string & | baseName, | ||
std::string & | debugSuffix, | ||
std::string & | extension | ||
) | [static] |
Dismantle a supplied library's file or pathname into its component parts.
This can take pathnames like
/usr/local/libMyDll_d.so e:\Program Files\Something\myLibrary_d.dll
and chop them into
directory libPrefix baseName debug extension ------------------------------- --------- ----------- ----- --------- /usr/local/ lib MyDll _d .so e:\Program Files\Something\ (none) myLibrary _d .dll
as well as tell you whether the given pathname is absolute or relative (and thus subject to search rules). At the beginning of the pathname (or right after the drive specification on Windows) we recognize three special symbols:
Anywhere in the pathname, the name ".." means "go up one level from the prior directory". ".." at the start is interpreted as "./..". A '.' appearing anywhere in the path name except the begining is ignored. An '@' appearing anywhere in the pathname other than the beginning is treated as an ordinary file character.
The pathname components are returned as separate strings with separators included such that concatenating all the strings reproduces the pathname in a canonicalized form. The "drive" letter prefix is recognized only when running on Windows; otherwise a prefix like "C:" is treated as ordinary file name characters. Note that we include the drive letter as part of the absolute directory. White space is removed, and path separator characters in the directory are changed to the appropriate slash for the currently running platform (i.e. backslash for Windows and forward slash everywhere else). The return value is false if the input path name is ill-formed; in that case it still tries to parse as much as it can.
static std::string SimTK::Plugin::getDynamicLibPrefix | ( | ) | [static] |
This is the platform dependent string which gets prepended to a dynamic library baseName to form the fileName -- "lib" on Unix-based systems and "" (empty string) for Windows.
static std::string SimTK::Plugin::getDynamicLibExtension | ( | ) | [static] |
This is the platform dependent extension (including the ".") used by default to identify dynamically linked libraries -- ".so" on Linux, ".dylib" on Apple, and ".dll" on Windows.
static std::string SimTK::Plugin::getDynamicLibDebugSuffix | ( | ) | [static] |
Obtain the appropriate debug suffix to use.
This is not platform dependent but rather depends on whether this compilation unit was built in Debug or Release modes. If Debug, then the string "_d" is returned, otherwise the empty string.
std::string SimTK::Plugin::m_defaultName [protected] |
Array_<std::string> SimTK::Plugin::m_searchPath [protected] |
std::string SimTK::Plugin::m_loadedPathname [protected] |
void* SimTK::Plugin::m_handle [protected] |
std::string SimTK::Plugin::m_lastMessage [mutable, protected] |