Newer
Older
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */

Mathieu Malaterre
committed
#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"

Mathieu Malaterre
committed
#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

Mathieu Malaterre
committed
#if !KWSYS_SUPPORTS_SHARED_LIBS
//----------------------------------------------------------------------------
// 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

Mathieu Malaterre
committed
#include <dl.h>
#include <errno.h>

Mathieu Malaterre
committed

Mathieu Malaterre
committed
//----------------------------------------------------------------------------
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
const std::string& libname)

Mathieu Malaterre
committed
{
return shl_load(libname.c_str(), BIND_DEFERRED | DYNAMIC_PATH, 0L);

Mathieu Malaterre
committed
}
//----------------------------------------------------------------------------
Andy Cedilnik
committed
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)

Mathieu Malaterre
committed
{

Mathieu Malaterre
committed
return !shl_unload(lib);
}
//----------------------------------------------------------------------------
DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
DynamicLoader::LibraryHandle lib, const std::string& sym)

Mathieu Malaterre
committed
void* addr;
int status;
Andy Cedilnik
committed
/* 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);

Mathieu Malaterre
committed
void* result = (status < 0) ? (void*)0 : addr;

Mathieu Malaterre
committed
// Hack to cast pointer-to-data to pointer-to-function.
Andy Cedilnik
committed
return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);

Mathieu Malaterre
committed
}
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

Mathieu Malaterre
committed
* 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) {

Mathieu Malaterre
committed
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

Mathieu Malaterre
committed
#include <mach-o/dyld.h>
#include <string.h> // for strlen

Mathieu Malaterre
committed

Mathieu Malaterre
committed
//----------------------------------------------------------------------------
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
const std::string& libname)

Mathieu Malaterre
committed
{
NSObjectFileImageReturnCode rc;
NSObjectFileImage image = 0;

Mathieu Malaterre
committed
rc = NSCreateObjectFileImageFromFile(libname.c_str(), &image);
// rc == NSObjectFileImageInappropriateFile when trying to load a dylib file
if (rc != NSObjectFileImageSuccess) {

Mathieu Malaterre
committed
return 0;
}
NSModule handle =
NSLinkModule(image, libname.c_str(), NSLINKMODULE_OPTION_BINDNOW |
NSLINKMODULE_OPTION_RETURN_ON_ERROR);
NSDestroyObjectFileImage(image);
return handle;

Mathieu Malaterre
committed
}
//----------------------------------------------------------------------------
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)

Mathieu Malaterre
committed
{
// 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);

Mathieu Malaterre
committed
return success;
}
//----------------------------------------------------------------------------
Andy Cedilnik
committed
DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
DynamicLoader::LibraryHandle lib, const std::string& sym)

Mathieu Malaterre
committed
{
// Need to prepend symbols with '_' on Apple-gcc compilers
char* rsym = new char[len + 1 + 1];
strcpy(rsym, "_");
strcat(rsym + 1, sym.c_str());
NSSymbol symbol = NSLookupSymbolInModule(lib, rsym);
result = NSAddressOfSymbol(symbol);
delete[] rsym;

Mathieu Malaterre
committed
// Hack to cast pointer-to-data to pointer-to-function.
Andy Cedilnik
committed
return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);

Mathieu Malaterre
committed
}
//----------------------------------------------------------------------------
const char* DynamicLoader::LastError()
{
return 0;
}
} // namespace KWSYS_NAMESPACE
#elif defined(_WIN32) && !defined(__CYGWIN__)
//----------------------------------------------------------------------------
// Implementation for Windows win32 code but not cygwin

Mathieu Malaterre
committed
#include <windows.h>

Mathieu Malaterre
committed
//----------------------------------------------------------------------------
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
const std::string& libname)

Mathieu Malaterre
committed
{
Andy Cedilnik
committed
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);

Mathieu Malaterre
committed
return lh;
}
//----------------------------------------------------------------------------
Andy Cedilnik
committed
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)

Mathieu Malaterre
committed
{
return (int)FreeLibrary(lib);
}
//----------------------------------------------------------------------------
Andy Cedilnik
committed
DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
DynamicLoader::LibraryHandle lib, const std::string& sym)
Brad King
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.
Brad King
committed
#if defined(__BORLANDC__) || defined(__WATCOMC__)
// Need to prepend symbols with '_'
char* rsym = new char[len + 1 + 1];
strcpy(rsym, "_");
const char* rsym = sym.c_str();
#endif
result = (void*)GetProcAddress(lib, rsym);
Brad King
committed
#if defined(__BORLANDC__) || defined(__WATCOMC__)
delete[] rsym;

Mathieu Malaterre
committed
#endif
// Hack to cast pointer-to-data to pointer-to-function.
Brad King
committed
#ifdef __WATCOMC__
return *(DynamicLoader::SymbolPointer*)(&result);
#else
Andy Cedilnik
committed
return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
Brad King
committed
#endif

Mathieu Malaterre
committed
}
//----------------------------------------------------------------------------
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) {

Mathieu Malaterre
committed
static char* str = 0;
delete[] str;
str = strcpy(new char[strlen((char*)lpMsgBuf) + 1], (char*)lpMsgBuf);

Mathieu Malaterre
committed
// Free the buffer.

Mathieu Malaterre
committed
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>
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
#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>
//----------------------------------------------------------------------------
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());
}
//----------------------------------------------------------------------------
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

Mathieu Malaterre
committed
#include <dlfcn.h>

Mathieu Malaterre
committed
//----------------------------------------------------------------------------
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
const std::string& libname)

Mathieu Malaterre
committed
{
return dlopen(libname.c_str(), RTLD_LAZY);

Mathieu Malaterre
committed
}
//----------------------------------------------------------------------------
Andy Cedilnik
committed
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)

Mathieu Malaterre
committed
{

Mathieu Malaterre
committed
// The function dlclose() returns 0 on success, and non-zero on error.

Mathieu Malaterre
committed
return !dlclose(lib);

Mathieu Malaterre
committed
// else
return 0;
}
//----------------------------------------------------------------------------
Andy Cedilnik
committed
DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
DynamicLoader::LibraryHandle lib, const std::string& sym)

Mathieu Malaterre
committed
// Hack to cast pointer-to-data to pointer-to-function.
{
void* pvoid;
DynamicLoader::SymbolPointer psym;
} result;
result.pvoid = dlsym(lib, sym.c_str());

Mathieu Malaterre
committed
}
//----------------------------------------------------------------------------
const char* DynamicLoader::LastError()
{

Mathieu Malaterre
committed
}
} // namespace KWSYS_NAMESPACE
#endif