DynamicLoader.cxx 11.3 KB
Newer Older
1 2
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
3 4 5 6 7 8 9 10
#include "kwsysPrivate.h"
#include KWSYS_HEADER(DynamicLoader.hxx)

#include KWSYS_HEADER(Configure.hxx)

// Work-around CMake dependency scanning limitation.  This must
// duplicate the above list of headers.
#if 0
11 12
#  include "Configure.hxx.in"
#  include "DynamicLoader.hxx.in"
13 14
#endif

15
// This file actually contains several different implementations:
16
// * NOOP for environments without dynamic libs
17 18 19 20 21 22 23 24 25
// * HP machines which uses shl_load
// * Mac OS X 10.2.x and earlier which uses NSLinkModule
// * Windows which uses LoadLibrary
// * BeOS / Haiku
// * FreeMiNT for Atari
// * Default implementation for *NIX systems (including Mac OS X 10.3 and
//   later) which use dlopen
//
// Each part of the ifdef contains a complete implementation for
Mathieu Malaterre's avatar
Mathieu Malaterre committed
26
// the static methods of DynamicLoader.
27

28 29
#if !KWSYS_SUPPORTS_SHARED_LIBS
// Implementation for environments without dynamic libs
30
#  include <string.h> // for strerror()
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62

namespace KWSYS_NAMESPACE {

DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  const std::string& libname)
{
  return 0;
}

int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
{
  if (!lib) {
    return 0;
  }

  return 1;
}

DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
  DynamicLoader::LibraryHandle lib, const std::string& sym)
{
  return 0;
}

const char* DynamicLoader::LastError()
{
  return "General error";
}

} // namespace KWSYS_NAMESPACE

#elif defined(__hpux)
63
// Implementation for HPUX machines
64 65
#  include <dl.h>
#  include <errno.h>
66

67
namespace KWSYS_NAMESPACE {
68

69 70
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  const std::string& libname)
71
{
72
  return shl_load(libname.c_str(), BIND_DEFERRED | DYNAMIC_PATH, 0L);
73 74
}

75
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
76
{
77
  if (!lib) {
78
    return 0;
79
  }
80 81 82
  return !shl_unload(lib);
}

83 84
DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
  DynamicLoader::LibraryHandle lib, const std::string& sym)
85
{
86 87
  void* addr;
  int status;
88

89
  /* TYPE_PROCEDURE Look for a function or procedure. (This used to be default)
90 91
   * TYPE_DATA      Look for a symbol in the data segment (for example,
   * variables).
92 93
   * TYPE_UNDEFINED Look for any symbol.
   */
94
  status = shl_findsym(&lib, sym.c_str(), TYPE_UNDEFINED, &addr);
95
  void* result = (status < 0) ? (void*)0 : addr;
96

97
  // Hack to cast pointer-to-data to pointer-to-function.
98
  return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
99 100 101 102 103
}

const char* DynamicLoader::LastError()
{
  // TODO: Need implementation with errno/strerror
104 105 106
  /* If successful, shl_findsym returns an integer (int) value zero. If
   * shl_findsym cannot find sym, it returns -1 and sets errno to zero.
   * If any other errors occur, shl_findsym returns -1 and sets errno to one
107 108 109 110 111 112 113 114 115
   * of these values (defined in <errno.h>):
   * ENOEXEC
   * A format error was detected in the specified library.
   * ENOSYM
   * A symbol on which sym depends could not be found.
   * EINVAL
   * The specified handle is invalid.
   */

116
  if (errno == ENOEXEC || errno == ENOSYM || errno == EINVAL) {
117
    return strerror(errno);
118
  }
119
  // else
120 121 122 123 124
  return 0;
}

} // namespace KWSYS_NAMESPACE

125 126
#elif defined(__APPLE__) && (MAC_OS_X_VERSION_MAX_ALLOWED < 1030)
// Implementation for Mac OS X 10.2.x and earlier
127 128
#  include <mach-o/dyld.h>
#  include <string.h> // for strlen
129

130
namespace KWSYS_NAMESPACE {
131

132 133
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  const std::string& libname)
134 135 136
{
  NSObjectFileImageReturnCode rc;
  NSObjectFileImage image = 0;
137

138
  rc = NSCreateObjectFileImageFromFile(libname.c_str(), &image);
139
  // rc == NSObjectFileImageInappropriateFile when trying to load a dylib file
140
  if (rc != NSObjectFileImageSuccess) {
141
    return 0;
142
  }
143 144 145
  NSModule handle = NSLinkModule(image, libname.c_str(),
                                 NSLINKMODULE_OPTION_BINDNOW |
                                   NSLINKMODULE_OPTION_RETURN_ON_ERROR);
146 147
  NSDestroyObjectFileImage(image);
  return handle;
148 149
}

