DynamicLoader.cxx 14.1 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
#if !KWSYS_SUPPORTS_SHARED_LIBS
29
//----------------------------------------------------------------------------
30
// Implementation for environments without dynamic libs
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 63 64 65 66 67 68 69
#include <string.h> // for strerror()

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)
//----------------------------------------------------------------------------
// Implementation for HPUX  machines
70
#include <dl.h>
71
#include <errno.h>
72

73
namespace KWSYS_NAMESPACE {
74 75

//----------------------------------------------------------------------------
76 77
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  const std::string& libname)
78
{
79
  return shl_load(libname.c_str(), BIND_DEFERRED | DYNAMIC_PATH, 0L);
80 81 82
}

//----------------------------------------------------------------------------
83
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
84
{
85
  if (!lib) {
86
    return 0;
87
  }
88 89 90 91
  return !shl_unload(lib);
}

//----------------------------------------------------------------------------
92 93
DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
  DynamicLoader::LibraryHandle lib, const std::string& sym)
94
{
95 96
  void* addr;
  int status;
97

98
  /* TYPE_PROCEDURE Look for a function or procedure. (This used to be default)
99 100
   * TYPE_DATA      Look for a symbol in the data segment (for example,
   * variables).
101 102
   * TYPE_UNDEFINED Look for any symbol.
   */
103
  status = shl_findsym(&lib, sym.c_str(), TYPE_UNDEFINED, &addr);
104
  void* result = (status < 0) ? (void*)0 : addr;
105

106
  // Hack to cast pointer-to-data to pointer-to-function.
107
  return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
108 109 110 111 112
}

const char* DynamicLoader::LastError()
{
  // TODO: Need implementation with errno/strerror
113 114 115
  /* 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
116 117 118 119 120 121 122 123 124
   * 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.
   */

125
  if (errno == ENOEXEC || errno == ENOSYM || errno == EINVAL) {
126
    return strerror(errno);
127
  }
128
  // else
129 130 131 132 133
  return 0;
}

} // namespace KWSYS_NAMESPACE

134 135 136
#elif defined(__APPLE__) && (MAC_OS_X_VERSION_MAX_ALLOWED < 1030)
//----------------------------------------------------------------------------
// Implementation for Mac OS X 10.2.x and earlier
137
#include <mach-o/dyld.h>
138
#include <string.h> // for strlen
139

140
namespace KWSYS_NAMESPACE {
141 142

//----------------------------------------------------------------------------
143 144
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  const std::string& libname)
145 146 147
{
  NSObjectFileImageReturnCode rc;
  NSObjectFileImage image = 0;
148

149
  rc = NSCreateObjectFileImageFromFile(libname.c_str(), &image);
150
  // rc == NSObjectFileImageInappropriateFile when trying to load a dylib file
151
  if (rc != NSObjectFileImageSuccess) {
152
    return 0;
153 154 155 156
  }
  NSModule handle =
    NSLinkModule(image, libname.c_str(), NSLINKMODULE_OPTION_BINDNOW |
                   NSLINKMODULE_OPTION_RETURN_ON_ERROR);
157 158
  NSDestroyObjectFileImage(image);
  return handle;
159 160 161
}

//----------------------------------------------------------------------------
162
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
163
{
164 165 166
  // 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.
167 168 169
  // 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);
170 171 172 173
  return success;
}

//----------------------------------------------------------------------------
174
DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
Brad King's avatar
Brad King committed
175
  DynamicLoader::LibraryHandle lib, const std::string& sym)
176
{
177
  void* result = 0;
178
  // Need to prepend symbols with '_' on Apple-gcc compilers
179
  size_t len = sym.size();
180
  char* rsym = new char[len + 1 + 1];
181
  strcpy(rsym, "_");
182
  strcat(rsym + 1, sym.c_str());
183 184

  NSSymbol symbol = NSLookupSymbolInModule(lib, rsym);
185
  if (symbol) {
186
    result = NSAddressOfSymbol(symbol);
187
  }
188 189

  delete[] rsym;
190
  // Hack to cast pointer-to-data to pointer-to-function.
191
  return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
192 193 194 195 196 197 198 199 200 201
}

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

} // namespace KWSYS_NAMESPACE

