agile is hosted by Hepforge, IPPP Durham

Loader.cc

Go to the documentation of this file.
00001 #include "AGILe/AGILe.hh"
00002 #include "AGILe/Generator.hh"
00003 #include "AGILe/Tools/AGILePaths.hh"
00004 #include "AGILe/Tools/osdir.hh"
00005 #include <dlfcn.h>
00006 #include <unistd.h>
00007 
00008 namespace AGILe {
00009 
00010 
00011   namespace Loader {
00012 
00013 
00014     Log& getLog() {
00015       return AGILe::Log::getLog("AGILe.Loader");
00016     }
00017 
00018 
00019     // Struct for holding library names and versions
00020     struct GenLibInfo {
00021       GenLibInfo(string libname, string pkgname="", string pkgversion="") {
00022         this->libname = libname;
00023         this->pkgname = pkgname;
00024         this->pkgversion = pkgversion;
00025       }
00026       string libname, pkgname, pkgversion;
00027     };
00028 
00029 
00030     // Static library handles
00031     vector<void*> handles;
00032     void* agilehandle = 0;
00033 
00034     // Libraries required for each known generator.
00035     typedef map<string, vector<GenLibInfo> > GenLibs;
00036 
00037     // Generator version is kept globally for use by the
00038     // Generator::setVersion(...) function.
00039     string version;
00040 
00041 
00042     // Initialise the dynamic loader
00043     void initialize() {
00044       // Nothing to do with raw dlopen
00045     }
00046 
00047 
00048 
00049     // Make the proper system library name
00050     string sysLibName(string libname) {
00051       // Put lib suffix on the end if needed
00052       if (libname.find(SYSDSO) == string::npos) libname += SYSDSO;
00053       return libname;
00054     }
00055 
00056 
00057 
00058     vector<string> getPlatforms(const GenLibInfo& info) {
00059       vector<string> platforms;
00060       if (!info.pkgname.empty()) {
00061         // If we're not trying to load an AGILe interface...
00062         platforms += getLCGPlatformTag();
00063       }
00064       // Also try with no platform tag
00065       platforms += "";
00066 
00067       return platforms;
00068     }
00069 
00070 
00071 
00072     vector<string> getLibSearchDirs(const GenLibInfo& info) {
00073       vector<string> dirs;
00074       if (info.pkgname.empty()) {
00075         // If we're trying to load an AGILe interface...
00076 
00078 
00079         // Use the AGILe library install path
00080         dirs.push_back(getLibPath());
00081 
00082         // Use the current dir, too.
00083         dirs.push_back(".");
00084 
00085         // and some default system locations
00086         dirs += "/usr/lib", "/usr/lib64", "/usr/lib32";
00087         dirs += "/usr/local/lib", "/usr/local/lib64", "/usr/local/lib32";
00088 
00089         // And then the user's (non-system) library path
00091         const char* envld = getenv("LD_LIBRARY_PATH");
00092         if (envld) dirs += split(envld);
00093 
00094       } else {
00095         // If we're loading a real generator library...
00096         dirs += getGenPaths();
00097       }
00098 
00099       return dirs;
00100     }
00101 
00102 
00103 
00104     string findGenLib(const GenLibInfo& info,
00105                       const vector<string> searchdirs,
00106                       const vector<string> platforms)
00107     {
00108       // Get platform-specific filename
00109       string libname = sysLibName(info.libname);
00110 
00111       // Try to find lib file here
00112       foreach (const string& d, searchdirs) {
00113         foreach (const string& p, platforms) {
00114           vector<string> versionsuffixes;
00115           versionsuffixes += ".3", ".2", "";
00116           foreach (string& vsuffix, versionsuffixes) {
00117             string libpath = d + "/" + info.pkgname;
00118             if (!info.pkgversion.empty()) {
00119               libpath += "/" + info.pkgversion + vsuffix;
00120             }
00121             if (!p.empty()) {
00122               libpath += "/" + p;
00123             }
00124             if (!info.pkgname.empty()) {
00125               libpath += "/lib";
00126             }
00127             libpath += "/" + libname;
00128             // Remove duplicate slashes from path
00129             while (libpath.find("//") != string::npos) {
00130               libpath.replace(libpath.find("//"), 2, "/");
00131             }
00132             // Return path if present
00133             getLog() << Log::TRACE << "Testing for " << libpath << endl;
00134             if (access(libpath.c_str(), R_OK) == 0) {
00135               getLog() << Log::TRACE << "Found " << libpath << endl;
00136               return libpath;
00137             }
00138           }
00139         }
00140       }
00141       // Fall back to non-Genser structure
00142       foreach (const string& d, searchdirs) {
00143         const string libdir = d + "/lib";
00144         vector<string> libnames;
00145         libnames += libname,(info.libname+info.pkgversion+SYSDSO);
00146         foreach (string& ln, libnames) {
00147           string libpath = libdir + "/" + ln;
00148           // Remove duplicate slashes from path
00149           while (libpath.find("//") != string::npos) {
00150             libpath.replace(libpath.find("//"), 2, "/");
00151           }
00152           // Return path if present
00153           getLog() << Log::TRACE << "Testing for " << libpath << endl;
00154           if (access(libpath.c_str(), R_OK) == 0) {
00155             getLog() << Log::TRACE << "Found " << libpath << endl;
00156             return libpath;
00157           }
00158         }
00159       }
00160       return "";
00161     }
00162 
00163 
00164 
00165     string findGenLib(const GenLibInfo& info) {
00166       // Build up lists of search directories and platforms
00167       vector<string> platforms = getPlatforms(info);
00168       vector<string> dirs = getLibSearchDirs(info);
00169 
00170       return findGenLib(info, dirs, platforms);
00171     }
00172 
00173 
00174 
00175     void* loadGenLib(const string& libpath, int dlmode=(RTLD_LAZY|RTLD_GLOBAL)) {
00176       getLog() << Log::TRACE << "Trying to load " << libpath << endl;
00177       void* lib = dlopen(libpath.c_str(), dlmode);
00178       if (lib) {
00179         getLog() << Log::TRACE << "Successfully loaded " << libpath << " (" << lib << ")" << endl;
00180         // If this is an AGILe interface, set the global handle
00181         if (libpath.find("libAGILe") != string::npos) {
00182           getLog() << Log::TRACE << "Setting AGILe module handle for " << libpath
00183                    << " (" << lib << ")" << endl;
00184           agilehandle = lib;
00185         }
00186       } else {
00187         getLog() << Log::TRACE << "Failed to load " << libpath << endl;
00188       }
00189       return lib;
00190     }
00191 
00192 
00193     void* loadGenLib(const GenLibInfo& info, int dlmode=(RTLD_LAZY|RTLD_GLOBAL)) {
00194       const string libpath = findGenLib(info);
00195       if (libpath != "") {
00196         return loadGenLib(libpath, dlmode);
00197       }
00198       return 0;
00199     }
00200 
00201 
00202     vector<string> _findGenVersions(const string& name) {
00203       vector<string> rtn;
00204       vector<string> dirs = getGenPaths();
00205       foreach (const string& d, dirs) {
00206         oslink::directory dir(d + "/" + name);
00207         while (dir) {
00208           string filename = dir.next();
00209           if (filename == "." || filename == "..") continue;
00210           if (filename.find(".2") == filename.length()-2 || filename.find(".3") == filename.length()-2) {
00211             filename = filename.substr(0, filename.length()-2);
00212           }
00213           //if (rtn.find(filename) == rtn.end()) rtn += filename;
00214           if (find(rtn.begin(), rtn.end(), filename) == rtn.end()) rtn += filename;
00215         }
00216       }
00217       // Get the versions sorted most-recent first, so that it will be the first to be tested
00218       sort(rtn.begin(), rtn.end());
00219       rtn += "HEAD";
00220       reverse(rtn.begin(), rtn.end());
00221       return rtn;
00222     }
00223 
00224 
00225     GenLibs _getAllGenLibInfo() {
00226 
00227       // Is LHAPDF available?
00228       const vector<string> lhapdf_versions = _findGenVersions("lhapdf");
00229       bool haveLHAPDF = false;
00230       GenLibInfo lhapdfLibInfo("DUMMY");
00231       foreach (const string& v, lhapdf_versions) {
00232         lhapdfLibInfo = GenLibInfo("libLHAPDF", "lhapdf", v);
00233         haveLHAPDF = ! findGenLib(lhapdfLibInfo).empty();
00234         if (haveLHAPDF) break;
00235       }
00236       // Try to fall back to non-Genser packaging
00237       if (!haveLHAPDF) {
00238         lhapdfLibInfo = GenLibInfo("libLHAPDF");
00239         haveLHAPDF = ! findGenLib(lhapdfLibInfo).empty();
00240       }
00241       // Announce the result
00242       if (haveLHAPDF) {
00243         Log::getLog("AGILe.Loader") << Log::DEBUG << "LHAPDF is available" << endl;
00244       } else {
00245         Log::getLog("AGILe.Loader") << Log::WARN << "LHAPDF is not available" << endl;
00246       }
00247 
00248 
00249       // Find available Fortran generator versions
00250       vector<string> py6_versions = _findGenVersions("pythia6");
00251       vector<string> hw6_versions = _findGenVersions("herwig");
00252       vector<string> alpgen_versions = _findGenVersions("alpgen");
00253       vector<string> rapgap_versions = _findGenVersions("rapgap");
00254       vector<string> cascade_versions = _findGenVersions("cascade");
00255       vector<string> ariadne_versions = _findGenVersions("ariadne");
00256       vector<string> phojet_versions = _findGenVersions("phojet");
00257 
00258 
00259       // Return value, to be populated
00260       GenLibs gens;
00261 
00262 
00263       // Fortran Herwig + variants
00264       foreach (const string& v, hw6_versions) {
00265         vector<GenLibInfo> baselibs, reqlibs;
00266         baselibs += GenLibInfo("libherwig", "herwig", v);
00267         if (haveLHAPDF) {
00268           baselibs += lhapdfLibInfo;
00269         } else {
00270           baselibs += GenLibInfo("libherwig_pdfdummy", "herwig", v);
00271         }
00272         baselibs += GenLibInfo("libHepMCfio");
00273         baselibs += GenLibInfo("libAGILeFHerwig");
00274         const GenLibInfo libinfo_herwigdummy("libherwig_dummy", "herwig", v);
00275         const GenLibInfo libinfo_jimmy("libjimmy", "jimmy", "4.31");
00276         const GenLibInfo libinfo_charybher("libcharybdis-h", "charybdis", "1.003hp");
00278         // Standard Herwig
00279         reqlibs = baselibs;
00280         reqlibs += libinfo_herwigdummy;
00281         gens["Herwig:" + v] = reqlibs;
00282         //
00283         // Herwig+Jimmy
00284         reqlibs = baselibs;
00285         reqlibs += libinfo_herwigdummy;
00286         reqlibs += libinfo_jimmy;
00287         reqlibs += GenLibInfo("libAGILeFHerwigJimmy");
00288         gens["HerwigJimmy:" + v] = reqlibs;
00289         //
00290         // Herwig(+Jimmy)+AlpGen
00291         foreach (const string& alpgen_version, alpgen_versions) {
00292           // Herwig+AlpGen
00293           reqlibs = baselibs;
00294           reqlibs += GenLibInfo("libalpgen", "alpgen", alpgen_version);
00295           reqlibs += GenLibInfo("libalpsho", "alpgen", alpgen_version);
00296           reqlibs += GenLibInfo("libatoher", "alpgen", alpgen_version);
00297           reqlibs += GenLibInfo("libAGILeAlpGen");
00298           reqlibs += GenLibInfo("libAGILeAlpGenFHerwig");
00299           gens["AlpGenHerwig:" + v + ":" + alpgen_version] = reqlibs;
00300           // Herwig+Jimmy+AlpGen
00301           reqlibs = baselibs;
00302           reqlibs += GenLibInfo("libalpgen", "alpgen", alpgen_version);
00303           reqlibs += GenLibInfo("libalpsho", "alpgen", alpgen_version);
00304           reqlibs += GenLibInfo("libatoher", "alpgen", alpgen_version);
00305           reqlibs += libinfo_jimmy;
00306           reqlibs += GenLibInfo("libAGILeAlpGen");
00307           reqlibs += GenLibInfo("libAGILeFHerwigJimmy");
00308           reqlibs += GenLibInfo("libAGILeAlpGenFHerwigJimmy");
00309           gens["AlpGenHerwigJimmy:" + v + ":" + alpgen_version] = reqlibs;
00310         }
00311         //
00312         // Herwig+Charybdis
00313         reqlibs = baselibs;
00314         reqlibs += libinfo_charybher;
00315         reqlibs += GenLibInfo("libAGILeCharybdis");
00316         reqlibs += GenLibInfo("libAGILeCharybdisFHerwig");
00317         gens["CharybdisHerwig:" + v] = reqlibs;
00318         //
00319         // Herwig+Jimmy+Charybdis
00320         reqlibs = baselibs;
00321         reqlibs += libinfo_charybher;
00322         reqlibs += libinfo_jimmy;
00323         reqlibs += GenLibInfo("libAGILeCharybdis");
00324         reqlibs += GenLibInfo("libAGILeFHerwigJimmy");
00325         reqlibs += GenLibInfo("libAGILeCharybdisFHerwigJimmy");
00326         gens["CharybdisHerwigJimmy:" + v] = reqlibs;
00327       }
00328 
00329 
00330       // Fortran Pythia + variants
00331       foreach (const string& v, py6_versions) {
00332         vector<GenLibInfo> baselibs, reqlibs;
00333         baselibs += GenLibInfo("libpythia6", "pythia6", v);
00334         if (haveLHAPDF) {
00335           baselibs += lhapdfLibInfo;
00336         } else {
00337           baselibs += GenLibInfo("libpythia6_pdfdummy", "pythia6", v);
00338         }
00339         baselibs += GenLibInfo("libHepMCfio");
00340         //
00341         // Standard Pythia
00342         reqlibs = baselibs;
00343         reqlibs += GenLibInfo("libAGILeFPythia_pyevwt");
00344         reqlibs += GenLibInfo("libpythia6_dummy", "pythia6", v);
00345         reqlibs += GenLibInfo("libAGILeFPythia");
00346         gens["Pythia6:" + v] = reqlibs;
00347         //
00348         // Pythia+AlpGen
00349         foreach (const string& alpgen_version, alpgen_versions) {
00350           reqlibs = baselibs;
00351           reqlibs += GenLibInfo("libalpgen", "alpgen", alpgen_version);
00352           reqlibs += GenLibInfo("libalpsho", "alpgen", alpgen_version);
00353           reqlibs += GenLibInfo("libatopyt", "alpgen", alpgen_version);
00354           reqlibs += GenLibInfo("libpythia6_dummy", "pythia6", v);
00355           reqlibs += GenLibInfo("libAGILeAlpGen");
00356           reqlibs += GenLibInfo("libAGILeAlpGenFPythia");
00357           gens["AlpGenPythia6:" + v + ":" + alpgen_version] = reqlibs;
00358         }
00359         //
00360         // Pythia+Charybdis
00361         reqlibs = baselibs;
00362         reqlibs += GenLibInfo("libcharybdis", "charybdis", "1.003hp");
00363         reqlibs += GenLibInfo("libpythia6_dummy", "pythia6", v);
00364         reqlibs += GenLibInfo("libAGILeCharybdis");
00365         reqlibs += GenLibInfo("libAGILeCharybdisFPythia");
00366         gens["CharybdisPythia6:" + v] = reqlibs;
00367         //
00368         // Pythia+Rapgap
00369         foreach (const string& vr, rapgap_versions) {
00370           reqlibs.clear();
00371           reqlibs += GenLibInfo("libpythia6", "pythia6", v);
00372           reqlibs.push_back(GenLibInfo("libpythia6_dummy", "pythia6", v)); // This is for pytime
00373           //reqlibs += GenLibInfo("libpythia6_dummies", "pythia6", v);
00374           reqlibs += GenLibInfo("librapgap32", "Rapgap", vr);
00375           reqlibs += GenLibInfo("libHepMCfio"); // This order is important
00376           if (haveLHAPDF) {
00377             reqlibs += lhapdfLibInfo;
00378           } else {
00379             reqlibs += GenLibInfo("libpythia6_pdfdummy", "pythia6", v);
00380           }
00381           reqlibs += GenLibInfo("libAGILeRapgap");
00382           gens["RapgapPythia6:" + v + ":" + vr] = reqlibs;
00383         }
00384         //
00385         // Pythia+Cascade
00386         foreach (const string& vc, cascade_versions) {
00387           vector<GenLibInfo> baselibs, reqlibs;
00388           baselibs.push_back(GenLibInfo("libpythia6", "pythia6", v));
00389           baselibs.push_back(GenLibInfo("libpythia6_dummy", "pythia6", v)); // This is for pytime
00390           baselibs.push_back(GenLibInfo("libcascade2", "cascade", vc));
00391           baselibs.push_back(GenLibInfo("libHepMCfio")); // This order is important
00392           if (haveLHAPDF) {
00393             reqlibs += lhapdfLibInfo;
00394           } else {
00395             reqlibs += GenLibInfo("libpythia6_pdfdummy", "pythia6", v);
00396           }
00397 
00398           reqlibs = baselibs;
00399           reqlibs.push_back(GenLibInfo("libAGILeCascade"));
00400           gens["CascadePythia6:" + v + ":" + vc] = reqlibs;
00401         }
00402         //
00403         // Pythia+Ariadne
00404         foreach (const string& va, ariadne_versions) {
00405           vector<GenLibInfo> baselibs, reqlibs;
00406           baselibs.push_back(GenLibInfo("libpythia6", "pythia6", v));
00407           baselibs.push_back(GenLibInfo("libar4", "ariadne", va));
00408           baselibs.push_back(GenLibInfo("libHepMCfio")); // This order is important
00409           if (haveLHAPDF) {
00410             reqlibs += lhapdfLibInfo;
00411           } else {
00412             reqlibs += GenLibInfo("libpythia6_pdfdummy", "pythia6", v);
00413           }
00414 
00415           reqlibs = baselibs;
00416           reqlibs.push_back(GenLibInfo("libAGILeAriadne"));
00417           gens["Ariadne" + va + ":" + "Pythia6." + v] = reqlibs;
00418         }
00419         //
00420         // Pythia+Phojet
00421         foreach (const string& vp, phojet_versions) {
00422           vector<GenLibInfo> baselibs, reqlibs;
00423           baselibs.push_back(GenLibInfo("libpythia6", "pythia6", v));
00424           baselibs.push_back(GenLibInfo("libphojet", "phojet", vp));
00425           baselibs.push_back(GenLibInfo("libHepMCfio")); // This order is important
00426           if (haveLHAPDF) {
00427             reqlibs += lhapdfLibInfo;
00428           } else {
00429             reqlibs += GenLibInfo("libpythia6_pdfdummy", "pythia6", v);
00430           }
00431 
00432           reqlibs = baselibs;
00433           reqlibs.push_back(GenLibInfo("libAGILePhojet"));
00434           gens["Phojet" + vp + ":" + "Pythia6." + v] = reqlibs;
00435         }
00436       }
00437 
00438       return gens;
00439     }
00440 
00441 
00442     // Find which generators are present by testing the files.
00443     vector<string> getAvailableGens() {
00444       GenLibs genlibs = _getAllGenLibInfo();
00445       vector<string> availableGens;
00446       typedef pair<string, vector<GenLibInfo> > GenLibInfoKV;
00447       foreach (const GenLibInfoKV& g, genlibs) {
00448         getLog() << Log::TRACE << "Trying to find libs for " << g.first << endl;
00449         // All listed libraries must be available for each generator to be considered useable.
00450         bool ok = true;
00451         foreach (const GenLibInfo& l, g.second) {
00452           const string libpath = findGenLib(l);
00453           if (libpath != "") {
00454             getLog() << Log::TRACE << "Found " << l.libname << " at " << libpath << endl;
00455           } else {
00456             getLog() << Log::TRACE << "Didn't find "
00457                      << l.pkgname << ":" << l.pkgversion << ":" << l.libname << endl;
00458             ok = false;
00459             break;
00460           }
00461         }
00462         // If all libs were present, add this gen to the "available" list.
00463         if (ok) {
00464           getLog() << Log::DEBUG << "Found all libs for " << g.first << endl;
00465           availableGens.push_back(g.first);
00466         }
00467       }
00468       return availableGens;
00469     }
00470 
00471 
00472     void loadGenLibs(const string& genname) {
00473       const string fioName = "libHepMCfio";
00474       string agileName = "";
00475       string pdflibName = "";
00476 
00477       // Get version string from colon separated version string if given.
00478       string name = genname;
00479       version = "";
00480       const size_t colonpos = genname.rfind(":");
00481       if (colonpos != string::npos) {
00482         const size_t versionlength = genname.length() - colonpos - 1;
00483         name = genname.substr(0, colonpos);
00484         version = genname.substr(colonpos+1, versionlength);
00485       }
00486 
00487       GenLibs genlibs = _getAllGenLibInfo();
00488       if (genlibs.find(genname) == genlibs.end()) {
00489         throw runtime_error("Trying to load an unknown generator combination: " + genname);
00490       } else {
00491         const vector<GenLibInfo> libs = genlibs[genname];
00492         for (vector<GenLibInfo>::const_iterator l = libs.begin(); l != libs.end(); ++l) {
00493           handles.push_back(loadGenLib(*l));
00494         }
00495       }
00496 
00497 
00498       // Check and reset dlopen errors
00499       for (vector<void*>::const_iterator h = handles.begin(); h != handles.end(); ++h) {
00500         if (*h == 0) {
00501           throw runtime_error((string("Failed to load libraries: ") + dlerror()).c_str());
00502         }
00503       }
00504       dlerror();
00505     }
00506 
00507 
00508     template <typename Fn>
00509     inline Fn evil_cast(void* ptr) {
00510       return reinterpret_cast<Fn>(reinterpret_cast<size_t>(ptr));
00511     }
00512 
00513 
00514     Generator* createGen() {
00515       // Load the factory and create an instance of the class
00516       void* makeGen = dlsym(agilehandle, "create");
00517       if (char* err = dlerror()) {
00518         throw runtime_error((string("Can't load creation factory: ") + err).c_str());
00519       }
00520 
00521       // Make the generator object.
00522       Generator* gen = evil_cast<Creator>(makeGen)();
00523 
00524       // Set the generator version for e.g. HepML dumps of generator state.
00525       gen->setVersion(version);
00526 
00527       return gen;
00528     }
00529 
00530 
00531     void destroyGen(Generator* gen) {
00532       //Destroyer* destroy_gen = (Destroyer*) dlsym(agilemod, "destroy");
00533       //if (dlerror()) {
00534       //  throw runtime_error("Can't load destruction factory");
00535       //}
00536       //destroy_gen(gen);
00537       delete gen;
00538     }
00539 
00540 
00541     // Close the libraries
00542     void finalize() {
00543       for (vector<void*>::reverse_iterator h = handles.rbegin(); h != handles.rend(); ++h) {
00544         if (*h != 0) dlclose(*h);
00545       }
00546     }
00547 
00548 
00549   }
00550 }
Generated on Tue Mar 6 10:39:38 2012 for AGILe - A Generator Interface Library (+ executable) by  doxygen 1.6.3