inlib
1.2.0
|
00001 // Copyright (C) 2010, Guy Barrand. All rights reserved. 00002 // See the file inlib.license for terms. 00003 00004 #ifndef inlib_sys_plugin 00005 #define inlib_sys_plugin 00006 00007 #include "../smanip" 00008 00009 #include <ostream> 00010 #include <cstdlib> 00011 #include <cstring> //memcpy 00012 00013 #ifdef WIN32 00014 #include <windows.h> 00015 #else 00016 #include <dlfcn.h> 00017 #endif 00018 00019 namespace inlib { 00020 00021 class plugin { 00022 public: 00023 plugin(const std::string& a_name,std::ostream& a_out,bool a_verbose = false,bool a_quiet = false) 00024 :m_module(0) 00025 ,m_out(a_out) 00026 ,m_name(a_name) 00027 ,m_verbose(a_verbose) 00028 { 00029 // a_name is the full name (path + libname). 00030 if(!open()) { 00031 if(!a_quiet) { 00032 m_out << "inlib::plugin :" 00033 << " can't load " << sout(m_name) << " library." << std::endl; 00034 m_out << "inlib::plugin :" 00035 << " error : " << m_error 00036 << std::endl; 00037 } 00038 } 00039 } 00040 00041 virtual ~plugin(){close();} 00042 00043 protected: 00044 plugin(const plugin& a_from):m_out(a_from.m_out){} 00045 plugin& operator=(const plugin&){return *this;} 00046 00047 public: 00048 bool open() { 00049 m_error = ""; 00050 std::string splg = m_name; 00051 if(m_verbose) { 00052 m_out << "inlib::plugin :" 00053 << " open " 00054 << sout(splg) << "..." << std::endl; 00055 } 00056 #ifdef WIN32 00057 m_module = ::LoadLibrary(splg.c_str()); 00058 #else 00059 {std::string path,name,sfx; 00060 path_name_suffix(m_name,path,name,sfx); 00061 if(path.empty()) { //Relative path 00062 std::string sfx = suffix(splg); 00063 if(sfx.empty()) { 00064 // Only the name "Xxx" had been given, we have to 00065 #if defined(__CYGWIN__) && defined(__GNUC__) 00066 // build the name "Xxx.dll" : 00067 splg = m_name + ".dll"; 00068 #elif defined(__APPLE__) 00069 splg = m_name + ".bundle"; 00070 #else 00071 // build the name "libXxx.so" : 00072 splg = "lib" + m_name + ".so"; 00073 #endif 00074 } 00075 }} 00076 int flags = RTLD_NOW | RTLD_GLOBAL; 00077 m_module = ::dlopen(splg.c_str(),flags); 00078 #if defined(__APPLE__) 00079 if(!m_module) { 00080 std::vector<std::string> ps = paths(); 00081 unsigned int pathn = ps.size(); 00082 for(unsigned int index=0;index<pathn;index++) { 00083 splg = ps[index]+"/" + m_name + ".bundle"; 00084 if(m_verbose) { 00085 m_out << "inlib::plugin::open :" 00086 << " open " 00087 << sout(splg) << "..." 00088 << std::endl; 00089 } 00090 m_module = ::dlopen(splg.c_str(),flags); 00091 if(m_module) break; 00092 } 00093 } 00094 #endif 00095 const char* cerror; 00096 if ((cerror=dlerror())!=NULL) m_error = cerror; 00097 #endif 00098 if(!m_module) return false; 00099 if(m_verbose) { 00100 m_out << "inlib::plugin :" 00101 << " " << sout(splg) << " opened." << std::endl; 00102 } 00103 m_plugin = splg; 00104 return true; 00105 } 00106 00107 void close(){ 00108 if(!m_module) return; //done 00109 if(m_verbose) { 00110 m_out << "inlib::close :" 00111 << " close " << sout(m_name) << "..." << std::endl; 00112 } 00113 #ifdef WIN32 00114 ::FreeLibrary((HMODULE)m_module); 00115 #else 00116 if(::dlclose(m_module)) { 00117 m_out << "inlib::~plugin :" 00118 << " error : " << ::dlerror() << std::endl; 00119 } 00120 #endif 00121 if(m_verbose) { 00122 m_out << "inlib::~plugin :" 00123 << " close " << sout(m_name) << " done." << std::endl; 00124 } 00125 m_module = 0; 00126 } 00127 00128 bool is_opened() const {return m_module?true:false;} 00129 00130 const std::string& file_name() const{return m_name;} 00131 00132 typedef void (*procedure)(); 00133 00134 procedure find(const std::string& a_name,bool a_quiet = false) const { 00135 if(!m_module) return 0; 00136 std::string name = a_name; 00137 procedure p = 0; 00138 if(m_verbose) { 00139 m_out << "inlib::find :" 00140 << " search symbol " 00141 << sout(name) << "..." << std::endl; 00142 } 00143 #ifdef WIN32 00144 p = (procedure)::GetProcAddress((HMODULE)m_module,name.c_str()); 00145 if (!p) { 00146 name = "_" + a_name; 00147 p = (procedure)::GetProcAddress((HMODULE)m_module,name.c_str()); 00148 if (!p) { 00149 if(!a_quiet) { 00150 m_out << "Lib : Can't find symbol " << sout(a_name) << "." 00151 << std::endl; 00152 } 00153 } 00154 } 00155 #else 00156 void* a = ::dlsym(m_module,(char*)name.c_str()); 00157 //trick to avoid the warning : 00158 //ISO C++ forbids casting between pointer-to-function and pointer-to-object 00159 ::memcpy(&p,&a,sizeof(void*)); //beurk 00160 00161 const char* cerror; 00162 if ((cerror=dlerror())!=NULL) { 00163 std::string serror = cerror; 00164 name = "_" + a_name; 00165 void* a = ::dlsym(m_module,(char*)name.c_str()); 00166 ::memcpy(&p,&a,sizeof(void*)); //rebeurk 00167 00168 if ((cerror=dlerror())!=NULL) { 00169 if(!a_quiet) { 00170 m_out << "inlib::find :" 00171 << " problem when searching " << sout(a_name) 00172 << " in " << sout(m_plugin) << "." 00173 << " dlerror : " << serror << std::endl; 00174 } 00175 } 00176 } 00177 #endif 00178 if(p && m_verbose) { 00179 m_out << "inlib::find :" 00180 << " symbol " << sout(name) << " found." << std::endl; 00181 } 00182 return p; 00183 } 00184 00185 public: 00186 static bool is_valid(const std::string& a_name,std::ostream& a_out) { 00187 plugin plg(a_name,a_out,0,true); 00188 bool status = plg.is_opened(); 00189 plg.close(); 00190 return status; 00191 } 00192 00193 protected: 00194 static std::vector<std::string> paths() { //APPLE only. 00195 const char* env = ::getenv("DYLD_LIBRARY_PATH"); 00196 if(!env) env = ::getenv("GDB_DYLD_LIBRARY_PATH"); 00197 std::string senv = (env==NULL ? std::string("") : std::string(env)); 00198 return words(senv,":"); 00199 } 00200 00201 protected: 00202 void* m_module; 00203 std::ostream& m_out; 00204 std::string m_name; 00205 std::string m_plugin; 00206 bool m_verbose; 00207 std::string m_error; 00208 }; 00209 00210 } 00211 00212 #include <map> 00213 00214 namespace inlib { 00215 00216 class plugin_cache { 00217 public: 00218 virtual bool open(const std::string& a_name,plugin*& a_plugin){ 00219 std::map<std::string,plugin*>::iterator it = m_cache.find(a_name); 00220 if(it!=m_cache.end()) { //a_name in the cache. 00221 a_plugin = (*it).second; 00222 return true; 00223 } 00224 a_plugin = new plugin(a_name,m_out); 00225 if(!a_plugin->is_opened()) { 00226 m_out << "inlib::can't open plugin " << a_name << std::endl; 00227 delete a_plugin; 00228 a_plugin = 0; 00229 return false; 00230 } 00231 m_cache[a_name] = a_plugin; 00232 return true; 00233 } 00234 public: 00235 plugin_cache(std::ostream& a_out) 00236 :m_out(a_out) 00237 {} 00238 virtual ~plugin_cache(){clear();} 00239 protected: 00240 plugin_cache(const plugin_cache& a_from) 00241 :m_out(a_from.m_out) 00242 {} 00243 plugin_cache& operator=(const plugin_cache&){return *this;} 00244 public: 00245 void clear() { 00246 std::map<std::string,plugin*>::iterator it; 00247 for(it = m_cache.begin();it!=m_cache.end();++it) { 00248 delete (*it).second; 00249 } 00250 m_cache.clear(); 00251 } 00252 protected: 00253 std::ostream& m_out; 00254 std::map<std::string,plugin*> m_cache; 00255 }; 00256 00257 00258 } 00259 00260 #endif