202 203 204
#elif defined(_WIN32) && !defined(__CYGWIN__)
//----------------------------------------------------------------------------
// Implementation for Windows win32 code but not cygwin
205 206
#include <windows.h>

207
namespace KWSYS_NAMESPACE {
Mathieu Malaterre's avatar
Mathieu Malaterre committed
208

209
//----------------------------------------------------------------------------
210 211
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  const std::string& libname)
212
{
213
  DynamicLoader::LibraryHandle lh;
214
  int length = MultiByteToWideChar(CP_UTF8, 0, libname.c_str(), -1, NULL, 0);
215
  wchar_t* wchars = new wchar_t[length + 1];
216
  wchars[0] = '\0';
217
  MultiByteToWideChar(CP_UTF8, 0, libname.c_str(), -1, wchars, length);
218
  lh = LoadLibraryW(wchars);
219
  delete[] wchars;
220 221 222 223
  return lh;
}

//----------------------------------------------------------------------------
224
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
225 226 227 228 229
{
  return (int)FreeLibrary(lib);
}

//----------------------------------------------------------------------------
230
DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
Brad King's avatar
Brad King committed
231
  DynamicLoader::LibraryHandle lib, const std::string& sym)
Mathieu Malaterre's avatar
Mathieu Malaterre committed
232
{
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
  // 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.
255
  void* result;
256 257
#if defined(__BORLANDC__) || defined(__WATCOMC__)
  // Need to prepend symbols with '_'
258
  size_t len = sym.size();
259
  char* rsym = new char[len + 1 + 1];
260
  strcpy(rsym, "_");
261
  strcat(rsym, sym.c_str());
262
#else
263
  const char* rsym = sym.c_str();
264 265
#endif
  result = (void*)GetProcAddress(lib, rsym);
266
#if defined(__BORLANDC__) || defined(__WATCOMC__)
267
  delete[] rsym;
268
#endif
269
// Hack to cast pointer-to-data to pointer-to-function.
270 271 272
#ifdef __WATCOMC__
  return *(DynamicLoader::SymbolPointer*)(&result);
#else
273
  return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
274
#endif
275 276 277 278 279
}

//----------------------------------------------------------------------------
const char* DynamicLoader::LastError()
{
280 281 282 283 284 285 286 287
  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) {
Clinton Stimpson's avatar
 
Clinton Stimpson committed
288
    return NULL;
289
  }
Clinton Stimpson's avatar
 
Clinton Stimpson committed
290

291
  static char* str = 0;
292 293
  delete[] str;
  str = strcpy(new char[strlen((char*)lpMsgBuf) + 1], (char*)lpMsgBuf);
294
  // Free the buffer.
295
  LocalFree(lpMsgBuf);
296 297 298 299 300
  return str;
}

} // namespace KWSYS_NAMESPACE

301 302 303
#elif defined(__BEOS__)
//----------------------------------------------------------------------------
// Implementation for BeOS / Haiku
304
#include <string.h> // for strerror()
305

306 307
#include <be/kernel/image.h>
#include <be/support/Errors.h>
308

309
namespace KWSYS_NAMESPACE {
310 311 312 313

static image_id last_dynamic_err = B_OK;

//----------------------------------------------------------------------------
314 315
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  const std::string& libname)
316 317 318
{
  // 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?).
319
  image_id rc = load_add_on(libname.c_str());
320
  if (rc < 0) {
321 322
    last_dynamic_err = rc;
    return 0;
323
  }
324

325
  return rc + 1;
326 327 328 329 330
}

//----------------------------------------------------------------------------
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
{
331 332 333 334
  if (!lib) {
    last_dynamic_err = B_BAD_VALUE;
    return 0;
  } else {
335
    // The function dlclose() returns 0 on success, and non-zero on error.
336 337
    status_t rc = unload_add_on(lib - 1);
    if (rc != B_OK) {
338 339 340
      last_dynamic_err = rc;
      return 0;
    }
341
  }
342 343 344 345 346 347

  return 1;
}

