From 010f4aa9d69c30818fad4c998bbcb99b4f42f43d Mon Sep 17 00:00:00 2001 From: Leonardo Florez-Valencia Date: Mon, 16 May 2016 07:57:25 -0500 Subject: [PATCH] ... --- appli/bash/cpPlugins_HostCreator.cxx | 19 +- appli/examples/plugins/CMakeLists.txt | 1 + .../examples/plugins/example_LoadPlugins.cxx | 49 ++++ .../plugins/example_LoadPluginsDirectory.cxx | 6 + .../plugins/example_LoadPluginsFile.cxx | 6 + .../example_ReadWriteImageWithWorkspace.cxx | 2 +- cmake/cpPlugins_Functions.cmake | 2 +- lib/cpPlugins/Interface.cxx | 214 +++++++++++------- lib/cpPlugins/Interface.h | 16 +- lib/cpPlugins/Workspace.cxx | 3 +- lib/cpPlugins_Config.h | 4 + .../cpPlugins_Install_CMAKE.sh | 5 + .../cpPlugins_Install_ITK.sh | 5 + .../cpPlugins_Install_QT4.sh | 5 + .../cpPlugins_Install_VTK.sh | 5 + 15 files changed, 247 insertions(+), 95 deletions(-) create mode 100644 appli/examples/plugins/example_LoadPlugins.cxx diff --git a/appli/bash/cpPlugins_HostCreator.cxx b/appli/bash/cpPlugins_HostCreator.cxx index eb529bd..9ed9ec8 100644 --- a/appli/bash/cpPlugins_HostCreator.cxx +++ b/appli/bash/cpPlugins_HostCreator.cxx @@ -75,19 +75,20 @@ void process_header( TInfo& info, const std::string& file_name ) // ------------------------------------------------------------------------- int main( int argc, char* argv[] ) { - if( argc < 3 ) + if( argc < 4 ) { std::cerr << "Usage: " << argv[ 0 ] - << " output_file header_file_0.h header_file_0.h ..." + << " plugins_name output_file header_file_0.h header_file_0.h ..." << std::endl; return( 1 ); } // fi + std::string plugins_name = argv[ 1 ]; // Parse all header files TInfo info; - for( int i = 2; i < argc; ++i ) + for( int i = 3; i < argc; ++i ) process_header( info, argv[ i ] ); if( info.size( ) == 0 ) { @@ -97,10 +98,10 @@ int main( int argc, char* argv[] ) } // fi // Write data - std::ofstream out_stream( argv[ 1 ] ); + std::ofstream out_stream( argv[ 2 ] ); // Write include section - for( int i = 2; i < argc; ++i ) + for( int i = 3; i < argc; ++i ) out_stream << "#include \"" << argv[ i ] << "\"" < +#include + +int main( int argc, char* argv[] ) +{ + if( argc < 2 ) + { + std::cerr << "Usage: " << argv[ 0 ] << " plugins" << std::endl; + return( 1 ); + + } // fi + + // Load interface + cpPlugins::Interface interface; + try + { + interface.LoadPlugin( argv[ 1 ] ); + } + catch( std::exception& err ) + { + std::cerr + << "Error caught: " + << err.what( ) + << std::endl; + return( 1 ); + + } // yrt + + // Show loaded plugins + auto plugins = interface.GetPlugins( ); + for( auto pIt = plugins.begin( ); pIt != plugins.end( ); ++pIt ) + std::cout << "Plugin: " << *pIt << std::endl; + std::cout << std::endl; + + // Show loaded filters + auto filters = interface.GetFilters( ); + for( auto cIt = filters.begin( ); cIt != filters.end( ); ++cIt ) + { + std::cout << "Category: " << cIt->first << std::endl; + for( auto nIt = cIt->second.begin( ); nIt != cIt->second.end( ); ++nIt ) + std::cout + << "\tFilter: " << *nIt + << std::endl; + + } // rof + return( 0 ); +} + +// eof - $RCSfile$ diff --git a/appli/examples/plugins/example_LoadPluginsDirectory.cxx b/appli/examples/plugins/example_LoadPluginsDirectory.cxx index 4e9366d..803d390 100644 --- a/appli/examples/plugins/example_LoadPluginsDirectory.cxx +++ b/appli/examples/plugins/example_LoadPluginsDirectory.cxx @@ -23,6 +23,12 @@ int main( int argc, char* argv[] ) } // yrt + // Show loaded plugins + auto plugins = interface.GetPlugins( ); + for( auto pIt = plugins.begin( ); pIt != plugins.end( ); ++pIt ) + std::cout << "Plugin: " << *pIt << std::endl; + std::cout << std::endl; + // Show loaded filters auto filters = interface.GetFilters( ); for( auto cIt = filters.begin( ); cIt != filters.end( ); ++cIt ) diff --git a/appli/examples/plugins/example_LoadPluginsFile.cxx b/appli/examples/plugins/example_LoadPluginsFile.cxx index b9a2817..929a48c 100644 --- a/appli/examples/plugins/example_LoadPluginsFile.cxx +++ b/appli/examples/plugins/example_LoadPluginsFile.cxx @@ -26,6 +26,12 @@ int main( int argc, char* argv[] ) } // yrt + // Show loaded plugins + auto plugins = interface.GetPlugins( ); + for( auto pIt = plugins.begin( ); pIt != plugins.end( ); ++pIt ) + std::cout << "Plugin: " << *pIt << std::endl; + std::cout << std::endl; + // Show loaded filters auto filters = interface.GetFilters( ); for( auto cIt = filters.begin( ); cIt != filters.end( ); ++cIt ) diff --git a/appli/examples/plugins/example_ReadWriteImageWithWorkspace.cxx b/appli/examples/plugins/example_ReadWriteImageWithWorkspace.cxx index 1d2382d..f4231f9 100644 --- a/appli/examples/plugins/example_ReadWriteImageWithWorkspace.cxx +++ b/appli/examples/plugins/example_ReadWriteImageWithWorkspace.cxx @@ -8,7 +8,7 @@ int main( int argc, char* argv[] ) { std::cerr << "Usage: " << argv[ 0 ] - << " input_image(s) output_image" << std::endl; + << " input_image(s) output_image [output_workspace]" << std::endl; return( 1 ); } // fi diff --git a/cmake/cpPlugins_Functions.cmake b/cmake/cpPlugins_Functions.cmake index 68c2b88..d53d0f0 100644 --- a/cmake/cpPlugins_Functions.cmake +++ b/cmake/cpPlugins_Functions.cmake @@ -39,7 +39,7 @@ SET(host ${CMAKE_CURRENT_BINARY_DIR}/${libname}_Host.cxx) ADD_CUSTOM_COMMAND( OUTPUT ${host} DEPENDS ${cpPlugins_HostCreator_APP} ${headers} - COMMAND ${cpPlugins_HostCreator_APP} ${host} ${headers} + COMMAND ${cpPlugins_HostCreator_APP} ${libname} ${host} ${headers} ) SET(qtsources) FOREACH(qth ${qtheaders}) diff --git a/lib/cpPlugins/Interface.cxx b/lib/cpPlugins/Interface.cxx index 53b7b11..1f0a015 100644 --- a/lib/cpPlugins/Interface.cxx +++ b/lib/cpPlugins/Interface.cxx @@ -12,6 +12,7 @@ cpPlugins::Interface:: Interface( ) { + this->UpdatePaths( ); } // ------------------------------------------------------------------------- @@ -31,74 +32,101 @@ GetFilters( ) // ------------------------------------------------------------------------- void cpPlugins::Interface:: -GuessAccesiblePlugins( ) +UpdatePaths( ) { // Load environment configuration - char* path = std::getenv( "cpPlugins_PATHS" ); - if( path != NULL ) - { - std::vector< std::string > tokens; - cpPlugins::TokenizeString( tokens, path, "#" ); - for( auto tIt = tokens.begin( ); tIt != tokens.end( ); ++tIt ) - try { this->LoadPluginDir( *tIt ); } catch( ... ) { } - - } // fi + this->m_Paths.clear( ); + char* p = std::getenv( "cpPlugins_PATHS" ); + if( p != NULL ) + cpPlugins::TokenizeString( this->m_Paths, p, cpPlugins_SEPARATOR ); + this->m_Paths.push_back( "." ); +} - // Load local path - auto lpath = cpPlugins::CanonicalPath( "." ); - try { this->LoadPluginDir( lpath ); } catch( ... ) { } +// ------------------------------------------------------------------------- +void cpPlugins::Interface:: +GuessAccesiblePlugins( ) +{ + for( auto i = this->m_Paths.begin( ); i != this->m_Paths.end( ); ++i ) + try { this->LoadPluginDir( *i ); } catch( ... ) { } } // ------------------------------------------------------------------------- -bool cpPlugins::Interface:: -LoadConfiguration( const std::string& filename ) +void cpPlugins::Interface:: +LoadPlugin( const std::string& name ) { - std::ifstream in( filename.c_str( ) ); - if( !in ) - return( false ); + std::stringstream str; + str << cpPlugins_LIB_PREFIX << name << "." << cpPlugins_LIB_EXT; + std::string base_name = str.str( ); + bool found = false; + for( auto i = this->m_Paths.begin( ); i != this->m_Paths.end( ); ++i ) + { + std::string filename = *i; + if( i->back( ) != '/' ) + filename += std::string( "/" ); + filename += base_name; + try + { + this->LoadPluginFile( filename ); + found = true; + } + catch( ... ) + { + } // yrt - this->UnloadAll( ); - std::string line; - while( std::getline( in, line ) ) - try { this->LoadPluginFile( line ); } catch( ... ) { } - return( true ); + } // rof + if( !found ) + throw std::runtime_error( + std::string( "cpPlugins::Interface: Plugins library \"" ) + + name + + std::string( "\" not found." ) + ); } // ------------------------------------------------------------------------- -bool cpPlugins::Interface:: -SaveConfiguration( const std::string& filename ) const +void cpPlugins::Interface:: +LoadPluginDir( const std::string& dirname ) { - std::ofstream out( filename.c_str( ) ); - if( !out ) - return( false ); - auto dIt = this->m_DynLibraries.begin( ); - for( ; dIt != this->m_DynLibraries.end( ); ++dIt ) - out << dIt->first << std::endl; - out.close( ); - return( true ); + DIR* dir; + struct dirent* ent; + if( ( dir = opendir( dirname.c_str( ) ) ) != NULL ) + { + while( ( ent = readdir( dir ) ) != NULL ) + { + try + { + this->LoadPluginFile( + dirname + + std::string( "/" ) + + ent->d_name + ); + } + catch( ... ) { } + + } // elihw + closedir( dir ); + } + else + throw std::runtime_error( + std::string( "cpPlugins::Interface: Could not load directory " ) + + std::string( "\"" ) + dirname + std::string( "\"" ) + ); } // ------------------------------------------------------------------------- void cpPlugins::Interface:: LoadPluginFile( const std::string& filename ) { - // Open library with its canonical path name - auto canonical_fn = cpPlugins::PathHelper::CanonicalPath( filename ); - if( canonical_fn == "" ) + // Canonical filename + auto canonical = cpPlugins::PathHelper::CanonicalPath( filename ); + if( canonical == "" ) throw std::runtime_error( std::string( "cpPlugins::Interface: Library \"" ) + filename + std::string( "\" does not exist." ) ); - // Check if it was already loaded - if( - this->m_DynLibraries.find( canonical_fn ) != this->m_DynLibraries.end( ) - ) - return; - - // Ok, try to load the library - void* hnd = Self::_DLOpen( canonical_fn ); + // Try to load the library + void* hnd = Self::_DLOpen( canonical ); if( hnd == NULL ) throw std::runtime_error( std::string( "cpPlugins::Interface: Could not load library \"" ) + @@ -106,6 +134,13 @@ LoadPluginFile( const std::string& filename ) std::string( "\"" ) ); + // Get plugin name + std::string pl_name = Self::_DLGetName( hnd ); + + // Check if it was already loaded + if( this->m_DynLibraries.find( pl_name ) != this->m_DynLibraries.end( ) ) + return; + // Load filters TFilters filters = Self::_DLGetFilters( hnd ); @@ -134,7 +169,7 @@ LoadPluginFile( const std::string& filename ) if( creator != NULL ) { this->m_DynFilters[ catIt->first][ *clsIt ] = - TDynFunc( canonical_fn, creator ); + TDynFunc( pl_name, creator ); this->m_Filters[ catIt->first ].insert( *clsIt ); save_handler = true; @@ -148,44 +183,11 @@ LoadPluginFile( const std::string& filename ) // Keep dynlib handler, if needed if( save_handler ) - this->m_DynLibraries[ canonical_fn ] = hnd; + this->m_DynLibraries[ pl_name ] = TDynFileInfo( canonical, hnd ); else Self::_DLClose( hnd ); } -// ------------------------------------------------------------------------- -unsigned int cpPlugins::Interface:: -LoadPluginDir( const std::string& dirname ) -{ - DIR* dir; - struct dirent* ent; - unsigned int count = 0; - if( ( dir = opendir( dirname.c_str( ) ) ) != NULL ) - { - while( ( ent = readdir( dir ) ) != NULL ) - { - try - { - this->LoadPluginFile( - dirname + - std::string( "/" ) + - ent->d_name - ); - count++; - } - catch( ... ) { } - - } // elihw - closedir( dir ); - } - else - throw std::runtime_error( - std::string( "cpPlugins::Interface: Could not load directory " ) + - std::string( "\"" ) + dirname + std::string( "\"" ) - ); - return( count ); -} - // ------------------------------------------------------------------------- void cpPlugins::Interface:: UnloadAll( ) @@ -195,7 +197,7 @@ UnloadAll( ) d != this->m_DynLibraries.end( ); ++d ) - Self::_DLClose( d->second ); + Self::_DLClose( d->second.second ); this->m_DynLibraries.clear( ); this->m_DynFilters.clear( ); this->m_Filters.clear( ); @@ -220,6 +222,33 @@ Create( const std::string& category, const std::string& name ) return( filter ); } +// ------------------------------------------------------------------------- +std::string cpPlugins::Interface:: +GetPluginName( const std::string& category, const std::string& name ) const +{ + std::string plugin = ""; + auto catIt = this->m_DynFilters.find( category ); + if( catIt != this->m_DynFilters.end( ) ) + { + auto clsIt = catIt->second.find( name ); + if( clsIt != catIt->second.end( ) ) + plugin = clsIt->second.first; + + } // fi + return( plugin ); +} + +// ------------------------------------------------------------------------- +std::vector< std::string > cpPlugins::Interface:: +GetPlugins( ) const +{ + std::vector< std::string > res; + auto i = this->m_DynLibraries.begin( ); + for( ; i != this->m_DynLibraries.end( ); ++i ) + res.push_back( i->first ); + return( res ); +} + // ------------------------------------------------------------------------- void* cpPlugins::Interface:: _DLOpen( const std::string& fname ) @@ -234,6 +263,29 @@ _DLOpen( const std::string& fname ) return( hnd ); } +// ------------------------------------------------------------------------- +const char* cpPlugins::Interface:: +_DLGetName( void* hnd ) +{ + // Get descriptors + typedef const char* ( *f_t )( ); + f_t f = NULL; +#ifdef cpPlugins_SYS_WINDOWS + f = ( f_t )( ::GetProcAddress( ( HMODULE )hnd, "cpPlugins_Name" ) ); +#else // cpPlugins_SYS_WINDOWS + f = ( f_t )( dlsym( hnd, "cpPlugins_Name" ) ); +#endif // cpPlugins_SYS_WINDOWS + if( f == NULL ) + { + Self::_DLClose( hnd ); + throw std::runtime_error( + "cpPlugins::Interface: Library not recognized as a cpPlugins library." + ); + + } // fi + return( f( ) ); +} + // ------------------------------------------------------------------------- cpPlugins::Interface:: TFilters cpPlugins::Interface:: @@ -251,7 +303,7 @@ _DLGetFilters( void* hnd ) { Self::_DLClose( hnd ); throw std::runtime_error( - "cpPlugins::Interface: Library not recognized as a cpPlugins library: " + "cpPlugins::Interface: Library not recognized as a cpPlugins library." ); } // fi diff --git a/lib/cpPlugins/Interface.h b/lib/cpPlugins/Interface.h index 22d4811..655bbfa 100644 --- a/lib/cpPlugins/Interface.h +++ b/lib/cpPlugins/Interface.h @@ -20,8 +20,9 @@ namespace cpPlugins typedef std::pair< std::string, TCreator > TDynFunc; typedef std::map< std::string, TDynFunc > TDynFilter; typedef std::map< std::string, TDynFilter > TDynFilters; - typedef std::map< std::string, void* > TDynLibraries; typedef std::map< std::string, std::set< std::string > > TFilters; + typedef std::pair< std::string, void* > TDynFileInfo; + typedef std::map< std::string, TDynFileInfo > TDynLibraries; public: Interface( ); @@ -29,20 +30,24 @@ namespace cpPlugins const TFilters& GetFilters( ); + void UpdatePaths( ); void GuessAccesiblePlugins( ); - - bool LoadConfiguration( const std::string& filename ); - bool SaveConfiguration( const std::string& filename ) const; + void LoadPlugin( const std::string& name ); + void LoadPluginDir( const std::string& dirname ); void LoadPluginFile( const std::string& filename ); - unsigned int LoadPluginDir( const std::string& dirname ); void UnloadAll( ); cpPlugins::ProcessObject::Pointer Create( const std::string& category, const std::string& name ); + std::string GetPluginName( + const std::string& category, const std::string& name + ) const; + std::vector< std::string > GetPlugins( ) const; protected: static void* _DLOpen( const std::string& fname ); + static const char* _DLGetName( void* hnd ); static TFilters _DLGetFilters( void* hnd ); static TCreator _DLGetCreator( void* hnd, const std::string& category, const std::string& name @@ -50,6 +55,7 @@ namespace cpPlugins static void _DLClose( void* hnd ); protected: + std::vector< std::string > m_Paths; TDynLibraries m_DynLibraries; TDynFilters m_DynFilters; TFilters m_Filters; diff --git a/lib/cpPlugins/Workspace.cxx b/lib/cpPlugins/Workspace.cxx index d749829..d441c49 100644 --- a/lib/cpPlugins/Workspace.cxx +++ b/lib/cpPlugins/Workspace.cxx @@ -118,8 +118,7 @@ CreateFilter( // Get or create new filter from name if( !( this->m_Graph->HasVertexIndex( name ) ) ) { - ProcessObject::Pointer f = - this->m_Interface->Create( category, filter ); + ProcessObject::Pointer f = this->m_Interface->Create( category, filter ); if( f.IsNotNull( ) ) { if( f->IsInteractive( ) ) diff --git a/lib/cpPlugins_Config.h b/lib/cpPlugins_Config.h index e157cd3..9886262 100644 --- a/lib/cpPlugins_Config.h +++ b/lib/cpPlugins_Config.h @@ -34,6 +34,7 @@ # define cpPlugins_SYS_WINDOWS # define cpPlugins_LIB_PREFIX "" # define cpPlugins_LIB_EXT "dll" +# define cpPlugins_SEPARATOR ";" # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif @@ -44,14 +45,17 @@ # define cpPlugins_SYS_LINUX # define cpPlugins_LIB_PREFIX "lib" # define cpPlugins_LIB_EXT "so" +# define cpPlugins_SEPARATOR ":" #elif defined( __APPLE__ ) || defined( MACOSX ) || defined( macintosh ) || defined( Macintosh ) # define cpPlugins_SYS_MACOS # define cpPlugins_LIB_PREFIX "lib" # define cpPlugins_LIB_EXT "dylib" +# define cpPlugins_SEPARATOR ":" #elif defined( __FreeBSD__ ) || defined( __FreeBSD_kernel__ ) # define cpPlugins_SYS_FREEBSD # define cpPlugins_LIB_PREFIX "lib" # define cpPlugins_LIB_EXT "so" +# define cpPlugins_SEPARATOR ":" #else # error "This operating system is not supported by cpPlugins" #endif diff --git a/third_party_installers/cpPlugins_Install_CMAKE.sh b/third_party_installers/cpPlugins_Install_CMAKE.sh index 07cc1a8..ed6256f 100755 --- a/third_party_installers/cpPlugins_Install_CMAKE.sh +++ b/third_party_installers/cpPlugins_Install_CMAKE.sh @@ -141,6 +141,11 @@ echo "==> Platform : $platform" echo "==> Number of cores : $number_of_cores" echo "==> Number of threads : $number_of_threads" echo "=====================================================================" +read -n1 -r -p "Continue? [Y/N]... " key +echo +if [ "$key" != 'Y' -a "$key" != 'y' ] ; then + exit 1 +fi ## Create paths if [ "x$source_file" != "x" ]; then diff --git a/third_party_installers/cpPlugins_Install_ITK.sh b/third_party_installers/cpPlugins_Install_ITK.sh index 4a97e9e..99dcd85 100755 --- a/third_party_installers/cpPlugins_Install_ITK.sh +++ b/third_party_installers/cpPlugins_Install_ITK.sh @@ -148,6 +148,11 @@ echo "==> Platform : $platform" echo "==> Number of cores : $number_of_cores" echo "==> Number of threads : $number_of_threads" echo "=====================================================================" +read -n1 -r -p "Continue? [Y/N]... " key +echo +if [ "$key" != 'Y' -a "$key" != 'y' ] ; then + exit 1 +fi ## Create paths if [ "x$source_file" != "x" ]; then diff --git a/third_party_installers/cpPlugins_Install_QT4.sh b/third_party_installers/cpPlugins_Install_QT4.sh index 0960129..36c5d13 100755 --- a/third_party_installers/cpPlugins_Install_QT4.sh +++ b/third_party_installers/cpPlugins_Install_QT4.sh @@ -136,6 +136,11 @@ echo "==> Number of cores : $number_of_cores" echo "==> Number of threads : $number_of_threads" echo "==> Patch file : $patch_file" echo "=====================================================================" +read -n1 -r -p "Continue? [Y/N]... " key +echo +if [ "$key" != 'Y' -a "$key" != 'y' ] ; then + exit 1 +fi ## Create paths if [ "x$source_file" != "x" ]; then diff --git a/third_party_installers/cpPlugins_Install_VTK.sh b/third_party_installers/cpPlugins_Install_VTK.sh index 06f6501..1f8ecc3 100755 --- a/third_party_installers/cpPlugins_Install_VTK.sh +++ b/third_party_installers/cpPlugins_Install_VTK.sh @@ -174,6 +174,11 @@ echo "==> Platform : $platform" echo "==> Number of cores : $number_of_cores" echo "==> Number of threads : $number_of_threads" echo "=====================================================================" +read -n1 -r -p "Continue? [Y/N]... " key +echo +if [ "$key" != 'Y' -a "$key" != 'y' ] ; then + exit 1 +fi ## Create paths if [ "x$source_file" != "x" ]; then -- 2.45.1