AnalysisLoader.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 #include "Rivet/AnalysisLoader.hh"
00003 #include "Rivet/Tools/Utils.hh"
00004 #include "osdir.hh"
00005 #include <dlfcn.h>
00006 
00007 namespace Rivet {
00008 
00009   bool AnalysisLoader::_loaded = false;
00010   AnalysisBuilders AnalysisLoader::_analysisbuilders;
00011   set<void*> AnalysisLoader::_handles;
00012 
00013 
00014   set<string> AnalysisLoader::getAllAnalysisNames() {
00015     if (!_loaded) loadAnalyses();
00016     set<string> names;
00017     for (AnalysisBuilders::const_iterator ab = _analysisbuilders.begin(); 
00018          ab != _analysisbuilders.end(); ++ab) {
00019       names.insert(ab->first);
00020     }
00021     return names;
00022   }
00023 
00024 
00025   Analysis* AnalysisLoader::getAnalysis(const string& analysisname) { 
00026     if (!_loaded) loadAnalyses();
00027     AnalysisBuilders::iterator ab = _analysisbuilders.find(toUpper(analysisname));
00028     if (ab != _analysisbuilders.end()) {
00029       return ab->second();
00030     } else {
00031       return 0;
00032     }
00033   }
00034 
00035 
00036   set<Analysis*> AnalysisLoader::getAllAnalyses() {
00037     if (!_loaded) loadAnalyses();
00038     set<Analysis*> analyses;
00039     const set<string> names = getAllAnalysisNames();
00040     for (set<string>::const_iterator n = names.begin(); n != names.end(); ++n) {
00041       analyses.insert(getAnalysis(*n));
00042     }
00043     return analyses;
00044   }
00045 
00046 
00047   AnalysisBuilders& AnalysisLoader::loadAnalysisBuildersFromFile(const string& filename, AnalysisBuilders& builders) {      
00048     void* handle = dlopen((filename).c_str(), RTLD_LAZY); 
00049     if (!handle) {
00050       cerr << "Cannot open " << filename << ": " << dlerror() << endl;
00051       return builders;
00052     } else {
00053       // Store a list of libs to be neatly closed later
00054       _handles.insert(handle);
00055     }      
00056     
00057     //cout << "Loading symbol..." << endl;
00058     anabuilders_fn getBuilders = (anabuilders_fn) dlsym(handle, "getAnalysisBuilders");
00059     if (!getBuilders) {
00060       //cerr << "Cannot load symbol 'getAnalysisBuilders': " << dlerror() << endl;
00061       dlclose(handle);
00062       return builders;
00063     }
00064     
00065     //cout << "Calling fn..." << endl;
00066     AnalysisBuilders mybuilders = getBuilders();
00067     //cout << "Loading " << mybuilders.size() << " analyses from " << filename << endl;
00068     for (AnalysisBuilders::iterator b = mybuilders.begin(); b != mybuilders.end(); ++b) {
00069       builders[b->first] = b->second;
00070     }
00071     
00072     return builders;
00073   }
00074 
00075 
00076   void AnalysisLoader::closeAnalysisBuilders() {
00077     for (set<void*>::iterator h = _handles.begin(); h != _handles.end(); ++h) {
00078       if (*h) dlclose(*h);
00079       _handles.erase(*h);
00080     }
00081   }
00082     
00083 
00084   AnalysisBuilders& AnalysisLoader::loadAnalysisBuildersFromDir(const string& dirname, AnalysisBuilders& builders) {
00085     set<string> libfiles;
00086     oslink::directory dir(dirname);
00087     while (dir) {
00088       string filename = dir.next();
00089       
00090       // Require that lib filename matches "*Rivet*.{so,dylib,dll}" (basic glob)
00091       // @todo Use #define SYSDSO ".so", ".dylib", ".dll"
00092       #define SYSDSO string(".so")
00093       size_t posn = filename.find(SYSDSO);
00094       if (posn == string::npos || posn != filename.length()-SYSDSO.length()) continue;
00095       if (filename.find("Rivet") == string::npos) continue;
00096       //cout << "Found dlopen()-able file: " << filename << endl;
00097       libfiles.insert(filename);
00098     }
00099     
00100     for (set<string>::const_iterator l = libfiles.begin(); l != libfiles.end(); ++l) {        
00101       // Make sure this is an abs path
00102       /// @todo Sys-dependent path separator instead of "/"
00103       loadAnalysisBuildersFromFile(dirname + "/" + *l, builders);        
00104     }
00105     
00106     return builders;
00107   }
00108   
00109   
00110   AnalysisBuilders& AnalysisLoader::loadAnalysisBuildersFromDirs(const vector<string>& dirnames, AnalysisBuilders& builders) {
00111     for (vector<string>::const_iterator d = dirnames.begin(); d != dirnames.end(); ++d) {
00112       loadAnalysisBuildersFromDir(*d, builders);
00113     }
00114     return builders;
00115   }
00116   
00117   
00118   void AnalysisLoader::loadAnalyses() {
00119     vector<string> dirs;
00120     char* env = 0;
00121     
00122     // Always (try to) use the Rivet library install path
00123     dirs.push_back(getInstalledLibPath());
00124     
00125     // Then use the Rivet analysis path variable
00126     env = getenv("RIVET_ANALYSIS_PATH");
00127     if (env) dirs += split(env);
00128     
00129     // And then the user's (non-system) library path
00130     env = getenv("LD_LIBRARY_PATH");
00131     if (env) dirs += split(env);
00132     
00133     // Use the current dir, too.
00134     dirs.push_back(".");      
00135     
00136     // Load libs here
00137     loadAnalysisBuildersFromDirs(dirs, _analysisbuilders);
00138     _loaded = true;
00139   }
00140   
00141 
00142 }