OpenWalnut  1.5.0dev
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 <memory>
26 #include <set>
27 #include <string>
28 #include <vector>
29 
30 #include <boost/regex.hpp>
31 
32 #include "../common/WIOTools.h"
33 #include "../common/WPathHelper.h"
34 #include "../common/WSharedLib.h"
35 #include "WModuleLoader.h"
36 
38 {
39  // initialize members
40 }
41 
43 {
44  // cleanup all the handles
45  m_libs.clear();
46 }
47 
48 void WModuleLoader::load( WSharedAssociativeContainer< std::set< std::shared_ptr< WModule > > >::WriteTicket ticket,
49  boost::filesystem::path dir, unsigned int level )
50 {
51  for( boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator( dir );
52  i != boost::filesystem::directory_iterator(); ++i )
53  {
54  // all modules need to begin with this
55  std::string stem = i->path().stem().string();
56 
57  // we want to strip the search directory from the path
58  std::string relPath = i->path().string();
59  relPath.erase( 0, dir.string().length() + 1 ); // NOTE: +1 because we want to remove the "/" too
60 
61  // is it a lib? Use a regular expression to check this
62  // NOTE:: the double \\ is needed to escape the escape char (to interpret the "dot" as dot and not as "any char".
63  #ifdef __WIN32__
64  static const boost::regex CheckLibMMP( "^(lib)?(.*)\\" + WSharedLib::getSystemSuffix() +"$" );
65  #elif __APPLE__
66  static const boost::regex CheckLibMMP( "^(lib)?(.*)\\.[0-9]+\\.[0-9]+\\.[0-9]+\\" + WSharedLib::getSystemSuffix() + "$" );
67  #else
68  static const boost::regex CheckLibMMP( "^(lib)?(.*)\\" + WSharedLib::getSystemSuffix() + "\\.[0-9]+\\.[0-9]+\\.[0-9]+$" );
69  #endif
70  // this will contain the filename afterwards
71  boost::smatch matches;
72  std::string fn = i->path().filename().string();
73  bool matchLibName = boost::regex_match( fn, matches, CheckLibMMP );
74  std::string libBaseName = matchLibName ? std::string( matches[2] ) : "";
75 
76  if( !boost::filesystem::is_directory( *i ) &&
77  matchLibName &&
78  ( stem.compare( 0, getModulePrefix().length(), getModulePrefix() ) == 0 )
79  )
80  {
81  try
82  {
83  // load lib
84  std::shared_ptr< WSharedLib > l( new WSharedLib( i->path() ) );
85 
86  bool isLoadableModule = false;
87  bool isLoadableArbitrary = false;
88 
89  // be nice. Do not fail if the module symbol does not exist
90  if( l->existsFunction( W_LOADABLE_MODULE_SYMBOL ) )
91  {
92  // get instantiation function
93  W_LOADABLE_MODULE_SIGNATURE f;
94  l->fetchFunction< W_LOADABLE_MODULE_SIGNATURE >( W_LOADABLE_MODULE_SYMBOL, f );
95 
96  isLoadableModule = true;
97 
98  // get the first prototype
99  WModuleList m;
100  f( m );
101 
102  // could the prototype be created?
103  if( m.empty() )
104  {
105  continue;
106  }
107  else
108  {
109  // yes, add it to the list of prototypes
110  for( WModuleList::const_iterator iter = m.begin(); iter != m.end(); ++iter )
111  {
112  // which lib?
113  ( *iter )->setLibPath( i->path() );
114  // we use the library name (excluding extension and optional lib prefix) as package name
115  ( *iter )->setPackageName( libBaseName );
116  // resource path
117  ( *iter )->setLocalPath( WPathHelper::getModuleResourcePath( i->path().parent_path(), ( *iter )->getPackageName() ) );
118 
119  // add module
120  ticket->get().insert( *iter );
121 
122  // we need to keep a reference to the lib
123  m_libs.push_back( l );
124  }
125 
126  wlog::debug( "Module Loader" ) << "Loaded " << m.size() << " modules from " << relPath;
127  }
128  }
129 
130  // do the same for the arbitrary register functionality
131  // get instantiation function
132  if( l->existsFunction( W_LOADABLE_REGISTERARBITRARY_SYMBOL ) )
133  {
134  isLoadableArbitrary = true;
135 
136  // store this temporarily. This is called later, after OW was completely initialized
137  // put together the right path and call function
138  m_arbitraryRegisterLibs.push_back(
139  PostponedLoad( l, WPathHelper::getModuleResourcePath( i->path().parent_path(), libBaseName ) )
140  );
141  }
142  // lib gets closed if l looses focus
143 
144  if( !isLoadableModule && !isLoadableArbitrary )
145  {
146  wlog::warn( "Module Loader" ) << "Library does neither contain a module nor another extension.";
147  }
148  }
149  catch( const WException& e )
150  {
151  WLogger::getLogger()->addLogMessage( "Load failed for module \"" + relPath + "\". " + e.what() + ". Ignoring.",
152  "Module Loader", LL_ERROR );
153  }
154  }
155  else if( ( level <= 10 ) && // this sould be enough to tranverse the typical structure build/release/lib/openwalnut/MODULENAME (5 levels)
156  boost::filesystem::is_directory( *i ) ) // this only traverses down one level
157  {
158  // if it a dir -> traverse down
159  load( ticket, *i, level + 1 );
160  }
161  }
162 }
163 
164 void WModuleLoader::load( WSharedAssociativeContainer< std::set< std::shared_ptr< WModule > > >::WriteTicket ticket )
165 {
166  std::vector< boost::filesystem::path > allPaths = WPathHelper::getAllModulePaths();
167 
168  // go through each of the paths
169  for( std::vector< boost::filesystem::path >::const_iterator path = allPaths.begin(); path != allPaths.end(); ++path )
170  {
171  WLogger::getLogger()->addLogMessage( "Searching modules in \"" + ( *path ).string() + "\".", "Module Loader", LL_INFO );
172 
173  // does the directory exist?
174  if( !boost::filesystem::is_directory( *path ) || !boost::filesystem::exists( *path ) )
175  {
176  WLogger::getLogger()->addLogMessage( "Searching modules in \"" + ( *path ).string() +
177  "\" failed. It is not a directory or does not exist." +
178  " Ignoring.", "Module Loader", LL_WARNING );
179 
180  continue;
181  }
182 
183  // directly search the path for libOWmodule_ files
184  load( ticket, *path );
185  }
186 }
187 
189 {
190  typedef std::vector< PostponedLoad > Vec;
191  for( Vec::const_iterator iter = m_arbitraryRegisterLibs.begin(); iter != m_arbitraryRegisterLibs.end(); ++iter )
192  {
193  wlog::debug( "WModuleLoader" ) << "Initializing extensions of \"" << ( *iter ).m_lib->getLibraryName() << "\"";
194  W_LOADABLE_REGISTERARBITRARY_SIGNATURE arbitraryRegister;
195  ( *iter ).m_lib->fetchFunction< W_LOADABLE_REGISTERARBITRARY_SIGNATURE >( W_LOADABLE_REGISTERARBITRARY_SYMBOL, arbitraryRegister );
196  arbitraryRegister( ( *iter ).m_path );
197  }
198 }
199 
201 {
202  // all module file names need to have this prefix:
204 }
205 
Basic exception handler.
Definition: WException.h:39
virtual const char * what() const
Returns the message string set on throw.
Definition: WException.cpp:90
void addLogMessage(std::string message, std::string source="", LogLevel level=LL_DEBUG)
Appends a log message to the logging queue.
Definition: WLogger.cpp:84
static WLogger * getLogger()
Returns pointer to the currently running logger instance.
Definition: WLogger.cpp:64
void initializeExtensions()
The loader also stores information on which library provides the arbitrary registration mechanism.
std::vector< std::shared_ptr< WSharedLib > > m_libs
All the loaded shared libraries.
Definition: WModuleLoader.h:90
WModuleLoader()
Constructor.
static std::string getModulePrefix()
Returns the prefix of a shared module library filename.
~WModuleLoader()
Destructor, closes all handles to shared libraries.
std::vector< PostponedLoad > m_arbitraryRegisterLibs
The libs which need to be initialized when OW is loaded completely.
void load(WSharedAssociativeContainer< std::set< std::shared_ptr< WModule > > >::WriteTicket ticket)
Load the module prototypes from the shared libraries.
static boost::filesystem::path getModuleResourcePath(boost::filesystem::path moduleLibPath, std::string packageName)
The path to a given module's resources.
static std::vector< boost::filesystem::path > getAllModulePaths()
This returns a list of search paths for modules.
This class provides a common interface for thread-safe access to associative containers (set,...
This class loads shared libraries and provides function pointers.
Definition: WSharedLib.h:45
static std::string getSystemSuffix()
Returns the suffix for libraries used on the system.
Definition: WSharedLib.cpp:316
static std::string getSystemPrefix()
Returns the prefix used for libraries on the system.
Definition: WSharedLib.cpp:311
WStreamedLogger debug(const std::string &source)
Logging a debug message.
Definition: WLogger.h:331
WStreamedLogger warn(const std::string &source)
Logging a warning message.
Definition: WLogger.h:309
Helper to store information on a lib which gets initialized later.