00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "psana/DynLoader.h"
00017
00018
00019
00020
00021 #include <dlfcn.h>
00022
00023
00024
00025
00026 #include "psana/Exceptions.h"
00027 #include "MsgLogger/MsgLogger.h"
00028
00029
00030
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
00043
00044
00045 namespace psana {
00046
00047
00048
00049
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
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
00069 void* sym = loadFactoryFunction(className, "_psana_module_");
00070 ::mod_factory factory = (::mod_factory)sym;
00071
00072 return boost::shared_ptr<Module>(factory(fullName));
00073
00074 } else {
00075
00076
00077
00078
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
00089
00090
00091 boost::shared_ptr<Module>
00092 DynLoader::loadModule(const std::string& name) const
00093 {
00094
00095
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
00116 return loadModule(module, language);
00117 } else {
00118
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
00137
00138
00139 boost::shared_ptr<InputModule>
00140 DynLoader::loadInputModule(const std::string& name) const
00141 {
00142
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
00155 void* sym = loadFactoryFunction(className, "_psana_input_module_");
00156 ::input_mod_factory factory = (::input_mod_factory)sym;
00157
00158
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
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
00172 void* ldh = loadPackageLib(package);
00173
00174
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
00186
00187 void*
00188 DynLoader::loadPackageLib(const std::string& packageName) const
00189 {
00190
00191 std::string lib = "lib" + packageName + ".so";
00192
00193
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 }