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 }