2010-09-03 05:41:20 +08:00
|
|
|
/*
|
|
|
|
This file is part of Mitsuba, a physically based rendering system.
|
|
|
|
|
2011-04-14 21:15:59 +08:00
|
|
|
Copyright (c) 2007-2011 by Wenzel Jakob and others.
|
2010-09-03 05:41:20 +08:00
|
|
|
|
|
|
|
Mitsuba is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License Version 3
|
|
|
|
as published by the Free Software Foundation.
|
|
|
|
|
|
|
|
Mitsuba is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2011-04-14 21:15:59 +08:00
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2010-09-03 05:41:20 +08:00
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2010-08-10 01:38:37 +08:00
|
|
|
#include <mitsuba/core/plugin.h>
|
2010-09-10 09:14:48 +08:00
|
|
|
#include <mitsuba/core/statistics.h>
|
|
|
|
#include <mitsuba/core/properties.h>
|
|
|
|
#include <mitsuba/core/lock.h>
|
2010-08-10 01:38:37 +08:00
|
|
|
#include <mitsuba/core/fresolver.h>
|
2010-09-10 09:14:48 +08:00
|
|
|
#include <mitsuba/core/cobject.h>
|
2010-08-10 01:38:37 +08:00
|
|
|
|
|
|
|
#if !defined(WIN32)
|
|
|
|
#include <dlfcn.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
MTS_NAMESPACE_BEGIN
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
// Abstract plugin module implementation
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
2010-09-14 21:23:23 +08:00
|
|
|
Plugin::Plugin(const std::string &shortName, const fs::path &path)
|
2010-08-10 01:38:37 +08:00
|
|
|
: m_shortName(shortName), m_path(path) {
|
|
|
|
#if defined(WIN32)
|
2011-07-27 23:11:57 +08:00
|
|
|
m_handle = LoadLibrary(path.file_string().c_str());
|
2010-08-10 01:38:37 +08:00
|
|
|
if (!m_handle) {
|
2010-09-14 21:23:23 +08:00
|
|
|
SLog(EError, "Error while loading plugin \"%s\": %s",
|
2011-07-27 23:11:57 +08:00
|
|
|
m_path.file_string().c_str(), lastErrorText().c_str());
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
#else
|
2011-07-27 23:11:57 +08:00
|
|
|
m_handle = dlopen(path.file_string().c_str(), RTLD_LAZY | RTLD_LOCAL);
|
2010-08-10 01:38:37 +08:00
|
|
|
if (!m_handle) {
|
2010-09-14 21:23:23 +08:00
|
|
|
SLog(EError, "Error while loading plugin \"%s\": %s",
|
2011-07-27 23:11:57 +08:00
|
|
|
m_path.file_string().c_str(), dlerror());
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
#endif
|
2010-08-17 07:27:08 +08:00
|
|
|
try {
|
|
|
|
m_getDescription = (GetDescriptionFunc) getSymbol("GetDescription");
|
|
|
|
} catch (...) {
|
|
|
|
#if defined(WIN32)
|
|
|
|
FreeLibrary(m_handle);
|
|
|
|
#else
|
|
|
|
dlclose(m_handle);
|
|
|
|
#endif
|
|
|
|
throw;
|
|
|
|
}
|
2010-08-10 01:38:37 +08:00
|
|
|
|
2010-08-17 07:27:08 +08:00
|
|
|
m_createInstance = NULL;
|
|
|
|
m_createUtility = NULL;
|
|
|
|
m_isUtility = false;
|
|
|
|
|
2010-10-16 06:33:32 +08:00
|
|
|
if (hasSymbol("CreateUtility")) {
|
2010-08-17 07:27:08 +08:00
|
|
|
m_createUtility = (CreateUtilityFunc) getSymbol("CreateUtility");
|
|
|
|
m_isUtility = true;
|
2010-10-16 06:33:32 +08:00
|
|
|
} else {
|
|
|
|
m_createInstance = (CreateInstanceFunc) getSymbol("CreateInstance");
|
2010-08-17 07:27:08 +08:00
|
|
|
}
|
2010-08-10 01:38:37 +08:00
|
|
|
Statistics::getInstance()->logPlugin(shortName, getDescription());
|
|
|
|
|
|
|
|
/* New classes must be registered within the class hierarchy */
|
|
|
|
Class::staticInitialization();
|
|
|
|
}
|
|
|
|
|
2010-10-16 06:33:32 +08:00
|
|
|
bool Plugin::hasSymbol(const std::string &sym) const {
|
|
|
|
#if defined(WIN32)
|
|
|
|
void *ptr = GetProcAddress(m_handle, sym.c_str());
|
|
|
|
#else
|
|
|
|
void *ptr = dlsym(m_handle, sym.c_str());
|
|
|
|
#endif
|
|
|
|
return ptr != NULL;
|
|
|
|
}
|
|
|
|
|
2010-08-10 01:38:37 +08:00
|
|
|
void *Plugin::getSymbol(const std::string &sym) {
|
|
|
|
#if defined(WIN32)
|
|
|
|
void *data = GetProcAddress(m_handle, sym.c_str());
|
|
|
|
if (!data) {
|
|
|
|
SLog(EError, "Could not resolve symbol \"%s\" in \"%s\": %s",
|
2011-07-27 23:11:57 +08:00
|
|
|
sym.c_str(), m_path.file_string().c_str(), lastErrorText().c_str());
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
void *data = dlsym(m_handle, sym.c_str());
|
|
|
|
if (!data) {
|
|
|
|
SLog(EError, "Could not resolve symbol \"%s\" in \"%s\": %s",
|
2011-07-27 23:11:57 +08:00
|
|
|
sym.c_str(), m_path.file_string().c_str(), dlerror());
|
2010-08-10 01:38:37 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
ConfigurableObject *Plugin::createInstance(const Properties &props) const {
|
|
|
|
return (ConfigurableObject *) m_createInstance(props);
|
|
|
|
}
|
|
|
|
|
2010-09-02 23:57:04 +08:00
|
|
|
Utility *Plugin::createUtility() const {
|
|
|
|
return (Utility *) m_createUtility();
|
2010-08-17 07:27:08 +08:00
|
|
|
}
|
|
|
|
|
2010-08-10 01:38:37 +08:00
|
|
|
std::string Plugin::getDescription() const {
|
|
|
|
return m_getDescription();
|
|
|
|
}
|
|
|
|
|
|
|
|
Plugin::~Plugin() {
|
|
|
|
#if defined(WIN32)
|
|
|
|
FreeLibrary(m_handle);
|
|
|
|
#else
|
|
|
|
dlclose(m_handle);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
// Plugin manager
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
2010-08-24 17:19:13 +08:00
|
|
|
ref<PluginManager> PluginManager::m_instance = NULL;
|
2010-08-10 01:38:37 +08:00
|
|
|
|
|
|
|
PluginManager::PluginManager() {
|
|
|
|
m_mutex = new Mutex();
|
|
|
|
}
|
|
|
|
|
|
|
|
PluginManager::~PluginManager() {
|
|
|
|
/* Release the memory used by plugin modules */
|
|
|
|
for (std::map<std::string, Plugin *>::iterator it = m_plugins.begin();
|
|
|
|
it != m_plugins.end(); ++it) {
|
|
|
|
delete (*it).second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ConfigurableObject *PluginManager::createObject(const Class *classType,
|
|
|
|
const Properties &props) {
|
|
|
|
ConfigurableObject *object;
|
|
|
|
|
|
|
|
m_mutex->lock();
|
|
|
|
try {
|
|
|
|
ensurePluginLoaded(props.getPluginName());
|
|
|
|
object = m_plugins[props.getPluginName()]->createInstance(props);
|
|
|
|
} catch (std::runtime_error &e) {
|
|
|
|
m_mutex->unlock();
|
|
|
|
throw e;
|
|
|
|
} catch (std::exception &e) {
|
|
|
|
m_mutex->unlock();
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
m_mutex->unlock();
|
|
|
|
if (!object->getClass()->derivesFrom(classType))
|
|
|
|
Log(EError, "Type mismatch when loading plugin \"%s\": Expected "
|
|
|
|
"an instance of \"%s\"", props.getPluginName().c_str(), classType->getName().c_str());
|
|
|
|
if (object->getClass()->isAbstract())
|
|
|
|
Log(EError, "Error when loading plugin \"%s\": Identifies itself as an abstract class",
|
|
|
|
props.getPluginName().c_str());
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::string> PluginManager::getLoadedPlugins() const {
|
|
|
|
std::vector<std::string> list;
|
|
|
|
m_mutex->lock();
|
|
|
|
for (std::map<std::string, Plugin *>::const_iterator it = m_plugins.begin();
|
|
|
|
it != m_plugins.end(); ++it) {
|
|
|
|
list.push_back((*it).first);
|
|
|
|
}
|
|
|
|
m_mutex->unlock();
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PluginManager::ensurePluginLoaded(const std::string &name) {
|
|
|
|
/* Plugin already loaded? */
|
|
|
|
if (m_plugins[name] != NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Build the full plugin file name */
|
|
|
|
#if defined(WIN32)
|
|
|
|
std::string shortName = std::string("plugins/") + name + std::string(".dll");
|
|
|
|
#elif defined(__OSX__)
|
|
|
|
std::string shortName = std::string("plugins/") + name + std::string(".dylib");
|
|
|
|
#else
|
|
|
|
std::string shortName = std::string("plugins/") + name + std::string(".so");
|
|
|
|
#endif
|
2010-09-10 09:14:48 +08:00
|
|
|
const FileResolver *resolver = Thread::getThread()->getFileResolver();
|
|
|
|
fs::path path = resolver->resolve(shortName);
|
2010-08-10 01:38:37 +08:00
|
|
|
|
2010-09-10 09:14:48 +08:00
|
|
|
if (fs::exists(path)) {
|
2010-08-10 01:38:37 +08:00
|
|
|
Log(EInfo, "Loading plugin \"%s\" ..", shortName.c_str());
|
2011-07-27 23:11:57 +08:00
|
|
|
m_plugins[name] = new Plugin(shortName, path.file_string());
|
2010-08-10 01:38:37 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Plugin not found! */
|
|
|
|
Log(EError, "Plugin \"%s\" not found!", name.c_str());
|
|
|
|
}
|
|
|
|
|
2010-08-24 17:19:13 +08:00
|
|
|
void PluginManager::staticInitialization() {
|
|
|
|
m_instance = new PluginManager();
|
|
|
|
}
|
|
|
|
|
|
|
|
void PluginManager::staticShutdown() {
|
|
|
|
m_instance = NULL;
|
|
|
|
}
|
|
|
|
|
2011-07-17 06:28:28 +08:00
|
|
|
Version::Version(const std::string &versionString) {
|
|
|
|
std::vector<std::string> tokens = tokenize(trim(versionString), ".");
|
|
|
|
if (tokens.size() != 3)
|
|
|
|
SLog(EError, "Unable to parse version string \"%s\"!", versionString.c_str());
|
|
|
|
char *end_ptr = NULL;
|
|
|
|
m_major = strtol(tokens[0].c_str(), &end_ptr, 10);
|
|
|
|
if (*end_ptr != '\0')
|
|
|
|
SLog(EError, "Unable to parse the major program version \"%i\"!", tokens[0].c_str());
|
|
|
|
m_minor = strtol(tokens[1].c_str(), &end_ptr, 10);
|
|
|
|
if (*end_ptr != '\0')
|
|
|
|
SLog(EError, "Unable to parse the minor program version \"%i\"!", tokens[1].c_str());
|
|
|
|
m_release = strtol(tokens[2].c_str(), &end_ptr, 10);
|
|
|
|
if (*end_ptr != '\0')
|
|
|
|
SLog(EError, "Unable to parse the release program version \"%i\"!", tokens[2].c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Version::toString() const {
|
|
|
|
return formatString("%i.%i.%i", m_major, m_minor, m_release);
|
|
|
|
}
|
|
|
|
|
2010-08-10 01:38:37 +08:00
|
|
|
MTS_IMPLEMENT_CLASS(PluginManager, false, Object)
|
|
|
|
MTS_NAMESPACE_END
|