WModuleLoader.cpp 6.86 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------

25 26
#include <set>
#include <string>
Sebastian Eichelbaum's avatar
[STYLE]  
Sebastian Eichelbaum committed
27
#include <vector>
28

29 30
#include <boost/regex.hpp>

31
#include "../common/WIOTools.h"
32
#include "../common/WPathHelper.h"
33
#include "../common/WSharedLib.h"
34 35 36

#include "WModuleLoader.h"

37
WModuleLoader::WModuleLoader( )
38
{
39
    // initialize members
40 41 42 43
}

WModuleLoader::~WModuleLoader()
{
44 45
    // cleanup all the handles
    m_libs.clear();
46 47
}

48 49
void WModuleLoader::load( WSharedAssociativeContainer< std::set< boost::shared_ptr< WModule > > >::WriteTicket ticket,
                          boost::filesystem::path dir, unsigned int level )
50
{
51
    for( boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator( dir );
52 53
         i != boost::filesystem::directory_iterator(); ++i )
    {
54
        // all modules need to begin with this
55
        std::string stem = i->path().stem().string();
56

57
        // we want to strip the search directory from the path
58 59
        std::string relPath = i->path().string();
        relPath.erase( 0, dir.string().length() + 1 ); // NOTE: +1 because we want to remove the "/" too
60

61
        // is it a lib? Use a regular expression to check this
62
        // NOTE:: the double \\ is needed to escape the escape char (to interpret the "dot" as dot and not as "any char".
63
        #ifdef __WIN32__
64
            static const boost::regex CheckLibMMP( "^(lib)?(.*)\\" + WSharedLib::getSystemSuffix() +"$" );
65
        #elif __APPLE__
66
            static const boost::regex CheckLibMMP( "^(lib)?(.*)\\.[0-9]+\\.[0-9]+\\.[0-9]+\\" + WSharedLib::getSystemSuffix() + "$" );
67
        #else
68
            static const boost::regex CheckLibMMP( "^(lib)?(.*)\\" + WSharedLib::getSystemSuffix() + "\\.[0-9]+\\.[0-9]+\\.[0-9]+$" );
69
        #endif
70
        // this will contain the filename afterwards
71
        boost::smatch matches;
72 73
        bool matchLibName = boost::regex_match( i->path().filename().string(), matches, CheckLibMMP );
        std::string libBaseName = matchLibName ? std::string( matches[2] ) : "";
74 75

        if( !boost::filesystem::is_directory( *i ) &&
76
            matchLibName &&
77
            ( stem.compare( 0, getModulePrefix().length(), getModulePrefix() ) == 0 )
78
          )
79 80 81
        {
            try
            {
82 83
                // load lib
                boost::shared_ptr< WSharedLib > l = boost::shared_ptr< WSharedLib >( new WSharedLib( i->path() ) );
84 85

                // get instantiation function
86
                W_LOADABLE_MODULE_SIGNATURE f;
87
                l->fetchFunction< W_LOADABLE_MODULE_SIGNATURE >( W_LOADABLE_MODULE_SYMBOL, f );
88 89

                // get the first prototype
90
                WModuleList m;
91
                f( m );
92 93

                // could the prototype be created?
94
                if( m.empty() )
95
                {
96
                    WLogger::getLogger()->addLogMessage( "Load failed for module \"" + relPath + "\". Could not create any " +
97 98 99 100 101 102
                                                         "prototype instance.", "Module Loader", LL_ERROR );
                    continue;
                }
                else
                {
                    // yes, add it to the list of prototypes
103
                    for( WModuleList::const_iterator iter = m.begin(); iter != m.end(); ++iter )
104
                    {
105 106 107 108 109 110 111 112
                        // which lib?
                        ( *iter )->setLibPath( i->path() );
                        // we use the library name (excluding extension and optional lib prefix) as package name
                        ( *iter )->setPackageName( libBaseName );
                        // resource path
                        ( *iter )->setLocalPath( WPathHelper::getModuleResourcePath( i->path().parent_path(), ( *iter )->getPackageName() ) );

                        // add module
113
                        ticket->get().insert( *iter );
114 115

                        // we need to keep a reference to the lib
116 117 118
                        m_libs.push_back( l );
                    }

119
                    wlog::debug( "Module Loader" ) << "Loaded " << m.size() << " modules from " << relPath;
120
                }
121

122 123 124 125
                // lib gets closed if l looses focus
            }
            catch( const WException& e )
            {
126
                WLogger::getLogger()->addLogMessage( "Load failed for module \"" + relPath + "\". " + e.what() + ". Ignoring.",
127 128 129
                                                     "Module Loader", LL_ERROR );
            }
        }
130 131
        else if( ( level <= 10 ) &&  // this sould be enough to tranverse the typical structure build/release/lib/openwalnut/MODULENAME (5 levels)
                 boost::filesystem::is_directory( *i ) )     // this only traverses down one level
132 133 134 135 136 137 138 139 140 141 142 143
        {
            // if it a dir -> traverse down
            load( ticket, *i, level + 1 );
        }
    }
}

void WModuleLoader::load( WSharedAssociativeContainer< std::set< boost::shared_ptr< WModule > > >::WriteTicket ticket )
{
    std::vector< boost::filesystem::path > allPaths = WPathHelper::getAllModulePaths();

    // go through each of the paths
144
    for( std::vector< boost::filesystem::path >::const_iterator path = allPaths.begin(); path != allPaths.end(); ++path )
145
    {
146
        WLogger::getLogger()->addLogMessage( "Searching modules in \"" + ( *path ).string() + "\".", "Module Loader", LL_INFO );
147 148

        // does the directory exist?
149
        if( !boost::filesystem::is_directory( *path ) || !boost::filesystem::exists( *path ) )
150
        {
151
            WLogger::getLogger()->addLogMessage( "Searching modules in \"" + ( *path ).string() +
Sebastian Eichelbaum's avatar
[STYLE]  
Sebastian Eichelbaum committed
152
                                                 "\" failed. It is not a directory or does not exist." +
153 154 155 156 157 158 159
                                                 " Ignoring.", "Module Loader", LL_WARNING );

            continue;
        }

        // directly search the path for libOWmodule_ files
        load( ticket, *path );
160
    }
161
}
162 163 164 165

std::string WModuleLoader::getModulePrefix()
{
    // all module file names need to have this prefix:
166
    return WSharedLib::getSystemPrefix();
167 168
}