OpenWalnut  1.3.1
WModuleLoader.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #include <set>
26 #include <string>
27 #include <vector>
28 
29 #include <boost/regex.hpp>
30 
31 #include "../common/WIOTools.h"
32 #include "../common/WPathHelper.h"
33 #include "../common/WSharedLib.h"
34 
35 #include "WKernel.h"
36 
37 #include "WModuleLoader.h"
38 
40 {
41  // initialize members
42 }
43 
45 {
46  // cleanup all the handles
47  m_libs.clear();
48 }
49 
50 void WModuleLoader::load( WSharedAssociativeContainer< std::set< boost::shared_ptr< WModule > > >::WriteTicket ticket,
51  boost::filesystem::path dir, unsigned int level )
52 {
53  for( boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator( dir );
54  i != boost::filesystem::directory_iterator(); ++i )
55  {
56  // all modules need to begin with this
57  std::string stem = i->path().stem().string();
58 
59  // we want to strip the search directory from the path
60  std::string relPath = i->path().string();
61  relPath.erase( 0, dir.string().length() + 1 ); // NOTE: +1 because we want to remove the "/" too
62 
63  // is it a lib? Use a regular expression to check this
64  // NOTE:: the double \\ is needed to escape the escape char (to interpret the "dot" as dot and not as "any char".
65  #ifdef __WIN32__
66  static const boost::regex CheckLibMMP( "^(lib)?(.*)\\" + WSharedLib::getSystemSuffix() +"$" );
67  #elif __APPLE__
68  static const boost::regex CheckLibMMP( "^(lib)?(.*)\\.[0-9]+\\.[0-9]+\\.[0-9]+\\" + WSharedLib::getSystemSuffix() + "$" );
69  #else
70  static const boost::regex CheckLibMMP( "^(lib)?(.*)\\" + WSharedLib::getSystemSuffix() + "\\.[0-9]+\\.[0-9]+\\.[0-9]+$" );
71  #endif
72  // this will contain the filename afterwards
73  boost::smatch matches;
74  bool matchLibName = boost::regex_match( i->path().filename().string(), matches, CheckLibMMP );
75  std::string libBaseName = matchLibName ? std::string( matches[2] ) : "";
76 
77  if( !boost::filesystem::is_directory( *i ) &&
78  matchLibName &&
79  ( stem.compare( 0, getModulePrefix().length(), getModulePrefix() ) == 0 )
80  )
81  {
82  try
83  {
84  // load lib
85  boost::shared_ptr< WSharedLib > l = boost::shared_ptr< WSharedLib >( new WSharedLib( i->path() ) );
86 
87  // get instantiation function
88  W_LOADABLE_MODULE_SIGNATURE f;
89  l->fetchFunction< W_LOADABLE_MODULE_SIGNATURE >( W_LOADABLE_MODULE_SYMBOL, f );
90 
91  // get the first prototype
92  WModuleList m;
93  f( m );
94 
95  // could the prototype be created?
96  if( m.empty() )
97  {
98  WLogger::getLogger()->addLogMessage( "Load failed for module \"" + relPath + "\". Could not create any " +
99  "prototype instance.", "Module Loader", LL_ERROR );
100  continue;
101  }
102  else
103  {
104  // yes, add it to the list of prototypes
105  for( WModuleList::const_iterator iter = m.begin(); iter != m.end(); ++iter )
106  {
107  // which lib?
108  ( *iter )->setLibPath( i->path() );
109  // we use the library name (excluding extension and optional lib prefix) as package name
110  ( *iter )->setPackageName( libBaseName );
111  // resource path
112  ( *iter )->setLocalPath( WPathHelper::getModuleResourcePath( i->path().parent_path(), ( *iter )->getPackageName() ) );
113 
114  // add module
115  ticket->get().insert( *iter );
116 
117  // we need to keep a reference to the lib
118  m_libs.push_back( l );
119  }
120 
121  wlog::debug( "Module Loader" ) << "Loaded " << m.size() << " modules from " << relPath;
122  }
123 
124  // lib gets closed if l looses focus
125  }
126  catch( const WException& e )
127  {
128  WLogger::getLogger()->addLogMessage( "Load failed for module \"" + relPath + "\". " + e.what() + ". Ignoring.",
129  "Module Loader", LL_ERROR );
130  }
131  }
132  else if( ( level <= 10 ) && // this sould be enough to tranverse the typical structure build/release/lib/openwalnut/MODULENAME (5 levels)
133  boost::filesystem::is_directory( *i ) ) // this only traverses down one level
134  {
135  // if it a dir -> traverse down
136  load( ticket, *i, level + 1 );
137  }
138  }
139 }
140 
141 void WModuleLoader::load( WSharedAssociativeContainer< std::set< boost::shared_ptr< WModule > > >::WriteTicket ticket )
142 {
143  std::vector< boost::filesystem::path > allPaths = WPathHelper::getAllModulePaths();
144 
145  // go through each of the paths
146  for( std::vector< boost::filesystem::path >::const_iterator path = allPaths.begin(); path != allPaths.end(); ++path )
147  {
148  WLogger::getLogger()->addLogMessage( "Searching modules in \"" + ( *path ).string() + "\".", "Module Loader", LL_INFO );
149 
150  // does the directory exist?
151  if( !boost::filesystem::is_directory( *path ) || !boost::filesystem::exists( *path ) )
152  {
153  WLogger::getLogger()->addLogMessage( "Searching modules in \"" + ( *path ).string() +
154  "\" failed. It is not a directory or does not exist." +
155  " Ignoring.", "Module Loader", LL_WARNING );
156 
157  continue;
158  }
159 
160  // directly search the path for libOWmodule_ files
161  load( ticket, *path );
162  }
163 }
164 
166 {
167  // all module file names need to have this prefix:
169 }
170