// Copyright (C) 2012 Kornel Kisielewicz // This file is part of NV Libraries. // For conditions of distribution and use, see copyright notice in nv.hh #include "nv/common.hh" #include "nv/library.hh" #if NV_PLATFORM == NV_WINDOWS # define WIN32_LEAN_AND_MEAN # include # define NV_LIB_EXT ".dll" # define NV_LIB_HANDLE HMODULE # define NV_LIB_OPEN( name ) LoadLibraryEx( name, NULL, LOAD_WITH_ALTERED_SEARCH_PATH ) # define NV_LIB_GET( handle, name ) GetProcAddress( handle, name ) # define NV_LIB_CLOSE( name ) !FreeLibrary( name ) #elif NV_PLATFORM == NV_LINUX || NV_PLATFORM == NV_APPLE # include # define NV_LIB_EXT ".so" # define NV_LIB_HANDLE void* # define NV_LIB_OPEN( name ) dlopen( name, RTLD_LAZY | RTLD_GLOBAL) # define NV_LIB_GET( handle, name ) dlsym( handle, name ) # define NV_LIB_CLOSE( name ) dlclose( name ) #elif NV_PLATFORM == NV_APPLE # include "macUtils.h" # include # define NV_LIB_EXT ".dylib" # define NV_LIB_HANDLE CFBundleRef # define NV_LIB_OPEN( name ) mac_loadExeBundle( name ) # define NV_LIB_GET( handle, name ) mac_getBundleSym( handle, name ) # define NV_LIB_CLOSE( name ) mac_unloadExeBundle( name ) #endif #include "nv/logging.hh" using namespace nv; library::library() : m_handle( nullptr ), m_name() { } void library::open( const string& name ) { m_name = name; if ( !open() ) { m_handle = nullptr; NV_THROW( library_error, "Can't load library!", name ); } } bool nv::library::try_open( const string& name ) { m_name = name; if ( !open() ) { m_handle = nullptr; return false; } return true; } const string& library::get_name() const { return m_name; } bool library::open( ) { if ( m_handle != NULL ) { return true; } NV_LOG( LOG_NOTICE, "library : loading '" + m_name + "'..." ); string name = m_name; string ext = NV_LIB_EXT; size_t ext_len = ext.length(); if ( name.length() < ext_len || name.substr( name.length() - ext_len, ext_len ) != ext ) { name += ext; } m_handle = (void*)NV_LIB_OPEN( name.c_str() ); if ( m_handle == NULL ) { NV_LOG( LOG_NOTICE, "library : '" + name + "' failed to open." ); return false; } NV_LOG( LOG_NOTICE, "library : '" + name + "' loaded." ); return true; } void* library::get( const string& symbol ) { void* result = (void*) NV_LIB_GET( (NV_LIB_HANDLE) m_handle, symbol.c_str() ); if ( !result ) { NV_THROW( library_error, "Can't find symbol " + symbol + "!", m_name ); } return result; } void* nv::library::try_get( const string& symbol ) { return (void*) NV_LIB_GET( (NV_LIB_HANDLE) m_handle, symbol.c_str() ); } bool library::is_open() const { return m_handle != nullptr; } void library::close() { if ( NV_LIB_CLOSE( (NV_LIB_HANDLE)m_handle ) ) { NV_LOG( LOG_ERROR, "library : can't close library '" + m_name + "'!" ); } m_handle = NULL; NV_LOG( LOG_NOTICE, "library : '" + m_name + "' closed." ); } library::~library() { if ( m_handle != NULL ) { close(); } } string library::get_error() { #if NV_PLATFORM == NV_WINDOWS // We do hate WinAPI for code like this, don't we? LPTSTR buffer = NULL; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buffer, 0, NULL ); string msg( (char*)buffer ); LocalFree( buffer ); return msg; #elif NV_PLATFORM == NV_LINUX || NV_PLATFORM == NV_APPLE return string(dlerror()); #else return string(""); #endif }