Library.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 National Institute For Space Research (INPE) - Brazil.
3 
4  This file is part of the TerraLib - a Framework for building GIS enabled applications.
5 
6  TerraLib is free software: you can redistribute it and/or modify
7  it under the terms of the GNU Lesser General Public License as published by
8  the Free Software Foundation, either version 3 of the License,
9  or (at your option) any later version.
10 
11  TerraLib is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public License
17  along with TerraLib. See COPYING. If not, write to
18  TerraLib Team at <terralib-team@terralib.org>.
19  */
20 
21 /*!
22  \file terralib/core/lib/Library.cpp
23 
24  \brief A class for handling shared libraries.
25 
26  \author Gilberto Ribeiro de Queiroz
27  */
28 
29 // TerraLib
30 #include "Library.h"
31 #include "../../Defines.h"
32 #include "Exception.h"
33 #include "../translator/Translator.h"
34 
35 #ifndef TE_PLATFORM
36 #error "Could not determine platform! Please, contact TerraLib team (terralib-team@terralib.org) for helping support this platform!"
37 #endif
38 
39 // STL
40 #include <cassert>
41 #include <algorithm>
42 #include <cctype>
43 
44 // Boost
45 #include <boost/format.hpp>
46 
47 #if TE_PLATFORM == TE_PLATFORMCODE_MSWINDOWS
48 #include <windows.h>
49 #elif (TE_PLATFORM == TE_PLATFORMCODE_LINUX) || (TE_PLATFORM == TE_PLATFORMCODE_APPLE)
50 #include <cstdlib>
51 #include <dlfcn.h>
52 #else
53 #error "Platform not supported! Please, contact TerraLib team (terralib-team@terralib.org) for helping support this platform!"
54 #endif
55 
57 {
58  std::string slib_file_name; //!< The shared library file name.
59  void* module; //!< The handle for a DLLs, SO or a DyLib.
60 
61 #if defined(TE_PLATFORM) && (TE_PLATFORM == TE_PLATFORMCODE_MSWINDOWS)
62  static bool added_search_path_; //!< This flag is very important for Windows because some routines in its API returns 0 with two meanings: error or empty, but there is no way to know which one is right!
63 #endif
64 
65  Impl(const std::string& slib_file_name);
66 };
67 
68 #if (TE_PLATFORM == TE_PLATFORMCODE_MSWINDOWS)
69 bool te::core::Library::Impl::added_search_path_(false);
70 #endif
71 
73  : slib_file_name(slib_file_name),
74  module(nullptr)
75 {
76 }
77 
78 static std::string te_get_os_error()
79 {
80 #if (TE_PLATFORM == TE_PLATFORMCODE_MSWINDOWS)
81 
82  DWORD dw_message_id = ::GetLastError();
83 
84  LPVOID lp_msg_buf = 0;
85 
86  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
87  NULL,
88  dw_message_id,
89  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
90  (LPTSTR) &lp_msg_buf,
91  0,
92  NULL);
93 
94  if(lp_msg_buf == 0)
95  return std::string(TE_TR("Shared Library: could not determine the Operational System report error!"));
96 
97  std::string msg((char*)(lp_msg_buf));
98 
99  LocalFree(lp_msg_buf);
100 
101  return msg;
102 
103 #elif (TE_PLATFORM == TE_PLATFORMCODE_LINUX) || (TE_PLATFORM == TE_PLATFORMCODE_APPLE)
104 
105  const char* err_msg = dlerror();
106 
107  return (err_msg == nullptr) ? std::string(TE_TR("Shared Library: could not determine the Operational System report error!")) : std::string(err_msg);
108 
109 #else
110 
111  #error "Platform not supported! Please, contact TerraLib team (terralib-team@terralib.org) for helping support this platform!"
112 
113 #endif
114 }
115 
116 te::core::Library::Library(const std::string& slib_file_name, const bool& delay_load)
117  : m_pimpl(nullptr)
118 {
119  if(slib_file_name.empty() || std::all_of(slib_file_name.begin(), slib_file_name.end(), isspace))
120  {
121  boost::format err_msg(TE_TR("Library name cannot be empty."));
122 
123  throw LibraryNameException() << te::ErrorDescription(err_msg.str());
124  }
125 
126  m_pimpl = new Impl(slib_file_name);
127 
128  if(delay_load)
129  return;
130 
131  load();
132 }
133 
135 {
136 #ifdef NDEBUG
137  try
138  {
139 #endif
140  unload();
141 #ifdef NDEBUG
142  }
143  catch(...)
144  {
145  }
146 #endif
147 
148  delete m_pimpl;
149 }
150 
151 void
153 {
154  if(isLoaded())
155  return;
156 
157 #if (TE_PLATFORM == TE_PLATFORMCODE_MSWINDOWS)
158 
159  m_pimpl->module = (void*)LoadLibraryA(m_pimpl->slib_file_name.c_str());
160 
161 #elif (TE_PLATFORM == TE_PLATFORMCODE_LINUX) || (TE_PLATFORM == TE_PLATFORMCODE_APPLE)
162 
163  m_pimpl->module = dlopen(m_pimpl->slib_file_name.c_str(), RTLD_NOW);
164 
165 #else
166 
167  #error "Platform not supported! Please, contact TerraLib team (terralib-team@terralib.org) for helping support this platform!"
168 
169 #endif
170 
171  if(!isLoaded())
172  {
173  boost::format err_msg(TE_TR("Could not load library: %1%, due to following error: %2%."));
174 
176  }
177 }
178 
179 void
181 {
182  if(!isLoaded())
183  return;
184 
185 #if (TE_PLATFORM == TE_PLATFORMCODE_MSWINDOWS)
186 
187  BOOL result = FreeLibrary((HMODULE)m_pimpl->module);
188 
189  if(result == FALSE)
190  {
191  boost::format err_msg(TE_TR("Could not unload library: %1%, due to following error: %2%."));
192 
194  }
195 
196 #elif (TE_PLATFORM == TE_PLATFORMCODE_LINUX) || (TE_PLATFORM == TE_PLATFORMCODE_APPLE)
197 
198  if(dlclose(m_pimpl->module))
199  {
200  boost::format err_msg(TE_TR("Could not unload library: %1%, due to following error: %2%."));
201 
203  }
204 
205 #else
206 
207  #error "Platform not supported! Please, contact TerraLib team (terralib-team@terralib.org) for helping support this platform!"
208 
209 #endif
210 
211  m_pimpl->module = nullptr;
212 }
213 
214 bool
216 {
217  return (m_pimpl != nullptr) && (m_pimpl->module != nullptr);
218 }
219 
220 const std::string&
222 {
223  return m_pimpl->slib_file_name;
224 }
225 
226 void*
227 te::core::Library::getAddress(const char* symbol) const
228 {
229  assert(symbol);
230 
231 #if (TE_PLATFORM == TE_PLATFORMCODE_MSWINDOWS)
232 
233  void* f = GetProcAddress((HINSTANCE)m_pimpl->module, symbol);
234 
235 #elif (TE_PLATFORM == TE_PLATFORMCODE_LINUX) || (TE_PLATFORM == TE_PLATFORMCODE_APPLE)
236 
237  void* f = dlsym(m_pimpl->module, symbol);
238 
239 #else
240 
241  #error "Platform not supported! Please, contact TerraLib team (terralib-team@terralib.org) for helping support this platform!"
242 
243 #endif
244 
245  if(f == nullptr)
246  {
247  boost::format err_msg(TE_TR("Could not find symbol: %1%, in the library %2%, due to the following error: %3%."));
248 
250  }
251 
252  return f;
253 }
254 
255 std::string
256 te::core::Library::getNativeName(const std::string& name)
257 {
258 #if TE_PLATFORM == TE_PLATFORMCODE_MSWINDOWS
259 #ifdef NDEBUG
260  std::string nativeName = name + ".dll";
261 #else
262  std::string nativeName = name + "d.dll";
263 #endif
264 
265 #elif TE_PLATFORM == TE_PLATFORMCODE_LINUX
266  std::string nativeName = "lib" + name + ".so";
267 
268 #elif TE_PLATFORM == TE_PLATFORMCODE_APPLE
269  std::string nativeName = "lib" + name + ".dylib";
270 
271 #else
272 #error "Platform not supported! Please, contact the TerraLib team (terralib-team@dpi.inpe.br) for helping support this platform!"
273 #endif
274 
275  return nativeName;
276 }
277 
278 #if (TE_PLATFORM == TE_PLATFORMCODE_MSWINDOWS)
279 void te::core::Library::addSearchDir(const std::string& dir_name)
280 {
281 
282  if(dir_name.length() > (MAX_PATH - 2))
283  {
284  boost::format err_msg(TE_TR("The DLL lookup path is too long: %1%."));
285 
286  throw LibraryInvalidSearchPathException() << te::ErrorDescription((err_msg % dir_name).str());
287  }
288 
289 // add dir to the path of LoadLibrary
290  BOOL retval = SetDllDirectory(dir_name.c_str());
291 
292  if(retval == FALSE)
293  {
294  boost::format err_msg(TE_TR("The informed dir \"%1%\" couldn't be added to the application dll lookup path due to the following error: \"%2%\"."));
295 
296  throw te::core::LibraryInvalidSearchPathException() << te::ErrorDescription((err_msg % dir_name % te_get_os_error()).str());
297  }
298 
299  te::core::Library::Impl::added_search_path_ = true;
300 }
301 #endif
302 
303 void
305 {
306 #if TE_PLATFORM == TE_PLATFORMCODE_MSWINDOWS
307 
308 // come back with default Windows path
309  BOOL retval = SetDllDirectory("");
310 
311  if(retval == FALSE)
312  {
313  boost::format err_msg(TE_TR("Couldn't come back with default Windows DLL lookup path due to the following error: %1%."));
314 
316  }
317 
318  te::core::Library::Impl::added_search_path_ = false;
319 #endif
320 }
321 
322 std::string
324 {
325 #if TE_PLATFORM == TE_PLATFORMCODE_MSWINDOWS
326 
327  const DWORD buff_size = 32768;
328 
329  char buff[buff_size];
330 
331  DWORD length = GetDllDirectory(buff_size, buff);
332 
333  if(length == 0 && te::core::Library::Impl::added_search_path_)
334  {
335  boost::format err_msg(TE_TR("Couldn't get Windows DLL lookup path due to the following error: %1%!"));
336 
337  throw LibrarySearchPathException() << te::ErrorDescription((err_msg % te_get_os_error()).str());
338  }
339 
340  if(length <= buff_size)
341  {
342  return std::string(buff, length);
343  }
344  else
345  {
346  throw LibrarySearchPathException() << te::ErrorDescription(TE_TR("Windows DLL lookup path too long!"));
347  }
348 
349 #elif (TE_PLATFORM == TE_PLATFORMCODE_LINUX) || (TE_PLATFORM == TE_PLATFORMCODE_APPLE)
350 
351 #if (TE_PLATFORM == TE_PLATFORMCODE_LINUX)
352  const char* ldLibraryPath = getenv("LD_LIBRARY_PATH");
353 #else
354  const char* ldLibraryPath = getenv("DYLD_LIBRARY_PATH");
355 #endif
356 
357  return (ldLibraryPath == nullptr) ? std::string("") : std::string(ldLibraryPath);
358 
359 #else
360 
361  #error "Platform not supported! Please, contact TerraLib team (terralib-team@terralib.org) for helping support this platform!"
362 
363 #endif
364 }
365 
An exception indicating the operational system search library path was not found. ...
An exception indicating an error when reseting the operational system search library path...
A class for handling shared libraries.
An exception indicating an error when loading a shared library.
An exception indicating an error when releasing a shared library.
Impl * m_pimpl
Definition: Library.h:173
std::string slib_file_name
The shared library file name.
Definition: Library.cpp:58
Specific exception types for Library Manager.
static void addSearchDir(const std::string &dir_name)
Add the informed dir to the path used by the operational system to lookup for shared libraries...
Definition: Library.cpp:279
void unload()
Force the unload of the shared library from memory.
Definition: Library.cpp:180
#define TE_TR(message)
It marks a string in order to get translated.
Definition: Translator.h:242
boost::error_info< struct tag_error_description, std::string > ErrorDescription
The base type for error report messages.
static std::string getSearchPath()
Returns the system lookup path.
Definition: Library.cpp:323
~Library()
The destructor automatically unloads from memory the shared library if it was not unloaded explicitly...
Definition: Library.cpp:134
static void resetSearchPath()
Comes back the application lookup path to the original state, before any add_search_dir has been call...
Definition: Library.cpp:304
void * getAddress(const char *symbol) const
Return the address where the given symbol is loaded into memory.
Definition: Library.cpp:227
Library(const std::string &slib_file_name, const bool &delay_load=false)
Load a new shared library.
Definition: Library.cpp:116
TECOMMONEXPORT const std::string GetLastError()
It obtains the last thread&#39;s error message in a Windows System.
Definition: WinUtils.cpp:34
Impl(const std::string &slib_file_name)
Definition: Library.cpp:72
const std::string & getFileName() const
Return the shared library file name as informed in the constructor.
Definition: Library.cpp:221
void * module
The handle for a DLLs, SO or a DyLib.
Definition: Library.cpp:59
An exception indicating an error when adding a given path to the operational system search library pa...
An exception indicating an error when searching for a given symbol in a shared library.
static std::string te_get_os_error()
Definition: Library.cpp:78
bool isLoaded() const
Return true if the shared library is loaded otherwise return false.
Definition: Library.cpp:215
void load()
Load the shared library to memory.
Definition: Library.cpp:152
static std::string getNativeName(const std::string &name)
Given a shared library name without file extensions, prefixes and nor suffixes it will construct a li...
Definition: Library.cpp:256
An execption indicating an error when the library name is empty.