150
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
151
{
152 153 154
  // NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED
  // With  this  option  the memory for the module is not deallocated
  // allowing pointers into the module to still be valid.
155 156 157
  // You should use this option instead if your code experience some problems
  // reported against Panther 10.3.9 (fixed in Tiger 10.4.2 and up)
  bool success = NSUnLinkModule(lib, NSUNLINKMODULE_OPTION_NONE);
158 159 160
  return success;
}

161
DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
Brad King's avatar
Brad King committed
162
  DynamicLoader::LibraryHandle lib, const std::string& sym)
163
{
164
  void* result = 0;
165
  // Need to prepend symbols with '_' on Apple-gcc compilers
166
  std::string rsym = '_' + sym;
167

168
  NSSymbol symbol = NSLookupSymbolInModule(lib, rsym.c_str());
169
  if (symbol) {
170
    result = NSAddressOfSymbol(symbol);
171
  }
172

173
  // Hack to cast pointer-to-data to pointer-to-function.
174
  return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
175 176 177 178 179 180 181 182 183
}

const char* DynamicLoader::LastError()
{
  return 0;
}

} // namespace KWSYS_NAMESPACE

184 185
#elif defined(_WIN32) && !defined(__CYGWIN__)
// Implementation for Windows win32 code but not cygwin
186
#  include <windows.h>
187

188
namespace KWSYS_NAMESPACE {
Mathieu Malaterre's avatar
Mathieu Malaterre committed
189

190 191
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  const std::string& libname)
192
{
193
  DynamicLoader::LibraryHandle lh;
194
  int length = MultiByteToWideChar(CP_UTF8, 0, libname.c_str(), -1, NULL, 0);
195
  wchar_t* wchars = new wchar_t[length + 1];
196
  wchars[0] = '\0';
197
  MultiByteToWideChar(CP_UTF8, 0, libname.c_str(), -1, wchars, length);
198
  lh = LoadLibraryW(wchars);
199
  delete[] wchars;
200 201 202
  return lh;
}

203
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
204 205 206 207
{
  return (int)FreeLibrary(lib);
}

208
DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
Brad King's avatar
Brad King committed
209
  DynamicLoader::LibraryHandle lib, const std::string& sym)
Mathieu Malaterre's avatar
Mathieu Malaterre committed
210
{
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
  // TODO: The calling convention affects the name of the symbol.  We
  // should have a tool to help get the symbol with the desired
  // calling convention.  Currently we assume cdecl.
  //
  // Borland:
  //   __cdecl    = "_func" (default)
  //   __fastcall = "@_func"
  //   __stdcall  = "func"
  //
  // Watcom:
  //   __cdecl    = "_func"
  //   __fastcall = "@_func@X"
  //   __stdcall  = "_func@X"
  //   __watcall  = "func_" (default)
  //
  // MSVC:
  //   __cdecl    = "func" (default)
  //   __fastcall = "@_func@X"
  //   __stdcall  = "_func@X"
  //
  // Note that the "@X" part of the name above is the total size (in
  // bytes) of the arguments on the stack.
233
  void* result;
234
#  if defined(__BORLANDC__) || defined(__WATCOMC__)
235
  // Need to prepend symbols with '_'
236 237
  std::string ssym = '_' + sym;
  const char* rsym = ssym.c_str();
238
#  else
239
  const char* rsym = sym.c_str();
240
#  endif
241
  result = (void*)GetProcAddress(lib, rsym);
242
// Hack to cast pointer-to-data to pointer-to-function.
243
#  ifdef __WATCOMC__
244
  return *(DynamicLoader::SymbolPointer*)(&result);
245
#  else
246
  return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
247
#  endif
248 249 250 251
}

const char* DynamicLoader::LastError()
{
252 253 254 255 256 257 258 259
  LPVOID lpMsgBuf = NULL;

  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                NULL, GetLastError(),
                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
                (LPTSTR)&lpMsgBuf, 0, NULL);

  if (!lpMsgBuf) {
260
    return NULL;
261
  }
262

263
  static char* str = 0;
264 265
  delete[] str;
  str = strcpy(new char[strlen((char*)lpMsgBuf) + 1], (char*)lpMsgBuf);
266
  // Free the buffer.
267
  LocalFree(lpMsgBuf);
268 269 270 271 272
  return str;
}

} // namespace KWSYS_NAMESPACE

273 274
#elif defined(__BEOS__)
// Implementation for BeOS / Haiku
275
#  include <string.h> // for strerror()
276

277 278
#  include <be/kernel/image.h>
#  include <be/support/Errors.h>
279

280
namespace KWSYS_NAMESPACE {
281 282 283

static image_id last_dynamic_err = B_OK;

284 285
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  const std::string& libname)
286 287 288
{
  // image_id's are integers, errors are negative. Add one just in case we
  //  get a valid image_id of zero (is that even possible?).
289
  image_id rc = load_add_on(libname.c_str());
290
  if (rc < 0) {
291 292
    last_dynamic_err = rc;
    return 0;
293
  }
294

295
  return rc + 1;
296 297 298 299
}

