ARGoS  3
A parallel, multi-engine simulator for swarm robotics
core/utility/plugins/dynamic_loading.cpp
Go to the documentation of this file.
00001 
00007 #include "dynamic_loading.h"
00008 
00009 #include <dirent.h>
00010 #include <cerrno>
00011 
00012 namespace argos {
00013 
00014    /****************************************/
00015    /****************************************/
00016 
00017    CDynamicLoading::TDLHandleMap CDynamicLoading::m_tOpenLibs;
00018    const std::string CDynamicLoading::DEFAULT_PLUGIN_PATH = ARGOS_INSTALL_PREFIX "/lib/argos3/";
00019 
00020    /****************************************/
00021    /****************************************/
00022 
00023    CDynamicLoading::TDLHandle CDynamicLoading::LoadLibrary(const std::string& str_lib) {
00024       TDLHandle tHandle;
00025       /* Check if the provided path is absolute or relative */
00026       if(str_lib[0] == '/') {
00027          /*
00028           * Absolute path
00029           */
00030          /* First check if the library is already loaded */
00031          TDLHandleMap::iterator it = m_tOpenLibs.find(str_lib);
00032          if(it != m_tOpenLibs.end()) {
00033             /* Already loaded */
00034             return m_tOpenLibs[str_lib];
00035          }
00036          /* Not already loaded, load the library and bomb out in case of failure */
00037          tHandle = ::dlopen(str_lib.c_str(), RTLD_LAZY);
00038          if(tHandle == NULL) {
00039             THROW_ARGOSEXCEPTION("Can't load library \""
00040                                  << str_lib
00041                                  << "\", "
00042                                  << ::dlerror());
00043          }
00044          /* Store the handle to the loaded library */
00045          m_tOpenLibs[str_lib] = tHandle;
00046          return tHandle;
00047       }
00048       else {
00049          /*
00050           * Relative path, go through the plugin directories
00051           */
00052          /* String to store the full path to a library */
00053          std::string strLibPath;
00054          /* String to store the list of paths to search */
00055          std::string strPluginPath = ".:" + DEFAULT_PLUGIN_PATH;
00056          /* Get variable ARGOS_PLUGIN_PATH from the environment */
00057          if(::getenv("ARGOS_PLUGIN_PATH") != NULL) {
00058             /* Add value of the variable to list of paths to check */
00059             strPluginPath += ":" + std::string(::getenv("ARGOS_PLUGIN_PATH"));
00060          }
00061          /* Add : at the end to make parsing easier */
00062          if(strPluginPath[strPluginPath.length()-1] != ':') {
00063             strPluginPath.append(":");
00064          }
00065          /*
00066           * Go through paths and try to load the library
00067           */
00068          /* Parse the string */
00069          std::istringstream issPluginPath(strPluginPath);
00070          std::string strDir;
00071          while(std::getline(issPluginPath, strDir, ':')) {
00072             /* Add '/' to dir if missing */
00073             if(strDir[strDir.length()-1] != '/') {
00074                strDir.append("/");
00075             }
00076             strLibPath = strDir + str_lib;
00077             /* First check if the library is already loaded */
00078             TDLHandleMap::iterator it = m_tOpenLibs.find(strLibPath);
00079             if(it != m_tOpenLibs.end()) {
00080                /* Already loaded */
00081                return m_tOpenLibs[strLibPath];
00082             }
00083             /* Not already loaded, try and load the library */
00084             tHandle = ::dlopen(strLibPath.c_str(), RTLD_LAZY);
00085             if(tHandle != NULL) {
00086                /* Store the handle to the loaded library */
00087                m_tOpenLibs[strLibPath] = tHandle;
00088                return tHandle;
00089             }
00090             else {
00091                LOGERR << ::dlerror()
00092                       << std::endl;
00093             }
00094          }
00095          /* If we get here, it's because no directory worked */
00096          THROW_ARGOSEXCEPTION("Can't load library \""
00097                               << str_lib
00098                               << "\".");
00099       }
00100    }
00101 
00102    /****************************************/
00103    /****************************************/
00104 
00105    void CDynamicLoading::UnloadLibrary(const std::string& str_lib) {
00106       TDLHandleMap::iterator it = m_tOpenLibs.find(str_lib);
00107       if(it != m_tOpenLibs.end()) {
00108          UnloadLibrary(it->second);
00109       }
00110       else {
00111          THROW_ARGOSEXCEPTION("Can't load library \""
00112                               << str_lib
00113                               << "\": library does not appear to have been loaded.");
00114       }
00115    }
00116 
00117    /****************************************/
00118    /****************************************/
00119 
00120    void CDynamicLoading::UnloadLibrary(TDLHandle t_lib) {
00121       ::dlclose(t_lib);
00122    }
00123 
00124    /****************************************/
00125    /****************************************/
00126 
00127    void CDynamicLoading::LoadAllLibraries() {      
00128       /* String to store the full path to a library */
00129       std::string strLibPath;
00130       /* String to store the list of paths to search */
00131       std::string strPluginPath = DEFAULT_PLUGIN_PATH;
00132       /* Get variable ARGOS_PLUGIN_PATH from the environment */
00133       if(::getenv("ARGOS_PLUGIN_PATH") != NULL) {
00134          /* Add value of the variable to list of paths to check */
00135          strPluginPath += ":" + std::string(::getenv("ARGOS_PLUGIN_PATH"));
00136       }
00137       /* Add : at the end to make parsing easier */
00138       if(strPluginPath[strPluginPath.length()-1] != ':') {
00139          strPluginPath.append(":");
00140       }
00141       /*
00142        * Go through paths and load all the libraries
00143        */
00144       /* Directory info */
00145       DIR* ptDir;
00146       struct dirent* ptDirData;
00147       /* Parse the string */
00148       std::istringstream issPluginPath(strPluginPath);
00149       std::string strDir;
00150       while(std::getline(issPluginPath, strDir, ':')) {
00151          /* Add '/' to dir if missing */
00152          if(strDir[strDir.length()-1] != '/') {
00153             strDir.append("/");
00154          }
00155          /* Try to open the directory */
00156          ptDir = ::opendir(strDir.c_str());
00157          if(ptDir != NULL) {
00158             /* Directory open, now go through the files in the directory */
00159             while((ptDirData = ::readdir(ptDir)) != NULL) {
00160                /* We have a file, check that it is a library file */
00161                if(std::string(ptDirData->d_name).rfind("." ARGOS_SHARED_LIBRARY_EXTENSION) != std::string::npos) {
00162                   /* It's a library file, load it */
00163                   LoadLibrary(strDir + ptDirData->d_name);
00164                }
00165                if(std::string(ARGOS_SHARED_LIBRARY_EXTENSION) != std::string(ARGOS_MODULE_LIBRARY_EXTENSION)) {
00166                   if(std::string(ptDirData->d_name).rfind("." ARGOS_MODULE_LIBRARY_EXTENSION) != std::string::npos) {
00167                      /* It's a library file, load it */
00168                      LoadLibrary(strDir + ptDirData->d_name);
00169                   }
00170                }
00171             }
00172             /* Close directory */
00173             ::closedir(ptDir);
00174          }
00175          else {
00176             /* Error opening directory open, inform user without bombing out */
00177             LOGERR << "[WARNING] Error opening directory \""
00178                    << strDir
00179                    << "\": "
00180                    << ::strerror(errno)
00181                    << std::endl;
00182          }
00183       }
00184    }
00185 
00186    /****************************************/
00187    /****************************************/
00188 
00189    void CDynamicLoading::UnloadAllLibraries() {
00190       for(TDLHandleMap::iterator it = m_tOpenLibs.begin();
00191           it != m_tOpenLibs.end();
00192           ++it) {
00193          UnloadLibrary(it->second);
00194       }
00195    }
00196 
00197    /****************************************/
00198    /****************************************/
00199 
00200 }