GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
oct-shlib.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1999-2017 John W. Eaton
4 Copyright (C) 2009 VZLU Prague
5 
6 This file is part of Octave.
7 
8 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <http://www.gnu.org/licenses/>.
21 
22 */
23 
24 #if defined (HAVE_CONFIG_H)
25 # include "config.h"
26 #endif
27 
28 #include <map>
29 
30 #if defined (HAVE_SHL_LOAD_API)
31 # include <cerrno>
32 # include <cstring>
33 #endif
34 
35 #if defined (HAVE_DYLD_API)
36 # include <mach-o/dyld.h>
37 #endif
38 
39 extern "C"
40 {
41 #if defined (HAVE_DLOPEN_API)
42 # if defined (HAVE_DLFCN_H)
43 # include <dlfcn.h>
44 # else
45 extern void *dlopen (const char *, int);
46 extern const char *dlerror (void);
47 extern void *dlsym (void *, const char *);
48 extern int dlclose (void *);
49 # endif
50 #elif defined (HAVE_SHL_LOAD_API)
51 # include <dl.h>
52 #elif defined (HAVE_LOADLIBRARY_API)
53 # define WIN32_LEAN_AND_MEAN 1
54 # include <windows.h>
55 #endif
56 }
57 
58 #include "file-ops.h"
59 #include "file-stat.h"
60 #include "lo-error.h"
61 #include "oct-shlib.h"
62 #include "str-vec.h"
63 
64 namespace octave
65 {
67  : count (1), file (f), tm_loaded (), fcn_names ()
68  {
69  instances[f] = this;
70 
71  if (is_out_of_date ())
72  (*current_liboctave_warning_with_id_handler)
73  ("Octave:warn-future-time-stamp",
74  "timestamp on file %s is in the future", file.c_str ());
75  }
76 
77  bool
79  {
81  return (fs && fs.is_newer (tm_loaded));
82  }
83 
84  void
86  {
87  // We can't actually reload the library, but we'll pretend we did.
89  if (fs && fs.is_newer (tm_loaded))
90  {
91  tm_loaded = fs.mtime ();
92 
93  (*current_liboctave_warning_with_id_handler)
94  ("Octave:library-reload",
95  "library %s not reloaded due to existing references", file.c_str ());
96  }
97  }
98 
101  {
102  dynlib_rep *retval = 0;
103  std::map<std::string, dynlib_rep *>::iterator p = instances.find (f);
104  if (p != instances.end ())
105  {
106  retval = p->second;
107  retval->count++;
108  if (fake)
109  retval->fake_reload ();
110  }
111  else
112  retval = new_instance (f);
113 
114  return retval;
115  }
116 
117  void
119  {
120  auto p = fcn_names.find (name);
121 
122  if (p == fcn_names.end ())
123  fcn_names[name] = 1;
124  else
125  ++(p->second);
126  }
127 
128  bool
130  {
131  bool retval = false;
132 
133  auto p = fcn_names.find (fcn_name);
134 
135  if (p != fcn_names.end () && --(p->second) == 0)
136  {
137  fcn_names.erase (fcn_name);
138  retval = true;
139  }
140 
141  return retval;
142  }
143 
144  void
146  {
147  for (auto& fcn_sz_p : fcn_names)
148  cl_hook (fcn_sz_p.first);
149 
150  fcn_names.clear ();
151  }
152 
153  std::map<std::string, dynamic_library::dynlib_rep *>
155 
157 
158 #if defined (HAVE_DLOPEN_API)
159 
160  class
161  octave_dlopen_shlib : public dynamic_library::dynlib_rep
162  {
163  public:
164 
165  octave_dlopen_shlib (const std::string& f);
166 
167  ~octave_dlopen_shlib (void);
168 
169  void *search (const std::string& name,
170  dynamic_library::name_mangler mangler = 0);
171 
172  // FIXME: this is possibly redundant because failure to open a library will
173  // normally throw an exception, avoiding the construction of an invalid
174  // library. Leave it here for possible future use.
175 
176  bool is_open (void) const { return (library != 0); }
177 
178  private:
179 
180  // No copying!
181 
182  octave_dlopen_shlib (const octave_dlopen_shlib&);
183 
184  octave_dlopen_shlib& operator = (const octave_dlopen_shlib&);
185 
186  void *library;
187  };
188 
189  octave_dlopen_shlib::octave_dlopen_shlib (const std::string& f)
190  : dynamic_library::dynlib_rep (f), library (0)
191  {
192  int flags = 0;
193 
194  // Use RTLD_NOW to resolve all symbols before dlopen returns.
195  // By using this option, dlopen will detect errors and Octave
196  // won't exit if there are unresolved symbols in the file we are
197  // loading, and we may even get a useful diagnostic.
198 # if defined (RTLD_NOW)
199  flags |= RTLD_NOW;
200 # endif
201 
202  // Use RTLD_GLOBAL to export symbols from loaded objects so they are
203  // available to other subsequently loaded libraries.
204 # if defined (RTLD_GLOBAL)
205  flags |= RTLD_GLOBAL;
206 # endif
207 
208  library = dlopen (file.c_str (), flags);
209 
210  if (! library)
211  {
212  const char *msg = dlerror ();
213 
214  if (msg)
215  (*current_liboctave_error_handler) ("%s: failed to load: %s",
216  file.c_str (), msg);
217  else
218  (*current_liboctave_error_handler) ("%s: failed to load",
219  file.c_str ());
220  }
221  }
222 
223  octave_dlopen_shlib::~octave_dlopen_shlib (void)
224  {
225  if (library)
226  dlclose (library);
227  }
228 
229  void *
232  {
233  void *function = 0;
234 
235  if (! is_open ())
236  (*current_liboctave_error_handler)
237  ("shared library %s is not open", file.c_str ());
238 
239  std::string sym_name = name;
240 
241  if (mangler)
242  sym_name = mangler (name);
243 
244  function = dlsym (library, sym_name.c_str ());
245 
246  return function;
247  }
248 
249 #elif defined (HAVE_SHL_LOAD_API)
250 
251  class
252  octave_shl_load_shlib : public dynamic_library::dynlib_rep
253  {
254  public:
255 
256  octave_shl_load_shlib (const std::string& f);
257 
258  ~octave_shl_load_shlib (void);
259 
260  void *search (const std::string& name,
261  dynamic_library::name_mangler mangler = 0);
262 
263  bool is_open (void) const { return (library != 0); }
264 
265  private:
266 
267  // No copying!
268 
269  octave_shl_load_shlib (const octave_shl_load_shlib&);
270 
271  octave_shl_load_shlib& operator = (const octave_shl_load_shlib&);
272 
273  shl_t library;
274  };
275 
276  octave_shl_load_shlib::octave_shl_load_shlib (const std::string& f)
277  : dynamic_library::dynlib_rep (f), library (0)
278  {
279  file = f;
280 
281  library = shl_load (file.c_str (), BIND_IMMEDIATE, 0L);
282 
283  if (! library)
284  {
285  using namespace std; // FIXME: Why have this line?
286  (*current_liboctave_error_handler) ("%s", std::strerror (errno));
287  }
288  }
289 
290  octave_shl_load_shlib::~octave_shl_load_shlib (void)
291  {
292  if (library)
293  shl_unload (library);
294  }
295 
296  void *
299  {
300  void *function = 0;
301 
302  if (! is_open ())
303  (*current_liboctave_error_handler)
304  ("shared library %s is not open", file.c_str ());
305 
306  std::string sym_name = name;
307 
308  if (mangler)
309  sym_name = mangler (name);
310 
311  int status = shl_findsym (&library, sym_name.c_str (),
312  TYPE_UNDEFINED, &function);
313 
314  return function;
315  }
316 
317 #elif defined (HAVE_LOADLIBRARY_API)
318 
319  class
320  octave_w32_shlib: public dynamic_library::dynlib_rep
321  {
322  public:
323 
324  octave_w32_shlib (const std::string& f);
325 
326  ~octave_w32_shlib (void);
327 
328  void *search (const std::string& name,
329  dynamic_library::name_mangler mangler = 0);
330 
331  bool is_open (void) const { return (handle != 0); }
332 
333  private:
334 
335  // No copying!
336 
337  octave_w32_shlib (const octave_w32_shlib&);
338 
339  octave_w32_shlib& operator = (const octave_w32_shlib&);
340 
341  HINSTANCE handle;
342  };
343 
344  static void
345  set_dll_directory (const std::string& dir = "")
346  {
347  SetDllDirectory (dir.empty () ? 0 : dir.c_str ());
348  }
349 
350  octave_w32_shlib::octave_w32_shlib (const std::string& f)
351  : dynamic_library::dynlib_rep (f), handle (0)
352  {
354 
355  set_dll_directory (dir);
356 
357  handle = LoadLibrary (file.c_str ());
358 
359  set_dll_directory ();
360 
361  if (! handle)
362  {
363  DWORD lastError = GetLastError ();
364  const char *msg;
365 
366  switch (lastError)
367  {
368  case ERROR_MOD_NOT_FOUND:
369  case ERROR_DLL_NOT_FOUND:
370  msg = "could not find library or dependencies";
371  break;
372 
373  case ERROR_INVALID_DLL:
374  msg = "library or its dependencies are damaged";
375  break;
376 
377  case ERROR_DLL_INIT_FAILED:
378  msg = "library initialization routine failed";
379  break;
380 
381  default:
382  msg = "library open failed";
383  }
384 
385  (*current_liboctave_error_handler) ("%s: %s", msg, file.c_str ());
386  }
387  }
388 
389  octave_w32_shlib::~octave_w32_shlib (void)
390  {
391  if (handle)
392  FreeLibrary (handle);
393  }
394 
395  void *
398  {
399  void *function = 0;
400 
401  if (! is_open ())
402  (*current_liboctave_error_handler)
403  ("shared library %s is not open", file.c_str ());
404 
405  std::string sym_name = name;
406 
407  if (mangler)
408  sym_name = mangler (name);
409 
410  function = reinterpret_cast<void *> (GetProcAddress (handle,
411  sym_name.c_str ()));
412 
413  return function;
414  }
415 
416 #elif defined (HAVE_DYLD_API)
417 
418  class
419  octave_dyld_shlib : public dynamic_library::dynlib_rep
420  {
421  public:
422 
423  octave_dyld_shlib (void);
424 
425  ~octave_dyld_shlib (void);
426 
427  void open (const std::string& f);
428 
429  void *search (const std::string& name,
430  dynamic_library::name_mangler mangler = 0);
431 
432  void close (dynamic_library::close_hook cl_hook = 0);
433 
434  bool is_open (void) const {return (handle != 0); }
435 
436  private:
437 
438  // No copying!
439 
440  octave_dyld_shlib (const octave_dyld_shlib&);
441 
442  octave_dyld_shlib& operator = (const octave_dyld_shlib&);
443 
444  NSObjectFileImage img;
445  NSModule handle;
446  };
447 
448  octave_dyld_shlib::octave_dyld_shlib (const std::string& f)
449  : dynamic_library::dynlib_rep (f), handle (0)
450  {
451  int returnCode = NSCreateObjectFileImageFromFile (file.c_str (), &img);
452 
453  if (NSObjectFileImageSuccess != returnCode)
454  {
455  (*current_liboctave_error_handler)
456  ("got NSObjectFileImageReturnCode %d", returnCode);
457 
458  // FIXME: should use NSLinkEditError () to get
459  // more info on what went wrong.
460  }
461 
462  handle = NSLinkModule (img, file.c_str (),
463  (NSLINKMODULE_OPTION_RETURN_ON_ERROR
464  | NSLINKMODULE_OPTION_PRIVATE));
465  if (! handle)
466  {
467  NSLinkEditErrors ler;
468  int lerno;
469  const char *file2;
470  const char *errstr = 0;
471 
472  NSLinkEditError (&ler, &lerno, &file2, &errstr);
473 
474  if (! errstr)
475  errstr = "unspecified error";
476 
477  (*current_liboctave_error_handler) ("%s: %s", file.c_str (), errstr);
478  }
479  }
480 
481  octave_dyld_shlib::~octave_dyld_shlib (void)
482  {
483  if (handle)
484  NSUnLinkModule (handle, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES);
485 
486  NSDestroyObjectFileImage (img);
487  }
488 
489  void *
492  {
493  void *function = 0;
494 
495  if (! is_open ())
496  (*current_liboctave_error_handler)
497  ("bundle %s is not open", file.c_str ());
498 
499  std::string sym_name = name;
500 
501  if (mangler)
502  sym_name = mangler (name);
503 
504  NSSymbol symbol = NSLookupSymbolInModule (handle, sym_name.c_str ());
505 
506  if (symbol)
507  {
508  function = NSAddressOfSymbol (symbol);
509  }
510 
511  return function;
512  }
513 
514 #endif
515 
516  dynamic_library::dynlib_rep *
518  {
519 #if defined (HAVE_DLOPEN_API)
520  return new octave_dlopen_shlib (f);
521 #elif defined (HAVE_SHL_LOAD_API)
522  return new octave_shl_load_shlib (f);
523 #elif defined (HAVE_LOADLIBRARY_API)
524  return new octave_w32_shlib (f);
525 #elif defined (HAVE_DYLD_API)
526  return new octave_dyld_shlib (f);
527 #else
528  (*current_liboctave_error_handler)
529  ("support for dynamically loaded libraries was unavailable or disabled when liboctave was built");
530 #endif
531  }
532 }
virtual bool is_open(void) const
Definition: oct-shlib.h:64
virtual void * search(const std::string &, name_mangler=0)
Definition: oct-shlib.h:67
Octave interface to the compression and uncompression libraries.
Definition: aepbalance.cc:47
For example cd octave end example noindent changes the current working directory to file
Definition: dirfns.cc:120
static std::string dirname(const std::string &path)
Definition: file-ops.h:105
octave::sys::time mtime(void) const
Definition: file-stat.h:128
void do_close_hook(close_hook cl_hook)
Definition: oct-shlib.cc:145
void * search(const std::string &nm, name_mangler mangler=0) const
Definition: oct-shlib.h:164
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE const F77_DBLE * f
OCTAVE_NORETURN liboctave_error_handler current_liboctave_error_handler
Definition: lo-error.c:38
static std::map< std::string, dynlib_rep * > instances
Definition: oct-shlib.h:108
STL namespace.
bool is_newer(const octave::sys::time &time) const
Definition: file-stat.h:149
void add_fcn_name(const std::string &)
Definition: oct-shlib.cc:118
OCTAVE_EXPORT octave_value_list any number nd example oindent prints the prompt xample Pick a any number!nd example oindent and waits for the user to enter a value The string entered by the user is evaluated as an so it may be a literal a variable name
Definition: input.cc:871
bool is_out_of_date(void) const
Definition: oct-shlib.cc:78
void(* close_hook)(const std::string &)
Definition: oct-shlib.h:44
octave_refcount< int > count
Definition: oct-shlib.h:93
octave_value retval
Definition: data.cc:6294
static std::list< std::string > search(const std::string &path, const std::string &original_name, bool all)
Definition: kpse.cc:395
static dynlib_rep nil_rep
Definition: oct-shlib.h:113
p
Definition: lu.cc:138
void open(const std::string &f)
Definition: oct-shlib.h:153
octave::sys::file_stat fs(filename)
void close(close_hook cl_hook=0)
Definition: oct-shlib.h:156
bool remove_fcn_name(const std::string &)
Definition: oct-shlib.cc:129
static dynlib_rep * get_instance(const std::string &f, bool fake)
Definition: oct-shlib.cc:100
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:854
std::string(* name_mangler)(const std::string &)
Definition: oct-shlib.h:43
dynamic_library & operator=(const dynamic_library &sl)
Definition: oct-shlib.h:134
static dynlib_rep * new_instance(const std::string &f)
Definition: oct-shlib.cc:517