int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
{
300 301 302 303
  if (!lib) {
    last_dynamic_err = B_BAD_VALUE;
    return 0;
  } else {
304
    // The function dlclose() returns 0 on success, and non-zero on error.
305 306
    status_t rc = unload_add_on(lib - 1);
    if (rc != B_OK) {
307 308 309
      last_dynamic_err = rc;
      return 0;
    }
310
  }
311 312 313 314 315

  return 1;
}

DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
Brad King's avatar
Brad King committed
316
  DynamicLoader::LibraryHandle lib, const std::string& sym)
317 318
{
  // Hack to cast pointer-to-data to pointer-to-function.
319
  union
320 321 322 323 324 325 326
  {
    void* pvoid;
    DynamicLoader::SymbolPointer psym;
  } result;

  result.psym = NULL;

327 328 329
  if (!lib) {
    last_dynamic_err = B_BAD_VALUE;
  } else {
330 331 332
    // !!! FIXME: BeOS can do function-only lookups...does this ever
    // !!! FIXME:  actually _want_ a data symbol lookup, or was this union
    // !!! FIXME:  a leftover of dlsym()? (s/ANY/TEXT for functions only).
333 334 335
    status_t rc =
      get_image_symbol(lib - 1, sym.c_str(), B_SYMBOL_TYPE_ANY, &result.pvoid);
    if (rc != B_OK) {
336 337 338
      last_dynamic_err = rc;
      result.psym = NULL;
    }
339
  }
340 341 342 343 344
  return result.psym;
}

const char* DynamicLoader::LastError()
{
345
  const char* retval = strerror(last_dynamic_err);
346 347 348 349 350
  last_dynamic_err = B_OK;
  return retval;
}

} // namespace KWSYS_NAMESPACE
351

352 353
#elif defined(__MINT__)
// Implementation for FreeMiNT on Atari
354 355 356 357 358
#  define _GNU_SOURCE /* for program_invocation_name */
#  include <dld.h>
#  include <errno.h>
#  include <malloc.h>
#  include <string.h>
359

360
namespace KWSYS_NAMESPACE {
361

362 363
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  const std::string& libname)
364
{
365
  char* name = (char*)calloc(1, libname.size() + 1);
366
  dld_init(program_invocation_name);
367 368
  strncpy(name, libname.c_str(), libname.size());
  dld_link(libname.c_str());
369
  return (void*)name;
370 371 372 373
}

int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
{
374
  dld_unlink_by_file((char*)lib, 0);
375 376 377 378 379
  free(lib);
  return 0;
}

DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
Brad King's avatar
Brad King committed
380
  DynamicLoader::LibraryHandle lib, const std::string& sym)
381 382 383 384 385 386 387
{
  // Hack to cast pointer-to-data to pointer-to-function.
  union
  {
    void* pvoid;
    DynamicLoader::SymbolPointer psym;
  } result;
388
  result.pvoid = dld_get_symbol(sym.c_str());
389 390 391 392 393 394 395 396 397 398
  return result.psym;
}

const char* DynamicLoader::LastError()
{
  return dld_strerror(dld_errno);
}

} // namespace KWSYS_NAMESPACE

399 400 401
#else
// Default implementation for *NIX systems (including Mac OS X 10.3 and
// later) which use dlopen
402
#  include <dlfcn.h>
403

404
namespace KWSYS_NAMESPACE {
Mathieu Malaterre's avatar
Mathieu Malaterre committed
405

406 407
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  const std::string& libname)
408
{
409
  return dlopen(libname.c_str(), RTLD_LAZY);
410 411
}

412
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
413
{
414
  if (lib) {
415
    // The function dlclose() returns 0 on success, and non-zero on error.
416
    return !dlclose(lib);
417
  }
418 419 420 421
  // else
  return 0;
}

422
DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
Brad King's avatar
Brad King committed
423
  DynamicLoader::LibraryHandle lib, const std::string& sym)
Mathieu Malaterre's avatar
Mathieu Malaterre committed
424
{
425
  // Hack to cast pointer-to-data to pointer-to-function.
426
  union
Bill Hoffman's avatar
Bill Hoffman committed
427 428 429 430
  {
    void* pvoid;
    DynamicLoader::SymbolPointer psym;
  } result;
431
  result.pvoid = dlsym(lib, sym.c_str());
Bill Hoffman's avatar
Bill Hoffman committed
432
  return result.psym;
433 434 435 436
}

const char* DynamicLoader::LastError()
{
Mathieu Malaterre's avatar
Mathieu Malaterre committed
437
  return dlerror();
438 439 440 441
}

} // namespace KWSYS_NAMESPACE
#endif