Skip to content
Snippets Groups Projects
DynamicLoader.cxx 14.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
       file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
    
    #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
    
    #include "Configure.hxx.in"
    #include "DynamicLoader.hxx.in"
    
    // 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
    
    Mathieu Malaterre's avatar
    Mathieu Malaterre committed
    // the static methods of DynamicLoader.
    
    #if !KWSYS_SUPPORTS_SHARED_LIBS
    
    //----------------------------------------------------------------------------
    
    // Implementation for environments without dynamic libs
    
    #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
    
    namespace KWSYS_NAMESPACE {
    
    
    //----------------------------------------------------------------------------
    
    DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
      const std::string& libname)
    
      return shl_load(libname.c_str(), BIND_DEFERRED | DYNAMIC_PATH, 0L);
    
    }
    
    //----------------------------------------------------------------------------
    
    int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
    
      return !shl_unload(lib);
    }
    
    //----------------------------------------------------------------------------
    
    DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
      DynamicLoader::LibraryHandle lib, const std::string& sym)
    
      /* TYPE_PROCEDURE Look for a function or procedure. (This used to be default)
    
       * TYPE_DATA      Look for a symbol in the data segment (for example,
       * variables).
    
      status = shl_findsym(&lib, sym.c_str(), TYPE_UNDEFINED, &addr);
    
      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.
       */
    
    
      if (errno == ENOEXEC || errno == ENOSYM || errno == EINVAL) {
    
        return strerror(errno);
    
    #elif defined(__APPLE__) && (MAC_OS_X_VERSION_MAX_ALLOWED < 1030)
    //----------------------------------------------------------------------------
    // Implementation for Mac OS X 10.2.x and earlier
    
    #include <string.h> // for strlen
    
    namespace KWSYS_NAMESPACE {
    
    
    //----------------------------------------------------------------------------
    
    DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
      const std::string& libname)
    
    {
      NSObjectFileImageReturnCode rc;
      NSObjectFileImage image = 0;
    
      rc = NSCreateObjectFileImageFromFile(libname.c_str(), &image);
    
      // rc == NSObjectFileImageInappropriateFile when trying to load a dylib file
    
      if (rc != NSObjectFileImageSuccess) {
    
      }
      NSModule handle =
        NSLinkModule(image, libname.c_str(), NSLINKMODULE_OPTION_BINDNOW |
                       NSLINKMODULE_OPTION_RETURN_ON_ERROR);
    
      NSDestroyObjectFileImage(image);
      return handle;
    
    }
    
    //----------------------------------------------------------------------------
    
    int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
    
      // 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(
    
      DynamicLoader::LibraryHandle lib, const std::string& sym)
    
      void* result = 0;
    
      // Need to prepend symbols with '_' on Apple-gcc compilers
    
      size_t len = sym.size();
    
      char* rsym = new char[len + 1 + 1];
    
      strcat(rsym + 1, sym.c_str());
    
    
      NSSymbol symbol = NSLookupSymbolInModule(lib, rsym);
    
        result = NSAddressOfSymbol(symbol);
    
      // 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
    
    
    #elif defined(_WIN32) && !defined(__CYGWIN__)
    //----------------------------------------------------------------------------
    // Implementation for Windows win32 code but not cygwin
    
    namespace KWSYS_NAMESPACE {
    
    //----------------------------------------------------------------------------
    
    DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
      const std::string& libname)
    
      int length = MultiByteToWideChar(CP_UTF8, 0, libname.c_str(), -1, NULL, 0);
    
      wchar_t* wchars = new wchar_t[length + 1];
    
      MultiByteToWideChar(CP_UTF8, 0, libname.c_str(), -1, wchars, length);
    
      delete[] wchars;
    
      return lh;
    }
    
    //----------------------------------------------------------------------------
    
    int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
    
    {
      return (int)FreeLibrary(lib);
    }
    
    //----------------------------------------------------------------------------
    
    DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
    
      DynamicLoader::LibraryHandle lib, const std::string& sym)
    
    Mathieu Malaterre's avatar
    Mathieu Malaterre committed
    {
    
      // 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.
    
    #if defined(__BORLANDC__) || defined(__WATCOMC__)
      // Need to prepend symbols with '_'
    
      size_t len = sym.size();
    
      char* rsym = new char[len + 1 + 1];
    
      strcat(rsym, sym.c_str());
    
      const char* rsym = sym.c_str();
    
    #endif
      result = (void*)GetProcAddress(lib, rsym);
    
    #if defined(__BORLANDC__) || defined(__WATCOMC__)
    
    // Hack to cast pointer-to-data to pointer-to-function.
    
    #ifdef __WATCOMC__
      return *(DynamicLoader::SymbolPointer*)(&result);
    #else
    
      return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
    
    }
    
    //----------------------------------------------------------------------------
    const char* DynamicLoader::LastError()
    {
    
      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
        return NULL;
    
    Clinton Stimpson's avatar
     
    Clinton Stimpson committed
    
    
      delete[] str;
      str = strcpy(new char[strlen((char*)lpMsgBuf) + 1], (char*)lpMsgBuf);
    
      LocalFree(lpMsgBuf);
    
    #elif defined(__BEOS__)
    //----------------------------------------------------------------------------
    // Implementation for BeOS / Haiku
    
    #include <string.h> // for strerror()
    
    #include <be/kernel/image.h>
    #include <be/support/Errors.h>
    
    namespace KWSYS_NAMESPACE {
    
    
    static image_id last_dynamic_err = B_OK;
    
    //----------------------------------------------------------------------------
    
    DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
      const std::string& libname)
    
    {
      // 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?).
    
      image_id rc = load_add_on(libname.c_str());
    
        last_dynamic_err = rc;
        return 0;
    
    }
    
    //----------------------------------------------------------------------------
    int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
    {
    
      if (!lib) {
        last_dynamic_err = B_BAD_VALUE;
        return 0;
      } else {
    
        // The function dlclose() returns 0 on success, and non-zero on error.
    
        status_t rc = unload_add_on(lib - 1);
        if (rc != B_OK) {
    
          last_dynamic_err = rc;
          return 0;
        }
    
    
      return 1;
    }
    
    //----------------------------------------------------------------------------
    DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
    
      DynamicLoader::LibraryHandle lib, const std::string& sym)
    
    {
      // Hack to cast pointer-to-data to pointer-to-function.
    
      {
        void* pvoid;
        DynamicLoader::SymbolPointer psym;
      } result;
    
      result.psym = NULL;
    
    
      if (!lib) {
        last_dynamic_err = B_BAD_VALUE;
      } else {
    
        // !!! 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).
    
        status_t rc =
          get_image_symbol(lib - 1, sym.c_str(), B_SYMBOL_TYPE_ANY, &result.pvoid);
        if (rc != B_OK) {
    
          last_dynamic_err = rc;
          result.psym = NULL;
        }
    
      return result.psym;
    }
    
    //----------------------------------------------------------------------------
    const char* DynamicLoader::LastError()
    {
    
      const char* retval = strerror(last_dynamic_err);
    
      last_dynamic_err = B_OK;
      return retval;
    }
    
    } // namespace KWSYS_NAMESPACE
    
    Alexander Neundorf's avatar
     
    Alexander Neundorf committed
    
    
    Alexander Neundorf's avatar
     
    Alexander Neundorf committed
    //----------------------------------------------------------------------------
    
    // Implementation for FreeMiNT on Atari
    
    #define _GNU_SOURCE /* for program_invocation_name */
    #include <dld.h>
    
    #include <errno.h>
    #include <malloc.h>
    #include <string.h>
    
    namespace KWSYS_NAMESPACE {
    
    
    //----------------------------------------------------------------------------
    
    DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
      const std::string& libname)
    
      char* name = (char*)calloc(1, libname.size() + 1);
    
      dld_init(program_invocation_name);
    
      strncpy(name, libname.c_str(), libname.size());
      dld_link(libname.c_str());
    
      return (void*)name;
    
    }
    
    //----------------------------------------------------------------------------
    int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
    {
    
      dld_unlink_by_file((char*)lib, 0);
    
      free(lib);
      return 0;
    }
    
    //----------------------------------------------------------------------------
    DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
    
      DynamicLoader::LibraryHandle lib, const std::string& sym)
    
    {
      // Hack to cast pointer-to-data to pointer-to-function.
      union
      {
        void* pvoid;
        DynamicLoader::SymbolPointer psym;
      } result;
    
      result.pvoid = dld_get_symbol(sym.c_str());
    
      return result.psym;
    }
    
    //----------------------------------------------------------------------------
    const char* DynamicLoader::LastError()
    {
      return dld_strerror(dld_errno);
    }
    
    } // namespace KWSYS_NAMESPACE
    
    
    #else
    //----------------------------------------------------------------------------
    // Default implementation for *NIX systems (including Mac OS X 10.3 and
    // later) which use dlopen
    
    namespace KWSYS_NAMESPACE {
    
    //----------------------------------------------------------------------------
    
    DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
      const std::string& libname)
    
      return dlopen(libname.c_str(), RTLD_LAZY);
    
    }
    
    //----------------------------------------------------------------------------
    
    int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
    
        // The function dlclose() returns 0 on success, and non-zero on error.
    
      // else
      return 0;
    }
    
    //----------------------------------------------------------------------------
    
    DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
    
      DynamicLoader::LibraryHandle lib, const std::string& sym)
    
    Mathieu Malaterre's avatar
    Mathieu Malaterre committed
    {
    
      // Hack to cast pointer-to-data to pointer-to-function.
    
    Bill Hoffman's avatar
    Bill Hoffman committed
      {
        void* pvoid;
        DynamicLoader::SymbolPointer psym;
      } result;
    
      result.pvoid = dlsym(lib, sym.c_str());
    
    Bill Hoffman's avatar
    Bill Hoffman committed
      return result.psym;
    
    }
    
    //----------------------------------------------------------------------------
    const char* DynamicLoader::LastError()
    {
    
    Mathieu Malaterre's avatar
    Mathieu Malaterre committed
      return dlerror();