OpenWalnut 1.3.1
WModuleLoader.cpp
00001 //---------------------------------------------------------------------------
00002 //
00003 // Project: OpenWalnut ( http://www.openwalnut.org )
00004 //
00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
00006 // For more information see http://www.openwalnut.org/copying
00007 //
00008 // This file is part of OpenWalnut.
00009 //
00010 // OpenWalnut is free software: you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as published by
00012 // the Free Software Foundation, either version 3 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // OpenWalnut is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public License
00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
00022 //
00023 //---------------------------------------------------------------------------
00024 
00025 #include <set>
00026 #include <string>
00027 #include <vector>
00028 
00029 #include <boost/regex.hpp>
00030 
00031 #include "../common/WIOTools.h"
00032 #include "../common/WPathHelper.h"
00033 #include "../common/WSharedLib.h"
00034 
00035 #include "WKernel.h"
00036 
00037 #include "WModuleLoader.h"
00038 
00039 WModuleLoader::WModuleLoader( )
00040 {
00041     // initialize members
00042 }
00043 
00044 WModuleLoader::~WModuleLoader()
00045 {
00046     // cleanup all the handles
00047     m_libs.clear();
00048 }
00049 
00050 void WModuleLoader::load( WSharedAssociativeContainer< std::set< boost::shared_ptr< WModule > > >::WriteTicket ticket,
00051                           boost::filesystem::path dir, unsigned int level )
00052 {
00053     for( boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator( dir );
00054          i != boost::filesystem::directory_iterator(); ++i )
00055     {
00056         // all modules need to begin with this
00057         std::string stem = i->path().stem().string();
00058 
00059         // we want to strip the search directory from the path
00060         std::string relPath = i->path().string();
00061         relPath.erase( 0, dir.string().length() + 1 ); // NOTE: +1 because we want to remove the "/" too
00062 
00063         // is it a lib? Use a regular expression to check this
00064         // NOTE:: the double \\ is needed to escape the escape char (to interpret the "dot" as dot and not as "any char".
00065         #ifdef __WIN32__
00066             static const boost::regex CheckLibMMP( "^(lib)?(.*)\\" + WSharedLib::getSystemSuffix() +"$" );
00067         #elif __APPLE__
00068             static const boost::regex CheckLibMMP( "^(lib)?(.*)\\.[0-9]+\\.[0-9]+\\.[0-9]+\\" + WSharedLib::getSystemSuffix() + "$" );
00069         #else
00070             static const boost::regex CheckLibMMP( "^(lib)?(.*)\\" + WSharedLib::getSystemSuffix() + "\\.[0-9]+\\.[0-9]+\\.[0-9]+$" );
00071         #endif
00072         // this will contain the filename afterwards
00073         boost::smatch matches;
00074         bool matchLibName = boost::regex_match( i->path().filename().string(), matches, CheckLibMMP );
00075         std::string libBaseName = matchLibName ? std::string( matches[2] ) : "";
00076 
00077         if( !boost::filesystem::is_directory( *i ) &&
00078             matchLibName &&
00079             ( stem.compare( 0, getModulePrefix().length(), getModulePrefix() ) == 0 )
00080           )
00081         {
00082             try
00083             {
00084                 // load lib
00085                 boost::shared_ptr< WSharedLib > l = boost::shared_ptr< WSharedLib >( new WSharedLib( i->path() ) );
00086 
00087                 // get instantiation function
00088                 W_LOADABLE_MODULE_SIGNATURE f;
00089                 l->fetchFunction< W_LOADABLE_MODULE_SIGNATURE >( W_LOADABLE_MODULE_SYMBOL, f );
00090 
00091                 // get the first prototype
00092                 WModuleList m;
00093                 f( m );
00094 
00095                 // could the prototype be created?
00096                 if( m.empty() )
00097                 {
00098                     WLogger::getLogger()->addLogMessage( "Load failed for module \"" + relPath + "\". Could not create any " +
00099                                                          "prototype instance.", "Module Loader", LL_ERROR );
00100                     continue;
00101                 }
00102                 else
00103                 {
00104                     // yes, add it to the list of prototypes
00105                     for( WModuleList::const_iterator iter = m.begin(); iter != m.end(); ++iter )
00106                     {
00107                         // which lib?
00108                         ( *iter )->setLibPath( i->path() );
00109                         // we use the library name (excluding extension and optional lib prefix) as package name
00110                         ( *iter )->setPackageName( libBaseName );
00111                         // resource path
00112                         ( *iter )->setLocalPath( WPathHelper::getModuleResourcePath( i->path().parent_path(), ( *iter )->getPackageName() ) );
00113 
00114                         // add module
00115                         ticket->get().insert( *iter );
00116 
00117                         // we need to keep a reference to the lib
00118                         m_libs.push_back( l );
00119                     }
00120 
00121                     wlog::debug( "Module Loader" ) << "Loaded " << m.size() << " modules from " << relPath;
00122                 }
00123 
00124                 // lib gets closed if l looses focus
00125             }
00126             catch( const WException& e )
00127             {
00128                 WLogger::getLogger()->addLogMessage( "Load failed for module \"" + relPath + "\". " + e.what() + ". Ignoring.",
00129                                                      "Module Loader", LL_ERROR );
00130             }
00131         }
00132         else if( ( level <= 10 ) &&  // this sould be enough to tranverse the typical structure build/release/lib/openwalnut/MODULENAME (5 levels)
00133                  boost::filesystem::is_directory( *i ) )     // this only traverses down one level
00134         {
00135             // if it a dir -> traverse down
00136             load( ticket, *i, level + 1 );
00137         }
00138     }
00139 }
00140 
00141 void WModuleLoader::load( WSharedAssociativeContainer< std::set< boost::shared_ptr< WModule > > >::WriteTicket ticket )
00142 {
00143     std::vector< boost::filesystem::path > allPaths = WPathHelper::getAllModulePaths();
00144 
00145     // go through each of the paths
00146     for( std::vector< boost::filesystem::path >::const_iterator path = allPaths.begin(); path != allPaths.end(); ++path )
00147     {
00148         WLogger::getLogger()->addLogMessage( "Searching modules in \"" + ( *path ).string() + "\".", "Module Loader", LL_INFO );
00149 
00150         // does the directory exist?
00151         if( !boost::filesystem::is_directory( *path ) || !boost::filesystem::exists( *path ) )
00152         {
00153             WLogger::getLogger()->addLogMessage( "Searching modules in \"" + ( *path ).string() +
00154                                                  "\" failed. It is not a directory or does not exist." +
00155                                                  " Ignoring.", "Module Loader", LL_WARNING );
00156 
00157             continue;
00158         }
00159 
00160         // directly search the path for libOWmodule_ files
00161         load( ticket, *path );
00162     }
00163 }
00164 
00165 std::string WModuleLoader::getModulePrefix()
00166 {
00167     // all module file names need to have this prefix:
00168     return WSharedLib::getSystemPrefix();
00169 }
00170