| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ | |
| #if defined(_WIN32) | |
| # define NOMINMAX // hide min,max to not conflict with <limits> | |
| #endif | |
| #include "kwsysPrivate.h" | |
| #include KWSYS_HEADER(DynamicLoader.hxx) | |
| #include KWSYS_HEADER(Configure.hxx) | |
| #include KWSYS_HEADER(Encoding.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" | |
| #endif | |
| // 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 | |
| // the static methods of DynamicLoader. | |
| #define CHECK_OPEN_FLAGS(var, supported) \ | |
| do { \ | |
| /* Check for unknown flags. */ \ | |
| if ((var & AllOpenFlags) != var) { \ | |
| return InvalidLibrary; \ | |
| } \ | |
| \ | |
| /* Check for unsupported flags. */ \ | |
| if ((var & (supported)) != var) { \ | |
| return InvalidLibrary; \ | |
| } \ | |
| } while (0) | |
| namespace KWSYS_NAMESPACE { | |
| DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( | |
| std::string const& libname) | |
| { | |
| return DynamicLoader::OpenLibrary(libname, 0); | |
| } | |
| } | |
| #if !KWSYS_SUPPORTS_SHARED_LIBS | |
| // Implementation for environments without dynamic libs | |
| # include <string.h> // for strerror() | |
| namespace KWSYS_NAMESPACE { | |
| DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( | |
| std::string const& libname, int flags) | |
| { | |
| return InvalidLibrary; | |
| } | |
| int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) | |
| { | |
| if (!lib) { | |
| return 0; | |
| } | |
| return 1; | |
| } | |
| DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( | |
| DynamicLoader::LibraryHandle lib, std::string const& sym) | |
| { | |
| return nullptr; | |
| } | |
| char const* DynamicLoader::LastError() | |
| { | |
| return "General error"; | |
| } | |
| } // namespace KWSYS_NAMESPACE | |
| #elif defined(__hpux) | |
| // Implementation for HPUX machines | |
| # include <dl.h> | |
| # include <errno.h> | |
| namespace KWSYS_NAMESPACE { | |
| DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( | |
| std::string const& libname, int flags) | |
| { | |
| CHECK_OPEN_FLAGS(flags, 0); | |
| return shl_load(libname.c_str(), BIND_DEFERRED | DYNAMIC_PATH, 0L); | |
| } | |
| int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) | |
| { | |
| if (!lib) { | |
| return 0; | |
| } | |
| return !shl_unload(lib); | |
| } | |
| DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( | |
| DynamicLoader::LibraryHandle lib, std::string const& sym) | |
| { | |
| void* addr; | |
| int status; | |
| /* 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). | |
| * TYPE_UNDEFINED Look for any symbol. | |
| */ | |
| status = shl_findsym(&lib, sym.c_str(), TYPE_UNDEFINED, &addr); | |
| void* result = (status < 0) ? nullptr : addr; | |
| // Hack to cast pointer-to-data to pointer-to-function. | |
| return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result); | |
| } | |
| char const* 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); | |
| } | |
| // else | |
| return 0; | |
| } | |
| } // namespace KWSYS_NAMESPACE | |
| #elif defined(__APPLE__) && (MAC_OS_X_VERSION_MAX_ALLOWED < 1030) | |
| // Implementation for Mac OS X 10.2.x and earlier | |
| # include <mach-o/dyld.h> | |
| # include <string.h> // for strlen | |
| namespace KWSYS_NAMESPACE { | |
| DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( | |
| std::string const& libname, int flags) | |
| { | |
| CHECK_OPEN_FLAGS(flags, 0); | |
| NSObjectFileImageReturnCode rc; | |
| NSObjectFileImage image = 0; | |
| rc = NSCreateObjectFileImageFromFile(libname.c_str(), &image); | |
| // rc == NSObjectFileImageInappropriateFile when trying to load a dylib file | |
| if (rc != NSObjectFileImageSuccess) { | |
| return InvalidLibrary; | |
| } | |
| 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, std::string const& sym) | |
| { | |
| void* result = nullptr; | |
| // Need to prepend symbols with '_' on Apple-gcc compilers | |
| std::string rsym = '_' + sym; | |
| NSSymbol symbol = NSLookupSymbolInModule(lib, rsym.c_str()); | |
| if (symbol) { | |
| result = NSAddressOfSymbol(symbol); | |
| } | |
| // Hack to cast pointer-to-data to pointer-to-function. | |
| return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result); | |
| } | |
| char const* DynamicLoader::LastError() | |
| { | |
| return nullptr; | |
| } | |
| } // namespace KWSYS_NAMESPACE | |
| #elif defined(_WIN32) && !defined(__CYGWIN__) | |
| // Implementation for Windows win32 code but not cygwin | |
| # include <windows.h> | |
| # include <stdio.h> | |
| namespace KWSYS_NAMESPACE { | |
| DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( | |
| std::string const& libname, int flags) | |
| { | |
| CHECK_OPEN_FLAGS(flags, SearchBesideLibrary); | |
| DWORD llFlags = 0; | |
| if (flags & SearchBesideLibrary) { | |
| llFlags |= LOAD_WITH_ALTERED_SEARCH_PATH; | |
| } | |
| return LoadLibraryExW(Encoding::ToWindowsExtendedPath(libname).c_str(), | |
| nullptr, llFlags); | |
| } | |
| int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) | |
| { | |
| return (int)FreeLibrary(lib); | |
| } | |
| DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( | |
| DynamicLoader::LibraryHandle lib, std::string const& sym) | |
| { | |
| // 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. | |
| // | |
| // 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. | |
| void* result; | |
| char const* rsym = sym.c_str(); | |
| result = (void*)GetProcAddress(lib, rsym); | |
| return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result); | |
| } | |
| # define DYNLOAD_ERROR_BUFFER_SIZE 1024 | |
| char const* DynamicLoader::LastError() | |
| { | |
| wchar_t lpMsgBuf[DYNLOAD_ERROR_BUFFER_SIZE + 1]; | |
| DWORD error = GetLastError(); | |
| DWORD length = FormatMessageW( | |
| FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, error, | |
| MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language | |
| lpMsgBuf, DYNLOAD_ERROR_BUFFER_SIZE, nullptr); | |
| static char str[DYNLOAD_ERROR_BUFFER_SIZE + 1]; | |
| if (length < 1) { | |
| /* FormatMessage failed. Use a default message. */ | |
| snprintf(str, DYNLOAD_ERROR_BUFFER_SIZE, | |
| "DynamicLoader encountered error 0x%lX. " | |
| "FormatMessage failed with error 0x%lX", | |
| error, GetLastError()); | |
| return str; | |
| } | |
| if (!WideCharToMultiByte(CP_UTF8, 0, lpMsgBuf, -1, str, | |
| DYNLOAD_ERROR_BUFFER_SIZE, nullptr, nullptr)) { | |
| /* WideCharToMultiByte failed. Use a default message. */ | |
| snprintf(str, DYNLOAD_ERROR_BUFFER_SIZE, | |
| "DynamicLoader encountered error 0x%lX. " | |
| "WideCharToMultiByte failed with error 0x%lX", | |
| error, GetLastError()); | |
| } | |
| return str; | |
| } | |
| } // namespace KWSYS_NAMESPACE | |
| #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( | |
| std::string const& libname, int flags) | |
| { | |
| CHECK_OPEN_FLAGS(flags, 0); | |
| // 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()); | |
| if (rc < 0) { | |
| last_dynamic_err = rc; | |
| return InvalidLibrary; | |
| } | |
| return rc + 1; | |
| } | |
| 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, std::string const& sym) | |
| { | |
| // Hack to cast pointer-to-data to pointer-to-function. | |
| union | |
| { | |
| void* pvoid; | |
| DynamicLoader::SymbolPointer psym; | |
| } result; | |
| result.psym = nullptr; | |
| 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 = nullptr; | |
| } | |
| } | |
| return result.psym; | |
| } | |
| char const* DynamicLoader::LastError() | |
| { | |
| char const* retval = strerror(last_dynamic_err); | |
| last_dynamic_err = B_OK; | |
| return retval; | |
| } | |
| } // namespace KWSYS_NAMESPACE | |
| #elif defined(__MINT__) | |
| // 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( | |
| std::string const& libname, int flags) | |
| { | |
| CHECK_OPEN_FLAGS(flags, 0); | |
| 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, std::string const& 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; | |
| } | |
| char const* 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 | |
| # include <dlfcn.h> | |
| namespace KWSYS_NAMESPACE { | |
| DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( | |
| std::string const& libname, int flags) | |
| { | |
| CHECK_OPEN_FLAGS(flags, RTLDGlobal); | |
| int llFlags = RTLD_LAZY; | |
| if (flags & RTLDGlobal) { | |
| llFlags |= RTLD_GLOBAL; | |
| } | |
| return dlopen(libname.c_str(), llFlags); | |
| } | |
| int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) | |
| { | |
| if (lib) { | |
| // The function dlclose() returns 0 on success, and non-zero on error. | |
| return !dlclose(lib); | |
| } | |
| // else | |
| return 0; | |
| } | |
| DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( | |
| DynamicLoader::LibraryHandle lib, std::string const& sym) | |
| { | |
| // Hack to cast pointer-to-data to pointer-to-function. | |
| union | |
| { | |
| void* pvoid; | |
| DynamicLoader::SymbolPointer psym; | |
| } result; | |
| result.pvoid = dlsym(lib, sym.c_str()); | |
| return result.psym; | |
| } | |
| char const* DynamicLoader::LastError() | |
| { | |
| return dlerror(); | |
| } | |
| } // namespace KWSYS_NAMESPACE | |
| #endif |