CMake/DynamicLoader.cxx
KWSys Upstream 1b50bd3f5c KWSys 2016-12-02 (4967ccc0)
Code extracted from:

    http://public.kitware.com/KWSys.git

at commit 4967ccc054d268c430e73445f3a103e737c5f5f7 (master).

Upstream Shortlog
-----------------

Chuck Atkins (2):
      f1afce25 DynamicLoader: Re-organize preprocessor checks to use if, elif, else
      d94f92f7 DynamicLoader: Expand noop implementation to more platforms

Dāvis Mosāns (2):
      f069db91 Encoding: Fix conversion of strings that contain null bytes
      4967ccc0 ConsoleBuf: Fix output for strings that contain null byte
2016-12-05 09:55:32 -05:00

485 lines
14 KiB
C++

/* 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"
#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.
#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
#include <dl.h>
#include <errno.h>
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)
{
if (!lib) {
return 0;
}
return !shl_unload(lib);
}
//----------------------------------------------------------------------------
DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
DynamicLoader::LibraryHandle lib, const std::string& 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) ? (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);
}
// 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(
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) {
return 0;
}
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];
strcpy(rsym, "_");
strcat(rsym + 1, sym.c_str());
NSSymbol symbol = NSLookupSymbolInModule(lib, rsym);
if (symbol) {
result = NSAddressOfSymbol(symbol);
}
delete[] rsym;
// 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
#include <windows.h>
namespace KWSYS_NAMESPACE {
//----------------------------------------------------------------------------
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
const std::string& libname)
{
DynamicLoader::LibraryHandle lh;
int length = MultiByteToWideChar(CP_UTF8, 0, libname.c_str(), -1, NULL, 0);
wchar_t* wchars = new wchar_t[length + 1];
wchars[0] = '\0';
MultiByteToWideChar(CP_UTF8, 0, libname.c_str(), -1, wchars, length);
lh = LoadLibraryW(wchars);
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)
{
// 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.
void* result;
#if defined(__BORLANDC__) || defined(__WATCOMC__)
// Need to prepend symbols with '_'
size_t len = sym.size();
char* rsym = new char[len + 1 + 1];
strcpy(rsym, "_");
strcat(rsym, sym.c_str());
#else
const char* rsym = sym.c_str();
#endif
result = (void*)GetProcAddress(lib, rsym);
#if defined(__BORLANDC__) || defined(__WATCOMC__)
delete[] rsym;
#endif
// Hack to cast pointer-to-data to pointer-to-function.
#ifdef __WATCOMC__
return *(DynamicLoader::SymbolPointer*)(&result);
#else
return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
#endif
}
//----------------------------------------------------------------------------
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) {
return NULL;
}
static char* str = 0;
delete[] str;
str = strcpy(new char[strlen((char*)lpMsgBuf) + 1], (char*)lpMsgBuf);
// Free the buffer.
LocalFree(lpMsgBuf);
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(
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());
if (rc < 0) {
last_dynamic_err = rc;
return 0;
}
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, const std::string& sym)
{
// Hack to cast pointer-to-data to pointer-to-function.
union
{
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
#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(
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
#include <dlfcn.h>
namespace KWSYS_NAMESPACE {
//----------------------------------------------------------------------------
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
const std::string& libname)
{
return dlopen(libname.c_str(), RTLD_LAZY);
}
//----------------------------------------------------------------------------
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, const std::string& 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;
}
//----------------------------------------------------------------------------
const char* DynamicLoader::LastError()
{
return dlerror();
}
} // namespace KWSYS_NAMESPACE
#endif