DynamicLoader.cxx 11.3 KB
Newer Older
Kitware Robot's avatar
Kitware Robot committed
1 2
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
Kitware Robot's avatar
Kitware Robot committed
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
Kitware Robot's avatar
Kitware Robot committed
11 12
#  include "Configure.hxx.in"
#  include "DynamicLoader.hxx.in"
Kitware Robot's avatar
Kitware Robot committed
13 14
#endif

Kitware Robot's avatar
Kitware Robot committed
15 16 17 18 19 20 21 22 23 24 25
// This file actually contains several different implementations:
// * NOOP for environments without dynamic libs
// * 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
Kitware Robot's avatar
Kitware Robot committed
26 27
// the static methods of DynamicLoader.

Kitware Robot's avatar
Kitware Robot committed
28 29
#if !KWSYS_SUPPORTS_SHARED_LIBS
// Implementation for environments without dynamic libs
Kitware Robot's avatar
Kitware Robot committed
30
#  include <string.h> // for strerror()
Kitware Robot's avatar
Kitware Robot committed
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)
Kitware Robot's avatar
Kitware Robot committed
63
// Implementation for HPUX machines
Kitware Robot's avatar
Kitware Robot committed
64 65
#  include <dl.h>
#  include <errno.h>
Kitware Robot's avatar
Kitware Robot committed
66

Kitware Robot's avatar
Kitware Robot committed
67
namespace KWSYS_NAMESPACE {
Kitware Robot's avatar
Kitware Robot committed
68

Kitware Robot's avatar
Kitware Robot committed
69 70
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  const std::string& libname)
Kitware Robot's avatar
Kitware Robot committed
71
{
Kitware Robot's avatar
Kitware Robot committed
72
  return shl_load(libname.c_str(), BIND_DEFERRED | DYNAMIC_PATH, 0L);
Kitware Robot's avatar
Kitware Robot committed
73 74 75 76
}

int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
{
Kitware Robot's avatar
Kitware Robot committed
77
  if (!lib) {
Kitware Robot's avatar
Kitware Robot committed
78
    return 0;
Kitware Robot's avatar
Kitware Robot committed
79
  }
Kitware Robot's avatar
Kitware Robot committed
80 81 82
  return !shl_unload(lib);
}

Kitware Robot's avatar
Kitware Robot committed
83 84
DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
  DynamicLoader::LibraryHandle lib, const std::string& sym)
Kitware Robot's avatar
Kitware Robot committed
85 86 87 88 89
{
  void* addr;
  int status;

  /* TYPE_PROCEDURE Look for a function or procedure. (This used to be default)
Kitware Robot's avatar
Kitware Robot committed
90 91
   * TYPE_DATA      Look for a symbol in the data segment (for example,
   * variables).
Kitware Robot's avatar
Kitware Robot committed
92 93
   * TYPE_UNDEFINED Look for any symbol.
   */
Kitware Robot's avatar
Kitware Robot committed
94
  status = shl_findsym(&lib, sym.c_str(), TYPE_UNDEFINED, &addr);
Kitware Robot's avatar
Kitware Robot committed
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
  void* result = (status < 0) ? (void*)0 : addr;

  // Hack to cast pointer-to-data to pointer-to-function.
  return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
}

const char* DynamicLoader::LastError()
{
  // TODO: Need implementation with errno/strerror
  /* 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
   * 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.
   */

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

} // namespace KWSYS_NAMESPACE

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

Kitware Robot's avatar
Kitware Robot committed
130
namespace KWSYS_NAMESPACE {
Kitware Robot's avatar
Kitware Robot committed
131

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

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

Kitware Robot's avatar
Kitware Robot committed
150
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
Kitware Robot's avatar
Kitware Robot committed
151 152 153 154 155 156 157 158 159 160 161
{
  // 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.
  // 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);
  return success;
}

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

Kitware Robot's avatar
Kitware Robot committed
168
  NSSymbol symbol = NSLookupSymbolInModule(lib, rsym.c_str());
Kitware Robot's avatar
Kitware Robot committed
169
  if (symbol) {
Kitware Robot's avatar
Kitware Robot committed
170
    result = NSAddressOfSymbol(symbol);
Kitware Robot's avatar
Kitware Robot committed
171
  }
Kitware Robot's avatar
Kitware Robot committed
172 173 174 175 176 177 178 179 180 181 182 183

  // Hack to cast pointer-to-data to pointer-to-function.
  return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
}

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

} // namespace KWSYS_NAMESPACE

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

Kitware Robot's avatar
Kitware Robot committed
188
namespace KWSYS_NAMESPACE {
Kitware Robot's avatar
Kitware Robot committed
189

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

int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
{
  return (int)FreeLibrary(lib);
}

DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
Kitware Robot's avatar
Kitware Robot committed
209
  DynamicLoader::LibraryHandle lib, const std::string& sym)
Kitware Robot's avatar
Kitware Robot 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.
Kitware Robot's avatar
Kitware Robot committed
233
  void* result;
Kitware Robot's avatar
Kitware Robot committed
234
#  if defined(__BORLANDC__) || defined(__WATCOMC__)
Kitware Robot's avatar
Kitware Robot committed
235
  // Need to prepend symbols with '_'
Kitware Robot's avatar
Kitware Robot committed
236 237
  std::string ssym = '_' + sym;
  const char* rsym = ssym.c_str();
Kitware Robot's avatar
Kitware Robot committed
238
#  else
Kitware Robot's avatar
Kitware Robot committed
239
  const char* rsym = sym.c_str();
Kitware Robot's avatar
Kitware Robot committed
240
#  endif
Kitware Robot's avatar
Kitware Robot committed
241
  result = (void*)GetProcAddress(lib, rsym);
