psana/src/DynLoader.cpp

Go to the documentation of this file.
00001 //--------------------------------------------------------------------------
00002 // File and Version Information:
00003 //      $Id: DynLoader.cpp 6198 2013-05-01 17:02:51Z salnikov@SLAC.STANFORD.EDU $
00004 //
00005 // Description:
00006 //      Class DynLoader...
00007 //
00008 // Author List:
00009 //      Andrei Salnikov
00010 //
00011 //------------------------------------------------------------------------
00012 
00013 //-----------------------
00014 // This Class's Header --
00015 //-----------------------
00016 #include "psana/DynLoader.h"
00017 
00018 //-----------------
00019 // C/C++ Headers --
00020 //-----------------
00021 #include <dlfcn.h>
00022 
00023 //-------------------------------
00024 // Collaborating Class Headers --
00025 //-------------------------------
00026 #include "psana/Exceptions.h"
00027 #include "MsgLogger/MsgLogger.h"
00028 
00029 //-----------------------------------------------------------------------
00030 // Local Macros, Typedefs, Structures, Unions and Forward Declarations --
00031 //-----------------------------------------------------------------------
00032 
00033 namespace {
00034   
00035   const char logger[] = "DynLoader";
00036   
00037   typedef psana::Module* (*mod_factory)(const std::string& name);
00038   typedef psana::InputModule* (*input_mod_factory)(const std::string& name);
00039 }
00040 
00041 //              ----------------------------------------
00042 //              -- Public Function Member Definitions --
00043 //              ----------------------------------------
00044 
00045 namespace psana {
00046 
00047 /**
00048  *  Load one user module. The name of the module has a format 
00049  *  [Package.]Class[:name]
00050  */
00051 boost::shared_ptr<Module>
00052 DynLoader::loadModule(const std::string& name, const std::string& language) const
00053 {
00054   if (language == "c++") {
00055 
00056     // make class name, use psana for package name if not given
00057     std::string fullName = name;
00058     std::string className = name;
00059     std::string::size_type p1 = className.find(':');
00060     if (p1 != std::string::npos) {
00061       className.erase(p1);
00062     }
00063     if (className.find('.') == std::string::npos) {
00064       className = "psana." + className;
00065       fullName = "psana." + fullName;
00066     }
00067 
00068     // Load function
00069     void* sym = loadFactoryFunction(className, "_psana_module_");
00070     ::mod_factory factory = (::mod_factory)sym;
00071     // call factory function
00072     return boost::shared_ptr<Module>(factory(fullName));
00073 
00074   } else {
00075 
00076     // explicitly requested non-C++ module, load libpsana_lanaguage.so
00077     // library, find "moduleFactory()" function in it and call it
00078     // giving full name of the module.
00079 
00080     void* sym = loadFactoryFunction("psana_" + language + ".moduleFactory", "");
00081     ::mod_factory factory = (::mod_factory) sym;
00082     return boost::shared_ptr<Module>(factory(name));
00083 
00084   }
00085 }
00086 
00087 /**
00088  *  Load one user module. The name of the module has a format 
00089  *  [py:][Package.]Class[:name]
00090  */
00091 boost::shared_ptr<Module>
00092 DynLoader::loadModule(const std::string& name) const
00093 {
00094   // parse given name, determine language name
00095   // from it and a module name
00096   std::string language;
00097   std::string module = name;
00098   size_t n = name.find(":");
00099   if (n != std::string::npos) {
00100     language = name.substr(0, n);
00101     boost::algorithm::to_lower(language);
00102     if (language == "c++") {
00103       module = name.substr(n + 1);
00104     } else if (language == "python") {
00105       module = name.substr(n + 1);
00106     } else if (language == "py") {
00107       language = "python";
00108       module = name.substr(n + 1);
00109     } else {
00110       language.clear();
00111     }
00112   }
00113 
00114   if (not language.empty()) {
00115     // if language is specified then use it
00116     return loadModule(module, language);
00117   } else {
00118     // if not specified then try to load C++ module and then python
00119     try {
00120       return loadModule(module, "c++");
00121     } catch (psana::Exception ex) {
00122       std::string cpperr = ex.what();
00123       try {
00124         return loadModule(module, "python");
00125       } catch (const std::exception& pex) {
00126         std::string pyerr = pex.what();
00127         throw Exception(ERR_LOC, "Failed to load C++ or Python module with name " + module +
00128             "\n    C++ error: " + cpperr +
00129             "\n    Python error: " + pyerr);
00130       }
00131     }
00132   }
00133 }
00134 
00135 /**
00136  *  Load one input module. The name of the module has a format 
00137  *  Package.Class[:name]
00138  */
00139 boost::shared_ptr<InputModule>
00140 DynLoader::loadInputModule(const std::string& name) const
00141 {
00142   // make class name, use psana for package name if not given
00143   std::string fullName = name;
00144   std::string className = name;
00145   std::string::size_type p1 = className.find(':');
00146   if (p1 != std::string::npos) {
00147     className.erase(p1);
00148   }
00149   if (className.find('.') == std::string::npos) {
00150     className = "psana." + className;
00151     fullName = "psana." + fullName;
00152   }
00153   
00154   // Load function
00155   void* sym = loadFactoryFunction(className, "_psana_input_module_");
00156   ::input_mod_factory factory = (::input_mod_factory)sym;
00157   
00158   // call factory function
00159   return boost::shared_ptr<InputModule>(factory(fullName));
00160 }
00161 
00162 void* 
00163 DynLoader::loadFactoryFunction(const std::string& name, const std::string& factory) const
00164 {
00165   // get package name and module class name
00166   std::string::size_type p1 = name.find('.');
00167   if (p1 == std::string::npos) throw ExceptionModuleName(ERR_LOC, name);
00168   std::string package(name, 0, p1);
00169   std::string className(name, p1+1);
00170 
00171   // load the library
00172   void* ldh = loadPackageLib(package);
00173   
00174   // find the symbol
00175   std::string symname = factory + className;
00176   void* sym = dlsym(ldh, symname.c_str());
00177   if ( not sym ) {
00178     throw ExceptionDlerror(ERR_LOC, "failed to locate symbol "+symname);
00179   }
00180   
00181   return sym;
00182 }
00183 
00184 /**
00185  *  Load the library for a package 
00186  */
00187 void* 
00188 DynLoader::loadPackageLib(const std::string& packageName) const
00189 {
00190   // build library name
00191   std::string lib = "lib" + packageName + ".so";
00192   
00193   // load the library
00194   MsgLog(logger, trace, "loading library " << lib);
00195   void* ldh = dlopen(lib.c_str(), RTLD_NOW | RTLD_GLOBAL);
00196   if ( not ldh ) {
00197     throw ExceptionDlerror(ERR_LOC, "failed to load dynamic library "+lib);
00198   }
00199   
00200   return ldh;
00201 }
00202 
00203 } // namespace psana

Generated on 19 Dec 2016 for PSANAclasses by  doxygen 1.4.7