OpenWalnut  1.2.5
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
WSharedLib.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 <algorithm>
26 #include <cassert>
27 #include <string>
28 
29 #ifdef _WIN32
30  #include <iostream>
31  #include <windows.h> // NOLINT
32 #endif
33 
34 // Use filesystem version 2 for compatibility with newer boost versions.
35 #ifndef BOOST_FILESYSTEM_VERSION
36  #define BOOST_FILESYSTEM_VERSION 2
37 #endif
38 #include <boost/filesystem.hpp>
39 
40 #include "exceptions/WLibraryFetchFailed.h"
41 #include "exceptions/WLibraryLoadFailed.h"
42 #include "WSharedLib.h"
43 
44 #ifdef _WIN32
45 
46 /**
47  * Simple class holding an opened library.
48  */
49 struct WSharedLib::data
50 {
51  /**
52  * Path of lib.
53  */
54  const std::string m_path;
55 
56  /**
57  * Handle describing the loaded lib.
58  */
59  HMODULE m_hDLL;
60 
61  /**
62  * Constructor. Opens and loads the library.
63  *
64  * \see WSharedLib::WSharedLib for details.
65  *
66  * \param path the lib to open
67  */
68  explicit data( const std::string& path ):
69  m_path( path ),
70  m_hDLL( LoadLibrary( path.c_str() ) )
71  {
72  if( !m_hDLL )
73  {
74  throw WLibraryLoadFailed( std::string( "Could not load library \"" + m_path + "\" due to the error: " + errmsg() ) );
75  }
76  }
77 
78  /**
79  * Destructor. Closes the previously opened library handle.
80  */
81  ~data()
82  {
83  FreeLibrary( m_hDLL );
84  }
85 
86  /**
87  * Searches the lib for the specified function symbol and returns it.
88  *
89  * \param name the name of the function
90  *
91  * \return the pointer to the requested function
92  *
93  * \throw WLibraryFetchFailed thrown if the symbol could not be found.
94  */
95  func_ptr_type findFunction( const std::string& name )
96  {
97  func_ptr_type func_ptr = reinterpret_cast< func_ptr_type >( GetProcAddress( m_hDLL, name.c_str() ) );
98  if( !func_ptr )
99  {
100  throw WLibraryFetchFailed( std::string( "Could not fetch symbol \"" + name + "\"" + " due to the error: " + errmsg() ) );
101  }
102  return func_ptr;
103  }
104 
105  /**
106  * Searches the lib for the specified function symbol and returns it.
107  *
108  * \param name the name of the function
109  *
110  * \return the pointer to the requested function
111  *
112  * \throw WLibraryFetchFailed thrown if the symbol could not be found.
113  */
114  void* findVariable( const std::string& name )
115  {
116  return reinterpret_cast< void* >( findFunction( name ) );
117  }
118 
119  /**
120  * Constructs a nice looking error message for the last error occurred.
121  *
122  * \return the last error message
123  */
124  static std::string errmsg()
125  {
126  std::string msg;
127  LPTSTR lpMsgBuf = 0;
128  FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, GetLastError(), 0,
129  reinterpret_cast< LPTSTR >( &lpMsgBuf ), 0, 0 );
130  LPTSTR p = lpMsgBuf;
131  while( *p )
132  {
133  msg.push_back( *p++ );
134  }
135  LocalFree( lpMsgBuf );
136  return msg;
137  }
138 };
139 #else
140 #include <dlfcn.h> // NOLINT
141 #include <pthread.h> // NOLINT
142 
143 namespace
144 {
145  pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
146  struct auto_lock
147  {
148  auto_lock()
149  {
150  pthread_mutex_lock( &mutex );
151  }
152  ~auto_lock()
153  {
154  pthread_mutex_unlock( &mutex );
155  }
156  };
157 }
158 
159 /**
160  * Simple class holding an opened library.
161  */
163 {
164  /**
165  * Path of lib.
166  */
167  const std::string m_path;
168 
169  /**
170  * Handle describing the loaded lib.
171  */
172  void* m_dl;
173 
174  /**
175  * Destructor. Closes the previously opened library handle.
176  */
178  {
179  assert( dlclose( m_dl ) == 0 );
180  }
181 
182  /**
183  * Constructor. Opens and loads the library.
184  *
185  * \see WSharedLib::WSharedLib for details.
186  *
187  * \param path the lib to open
188  */
189  explicit data( const std::string& path )
190  : m_path( path ), m_dl( 0 )
191  {
192  auto_lock lock();
193  m_dl = dlopen( m_path.c_str(), RTLD_LAZY );
194  if( !m_dl )
195  {
196  throw WLibraryLoadFailed( std::string( "Could not load library \"" + m_path + "\" due to the error: " + dlerror() ) );
197  }
198  }
199 
200  /**
201  * Searches the lib for the specified function symbol and returns it.
202  *
203  * \param name the name of the function
204  *
205  * \return the pointer to the requested function
206  *
207  * \throw WLibraryFetchFailed thrown if the symbol could not be found.
208  */
209  func_ptr_type findFunction( const std::string& name )
210  {
211  return reinterpret_cast< func_ptr_type >( findVariable( name ) );
212  }
213 
214  /**
215  * Searches the lib for the specified symbol and returns it.
216  *
217  * \param name the name of the symbol to search.
218  *
219  * \return pointer to the symbol.
220  *
221  * \throw WLibraryFetchFailed thrown if the symbol could not be found.
222  *
223  */
224  void* findVariable( const std::string& name )
225  {
226  auto_lock lock();
227  dlerror();
228  void* variable_ptr = dlsym( m_dl, name.c_str() );
229  const char *err = dlerror();
230  if( err )
231  {
232  throw WLibraryFetchFailed( std::string( "Could not fetch symbol \"" + name + "\"" + " due to the error: " + err ) );
233  }
234  return variable_ptr;
235  }
236 };
237 #endif
238 
239 WSharedLib::WSharedLib( boost::filesystem::path lib ):
240  m_data( new data( lib.native_file_string() ) )
241 {
242 }
243 
245  m_data( new data( rhs.m_data->m_path ) )
246 {
247 }
248 
250 {
251  delete m_data;
252 }
253 
255 {
256  WSharedLib o( rhs );
257  swap( *this, o );
258  return *this;
259 }
260 
261 void swap( WSharedLib& lhs, WSharedLib& rhs )
262 {
263  std::swap( lhs.m_data, rhs.m_data );
264 }
265 
266 WSharedLib::func_ptr_type WSharedLib::findFunction( const std::string& name ) const
267 {
268  return m_data->findFunction( name );
269 }
270 
271 void* WSharedLib::findVariable( const std::string& name ) const
272 {
273  return m_data->findVariable( name );
274 }
275 
276 #ifdef _MSC_VER
277 // easier this way because VC has problems with quote in command line. So we can not get this information by #define from CMake.
278 // Maybe you have to spend another 500 bucks to have your VC support nearly trivial stuff.
279 std::string WSharedLib::getSystemPrefix()
280 {
281  return "";
282 }
283 
284 std::string WSharedLib::getSystemSuffix()
285 {
286  return ".dll";
287 }
288 #else
290 {
291  return W_LIB_PREFIX;
292 }
293 
295 {
296  return W_LIB_SUFFIX;
297 }
298 #endif
299 
301 {
302  return "../lib";
303 }
304