Kitware Robot's avatar
Kitware Robot committed
242
// Hack to cast pointer-to-data to pointer-to-function.
Kitware Robot's avatar
Kitware Robot committed
243
#  ifdef __WATCOMC__
Kitware Robot's avatar
Kitware Robot committed
244
  return *(DynamicLoader::SymbolPointer*)(&result);
Kitware Robot's avatar
Kitware Robot committed
245
#  else
Kitware Robot's avatar
Kitware Robot committed
246
  return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
Kitware Robot's avatar
Kitware Robot committed
247
#  endif
Kitware Robot's avatar
Kitware Robot committed
248 249 250 251
}

const char* DynamicLoader::LastError()
{
Kitware Robot's avatar
Kitware Robot committed
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) {
Kitware Robot's avatar
Kitware Robot committed
260
    return NULL;
Kitware Robot's avatar
Kitware Robot committed
261
  }
Kitware Robot's avatar
Kitware Robot committed
262 263

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

} // namespace KWSYS_NAMESPACE

Kitware Robot's avatar
Kitware Robot committed
273 274
#elif defined(__BEOS__)
// Implementation for BeOS / Haiku
Kitware Robot's avatar
Kitware Robot committed
275
#  include <string.h> // for strerror()
Kitware Robot's avatar
Kitware Robot committed
276

Kitware Robot's avatar
Kitware Robot committed
277 278
#  include <be/kernel/image.h>
#  include <be/support/Errors.h>
Kitware Robot's avatar
Kitware Robot committed
279

Kitware Robot's avatar
Kitware Robot committed
280
namespace KWSYS_NAMESPACE {
Kitware Robot's avatar
Kitware Robot committed
281 282 283

static image_id last_dynamic_err = B_OK;

Kitware Robot's avatar
Kitware Robot committed
284 285
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  const std::string& libname)
Kitware Robot's avatar
Kitware Robot committed
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?).
Kitware Robot's avatar
Kitware Robot committed
289
  image_id rc = load_add_on(libname.c_str());
Kitware Robot's avatar
Kitware Robot committed
290
  if (rc < 0) {
Kitware Robot's avatar
Kitware Robot committed
291 292
    last_dynamic_err = rc;
    return 0;
Kitware Robot's avatar
Kitware Robot committed
293
  }
Kitware Robot's avatar
Kitware Robot committed
294

Kitware Robot's avatar
Kitware Robot committed
295
  return rc + 1;
Kitware Robot's avatar
Kitware Robot committed
296 297 298 299
}

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

  return 1;
}

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

  result.psym = NULL;

Kitware Robot's avatar
Kitware Robot committed
327 328 329
  if (!lib) {
    last_dynamic_err = B_BAD_VALUE;
  } else {
Kitware Robot's avatar
Kitware Robot committed
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).
Kitware Robot's avatar
Kitware Robot committed
333 334 335
    status_t rc =
      get_image_symbol(lib - 1, sym.c_str(), B_SYMBOL_TYPE_ANY, &result.pvoid);
    if (rc != B_OK) {
Kitware Robot's avatar
Kitware Robot committed
336 337 338
      last_dynamic_err = rc;
      result.psym = NULL;
    }
Kitware Robot's avatar
Kitware Robot committed
339
  }
Kitware Robot's avatar
Kitware Robot committed
340 341 342 343 344
  return result.psym;
}

const char* DynamicLoader::LastError()
{
Kitware Robot's avatar
Kitware Robot committed
345
  const char* retval = strerror(last_dynamic_err);
Kitware Robot's avatar
Kitware Robot committed
346 347 348 349 350 351
  last_dynamic_err = B_OK;
  return retval;
}

} // namespace KWSYS_NAMESPACE

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

Kitware Robot's avatar
Kitware Robot committed
360
namespace KWSYS_NAMESPACE {
Kitware Robot's avatar
Kitware Robot committed
361

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

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

DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
Kitware Robot's avatar
Kitware Robot committed
380
  DynamicLoader::LibraryHandle lib, const std::string& sym)
Kitware Robot's avatar
Kitware Robot committed
381 382 383 384 385 386 387
{
  // Hack to cast pointer-to-data to pointer-to-function.
  union
  {
    void* pvoid;
    DynamicLoader::SymbolPointer psym;
  } result;
Kitware Robot's avatar
Kitware Robot committed
388
  result.pvoid = dld_get_symbol(sym.c_str());
Kitware Robot's avatar
Kitware Robot committed
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

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

Kitware Robot's avatar
Kitware Robot committed
404
namespace KWSYS_NAMESPACE {
Kitware Robot's avatar
Kitware Robot committed
405

Kitware Robot's avatar
Kitware Robot committed
406 407
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  const std::string& libname)
Kitware Robot's avatar
Kitware Robot committed
408
{
Kitware Robot's avatar
Kitware Robot committed
409
  return dlopen(libname.c_str(), RTLD_LAZY);
Kitware Robot's avatar
Kitware Robot committed
410 411 412 413
}

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

DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
Kitware Robot's avatar
Kitware Robot committed
423
  DynamicLoader::LibraryHandle lib, const std::string& sym)
Kitware Robot's avatar
Kitware Robot committed
424 425
{
  // Hack to cast pointer-to-data to pointer-to-function.
Kitware Robot's avatar
Kitware Robot committed
426
  union
Kitware Robot's avatar
Kitware Robot committed
427 428 429 430
  {
    void* pvoid;
    DynamicLoader::SymbolPointer psym;
  } result;
Kitware Robot's avatar
Kitware Robot committed
431
  result.pvoid = dlsym(lib, sym.c_str());
Kitware Robot's avatar
Kitware Robot committed
432 433 434 435 436 437 438 439 440 441
  return result.psym;
}

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

} // namespace KWSYS_NAMESPACE
#endif