// Copyright (C) 2012-2015 ChaosForge Ltd // http://chaosforge.org/ // // This file is part of Nova libraries. // For conditions of distribution and use, see copying.txt file in root folder. #include "nv/core/library.hh" #if NV_PLATFORM == NV_WINDOWS # define WIN32_LEAN_AND_MEAN # include # define NV_LIB_EXT ".dll" # define NV_LIB_OPEN( name ) static_cast( LoadLibraryEx( name, NULL, LOAD_WITH_ALTERED_SEARCH_PATH ) ) # define NV_LIB_GET( handle, name ) reinterpret_cast( GetProcAddress( static_cast( handle ), name ) ) # define NV_LIB_CLOSE( handle ) ( FreeLibrary( static_cast( handle ) ) != 0 ) #elif NV_PLATFORM == NV_LINUX || NV_PLATFORM == NV_APPLE # include # define NV_LIB_EXT ".so" # define NV_LIB_OPEN( name ) dlopen( name, RTLD_LAZY | RTLD_GLOBAL) # define NV_LIB_GET( handle, name ) dlsym( static_cast( handle ), name ) # define NV_LIB_CLOSE( handle ) ( dlclose( static_cast( handle ) ) == 0 ) #elif NV_PLATFORM == NV_APPLE # include "macUtils.h" # include # define NV_LIB_EXT ".dylib" # define NV_LIB_OPEN( name ) mac_loadExeBundle( name ) # define NV_LIB_GET( handle, name ) mac_getBundleSym( handle, name ) # define NV_LIB_CLOSE( handle ) ( mac_unloadExeBundle( handle ) == 0 ) #endif #include "nv/core/logging.hh" using namespace nv; library::library() : m_handle( nullptr ), m_name() { } void library::open( string_view name ) { m_name.assign( name.data(), name.size() ); if ( !open() ) { m_handle = nullptr; NV_LOG_CRITICAL( "library \"", name, "\" : failed to load!" ); NV_ABORT( "Can't load library!" ); } } bool nv::library::try_open( string_view name ) { m_name.assign( name.data(), name.size() ); if ( !open() ) { m_handle = nullptr; return false; } return true; } string_view library::get_name() const { return string_view( m_name ); } bool library::open( ) { if ( m_handle != NULL ) { return true; } NV_LOG_NOTICE( "library \"", string_view( m_name ), "\" : loading..." ); std::string name = m_name; string_view ext( NV_LIB_EXT ); if ( name.length() < ext.length() || name.substr( name.length() - ext.length(), ext.length() ) != ext ) { name.append( ext.data(), ext.length() ); } m_handle = NV_LIB_OPEN( name.c_str() ); if ( m_handle == NULL ) { NV_LOG_NOTICE( "library \"", string_view( name ), "\" : failed to open!" ); return false; } NV_LOG_NOTICE( "library \"", string_view( name ), "\" : loaded." ); return true; } void* library::get( string_view symbol ) { void* result = NV_LIB_GET( m_handle, symbol.data() ); if ( !result ) { NV_LOG_CRITICAL( "library \"", string_view( m_name ), "\" : can't find symbol \"", symbol, "\"" ); NV_ABORT( "Library symbol load failed!" ); } return result; } void* nv::library::try_get( string_view symbol ) { return NV_LIB_GET( m_handle, symbol.data() ); } bool library::is_open() const { return m_handle != nullptr; } void library::close() { if ( ! NV_LIB_CLOSE( m_handle ) ) { NV_LOG_ERROR( "library \"", string_view( m_name ), "\" : can't close library!" ); } m_handle = nullptr; } library::~library() { if ( m_handle != nullptr ) { close(); } } std::string library::get_error() { #if NV_PLATFORM == NV_WINDOWS // We do hate WinAPI for code like this, don't we? LPTSTR buffer = nullptr; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast( &buffer ), 0, NULL ); std::string msg( reinterpret_cast( buffer ) ); LocalFree( buffer ); return msg; #elif NV_PLATFORM == NV_LINUX || NV_PLATFORM == NV_APPLE return std::string( dlerror() ); #else return std::string(""); #endif }