GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
dynamic-ld.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1993-2024 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU 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 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <iostream>
31 #include <list>
32 
33 #include "file-stat.h"
34 #include "oct-env.h"
35 #include "oct-time.h"
36 
37 #include "defun.h"
38 #include "dynamic-ld.h"
39 #include "interpreter-private.h"
40 #include "interpreter.h"
41 #include "ov-fcn.h"
42 #include "ov-dld-fcn.h"
43 #include "ov-mex-fcn.h"
44 #include "parse.h"
45 #include "unwind-prot.h"
46 #include "utils.h"
47 #include "variables.h"
48 
49 #define STRINGIFY(s) STRINGIFY1(s)
50 #define STRINGIFY1(s) #s
51 
53 
54 void
55 dynamic_loader::shlibs_list::append (const dynamic_library& shl)
56 {
57  m_lib_list.push_back (shl);
58 }
59 
60 std::list<std::string>
61 dynamic_loader::shlibs_list::remove (dynamic_library& shl)
62 {
63  std::list<std::string> removed_fcns;
64 
65  for (auto p = m_lib_list.begin (); p != m_lib_list.end (); p++)
66  {
67  if (*p == shl)
68  {
69  m_lib_list.erase (p);
70 
71  removed_fcns = shl.close ();
72 
73  break;
74  }
75  }
76 
77  return removed_fcns;
78 }
79 
81 dynamic_loader::shlibs_list::find_file (const std::string& file_name) const
82 {
83  dynamic_library retval;
84 
85  for (const auto& lib : m_lib_list)
86  {
87  if (lib.file_name () == file_name)
88  {
89  retval = lib;
90  break;
91  }
92  }
93 
94  return retval;
95 }
96 
97 void
98 dynamic_loader::shlibs_list::display () const
99 {
100  std::cerr << "current shared libraries:" << std::endl;
101  for (const auto& lib : m_lib_list)
102  std::cerr << " " << lib.file_name () << std::endl;
103 }
104 
105 void
106 dynamic_loader::clear_function (const std::string& fcn_name)
107 {
108  warning_with_id ("Octave:reload-forces-clear", " %s", fcn_name.c_str ());
109 
110  // FIXME: is there a way to avoid this? Can we manage the list of
111  // functions that are loaded in the symbol table completely outside
112  // of the dynamic_loader class?
113 
114  symbol_table& symtab = m_interpreter.get_symbol_table ();
115 
116  symtab.clear_dld_function (fcn_name);
117 }
118 
119 void
120 dynamic_loader::clear (dynamic_library& oct_file)
121 {
122  if (oct_file.number_of_functions_loaded () > 1)
123  {
124  warning_with_id ("Octave:reload-forces-clear",
125  "reloading %s clears the following functions:",
126  oct_file.file_name ().c_str ());
127 
128  std::list<std::string> removed_fcns = m_loaded_shlibs.remove (oct_file);
129 
130  for (const auto& fcn_name : removed_fcns)
131  clear_function (fcn_name);
132  }
133  else
134  {
135  std::list<std::string> removed_fcns = m_loaded_shlibs.remove (oct_file);
136 
137  // FIXME: is there a way to avoid this? Can we manage the list
138  // of functions that are loaded in the symbol table completely
139  // outside of the dynamic_loader class?
140 
141  symbol_table& symtab = m_interpreter.get_symbol_table ();
142 
143  for (const auto& fcn_name : removed_fcns)
144  symtab.clear_dld_function (fcn_name);
145  }
146 }
147 
149 dynamic_loader::load_oct (const std::string& fcn_name,
150  const std::string& file_name,
151  bool relative)
152 {
153  octave_function *retval = nullptr;
154 
155  unwind_protect_var<bool> restore_var (m_doing_load, true);
156 
157  dynamic_library oct_file = m_loaded_shlibs.find_file (file_name);
158 
159  if (oct_file && oct_file.is_out_of_date ())
160  clear (oct_file);
161 
162  if (! oct_file)
163  {
164  oct_file.open (file_name);
165 
166  if (oct_file)
167  m_loaded_shlibs.append (oct_file);
168  }
169 
170  if (! oct_file)
171  error ("%s is not a valid shared library", file_name.c_str ());
172 
173  void *function = oct_file.search (fcn_name, name_mangler);
174 
175  if (! function)
176  {
177  // FIXME: can we determine this C mangling scheme
178  // automatically at run time or configure time?
179 
180  function = oct_file.search (fcn_name, name_uscore_mangler);
181  }
182 
183  if (function)
184  {
186  = reinterpret_cast<octave_dld_fcn_getter> (function);
187 
188  retval = f (oct_file, relative);
189 
190  if (! retval)
191  error ("failed to install .oct file function '%s'",
192  fcn_name.c_str ());
193  }
194 
195  return retval;
196 }
197 
198 void *
199 dynamic_loader::try_load_mex (dynamic_library& mex_file,
200  const std::string& fcn_name, bool& have_fmex)
201 {
202  // FCN_NAME is not used here, the mangler functions always return
203  // some form of "mexFunction".
204 
205  have_fmex = false;
206 
207  void *function = mex_file.search (fcn_name, mex_mangler);
208 
209  if (! function)
210  {
211  // FIXME: Can we determine this C mangling scheme
212  // automatically at run time or configure time?
213 
214  function = mex_file.search (fcn_name, mex_uscore_mangler);
215 
216  if (! function)
217  {
218  function = mex_file.search (fcn_name, mex_f77_mangler);
219 
220  if (function)
221  have_fmex = true;
222  }
223  }
224 
225  return function;
226 }
227 
229 dynamic_loader::load_mex (const std::string& fcn_name,
230  const std::string& file_name,
231  bool /*relative*/)
232 {
233  unwind_protect_var<bool> restore_var (m_doing_load, true);
234 
235  dynamic_library mex_file = m_loaded_shlibs.find_file (file_name);
236 
237  if (mex_file && mex_file.is_out_of_date ())
238  clear (mex_file);
239 
240  if (! mex_file)
241  {
242  mex_file.open (file_name);
243 
244  if (mex_file)
245  m_loaded_shlibs.append (mex_file);
246  }
247 
248  if (! mex_file)
249  error ("%s is not a valid shared library", file_name.c_str ());
250 
251  bool have_fmex = false;
252 
253  void *function = try_load_mex (mex_file, fcn_name, have_fmex);
254 
255  if (! function)
256  error ("failed to install .mex file function '%s'", fcn_name.c_str ());
257 
258  void *symbol = mex_file.search ("__mx_has_interleaved_complex__");
259 
260  bool interleaved = symbol != nullptr;
261 
262  return new octave_mex_function (function, interleaved, have_fmex,
263  mex_file, fcn_name);
264 }
265 
266 bool
267 dynamic_loader::remove_oct (const std::string& fcn_name,
268  dynamic_library& shl)
269 {
270  bool retval = false;
271 
272  // We don't need to do anything if this is called because we are in
273  // the process of reloading a .oct file that has changed.
274 
275  if (! m_doing_load)
276  {
277  retval = shl.remove (fcn_name);
278 
279  if (shl.number_of_functions_loaded () == 0)
280  m_loaded_shlibs.remove (shl);
281  }
282 
283  return retval;
284 }
285 
286 bool
287 dynamic_loader::remove_mex (const std::string& fcn_name,
288  dynamic_library& shl)
289 {
290  // Use the same procedure as for oct files.
291  return remove_oct (fcn_name, shl);
292 }
293 
294 std::string
295 dynamic_loader::name_mangler (const std::string& name)
296 {
297  return 'G' + name;
298 }
299 
300 std::string
301 dynamic_loader::name_uscore_mangler (const std::string& name)
302 {
303  return "_G" + name;
304 }
305 
306 std::string
307 dynamic_loader::mex_mangler (const std::string&)
308 {
309  return "mexFunction";
310 }
311 
312 std::string
313 dynamic_loader::mex_uscore_mangler (const std::string&)
314 {
315  return "_mexFunction";
316 }
317 
318 std::string
319 dynamic_loader::mex_f77_mangler (const std::string&)
320 {
321  return STRINGIFY (F77_FUNC (mexfunction, MEXFUNCTION));
322 }
323 
324 OCTAVE_END_NAMESPACE(octave)
void * search(const std::string &nm, const name_mangler &mangler=name_mangler()) const
Definition: oct-shlib.h:179
void open(const std::string &f)
Definition: oct-shlib.h:165
std::string file_name() const
Definition: oct-shlib.h:201
std::list< std::string > close()
Definition: oct-shlib.h:168
bool is_out_of_date() const
Definition: oct-shlib.h:198
std::size_t number_of_functions_loaded() const
Definition: oct-shlib.h:195
bool remove(const std::string &name)
Definition: oct-shlib.h:192
bool remove_oct(const std::string &fcn_name, dynamic_library &shl)
Definition: dynamic-ld.cc:267
bool remove_mex(const std::string &fcn_name, dynamic_library &shl)
Definition: dynamic-ld.cc:287
octave_function * load_oct(const std::string &fcn_name, const std::string &file_name="", bool relative=false)
Definition: dynamic-ld.cc:149
octave_function * load_mex(const std::string &fcn_name, const std::string &file_name="", bool relative=false)
Definition: dynamic-ld.cc:229
symbol_table & get_symbol_table()
Definition: interpreter.h:298
void clear_dld_function(const std::string &name)
Definition: symtab.cc:501
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
octave_function *(* octave_dld_fcn_getter)(const octave::dynamic_library &, bool relative)
Definition: defun-int.h:183
#define STRINGIFY(s)
Definition: dynamic-ld.cc:49
void warning_with_id(const char *id, const char *fmt,...)
Definition: error.cc:1078
void() error(const char *fmt,...)
Definition: error.cc:988
F77_RET_T const F77_DBLE const F77_DBLE * f
F77_RET_T F77_FUNC(xerbla, XERBLA)(F77_CONST_CHAR_ARG_DEF(s_arg