//----------------------------------------------------------------------------
DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
Brad King's avatar
Brad King committed
348
  DynamicLoader::LibraryHandle lib, const std::string& sym)
349 350
{
  // Hack to cast pointer-to-data to pointer-to-function.
351
  union
352 353 354 355 356 357 358
  {
    void* pvoid;
    DynamicLoader::SymbolPointer psym;
  } result;

  result.psym = NULL;

359 360 361
  if (!lib) {
    last_dynamic_err = B_BAD_VALUE;
  } else {
362 363 364
    // !!! 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).
365 366 367
    status_t rc =
      get_image_symbol(lib - 1, sym.c_str(), B_SYMBOL_TYPE_ANY, &result.pvoid);
    if (rc != B_OK) {
368 369 370
      last_dynamic_err = rc;
      result.psym = NULL;
    }
371
  }
372 373 374 375 376 377
  return result.psym;
}

//----------------------------------------------------------------------------
const char* DynamicLoader::LastError()
{
378
  const char* retval = strerror(last_dynamic_err);
379 380 381 382 383
  last_dynamic_err = B_OK;
  return retval;
}

} // namespace KWSYS_NAMESPACE
Alexander Neundorf's avatar
 
Alexander Neundorf committed
384

385
#elif defined(__MINT__)
Alexander Neundorf's avatar
 
Alexander Neundorf committed
386
//----------------------------------------------------------------------------
387
// Implementation for FreeMiNT on Atari
388 389
#define _GNU_SOURCE /* for program_invocation_name */
#include <dld.h>
390 391 392
#include <errno.h>
#include <malloc.h>
#include <string.h>
393

394
namespace KWSYS_NAMESPACE {
395 396

//----------------------------------------------------------------------------
397 398
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  const std::string& libname)
399
{
400
  char* name = (char*)calloc(1, libname.size() + 1);
401
  dld_init(program_invocation_name);
402 403
  strncpy(name, libname.c_str(), libname.size());
  dld_link(libname.c_str());
404
  return (void*)name;
405 406 407 408 409
}

//----------------------------------------------------------------------------
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
{
410
  dld_unlink_by_file((char*)lib, 0);
411 412 413 414 415 416
  free(lib);
  return 0;
}

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

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

} // namespace KWSYS_NAMESPACE

437 438 439 440
#else
//----------------------------------------------------------------------------
// Default implementation for *NIX systems (including Mac OS X 10.3 and
// later) which use dlopen
441 442
#include <dlfcn.h>

443
namespace KWSYS_NAMESPACE {
Mathieu Malaterre's avatar
Mathieu Malaterre committed
444

445
//----------------------------------------------------------------------------
446 447
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  const std::string& libname)
448
{
449
  return dlopen(libname.c_str(), RTLD_LAZY);
450 451 452
}

//----------------------------------------------------------------------------
453
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
454
{
455
  if (lib) {
456
    // The function dlclose() returns 0 on success, and non-zero on error.
457
    return !dlclose(lib);
458
  }
459 460 461 462 463
  // else
  return 0;
}

//----------------------------------------------------------------------------
464
DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
Brad King's avatar
Brad King committed
465
  DynamicLoader::LibraryHandle lib, const std::string& sym)
Mathieu Malaterre's avatar
Mathieu Malaterre committed
466
{
467
  // Hack to cast pointer-to-data to pointer-to-function.
468
  union
Bill Hoffman's avatar
Bill Hoffman committed
469 470 471 472
  {
    void* pvoid;
    DynamicLoader::SymbolPointer psym;
  } result;
473
  result.pvoid = dlsym(lib, sym.c_str());
Bill Hoffman's avatar
Bill Hoffman committed
474
  return result.psym;
475 476 477 478 479
}

//----------------------------------------------------------------------------
const char* DynamicLoader::LastError()
{
Mathieu Malaterre's avatar
Mathieu Malaterre committed
480
  return dlerror();
481 482 483 484
}

} // namespace KWSYS_NAMESPACE
#endif