From 79a216f3493a39d7f4f7a265c32ae35ae5d42c4a Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 9 Apr 2013 19:37:02 -0700 Subject: [PATCH] remove ltdl to reduce dependencies and because calling dlopen/LoadLibrary is easy --- SConstruct | 6 +-- include/mapnik/datasource_cache.hpp | 3 -- include/mapnik/plugin.hpp | 24 ++++++---- src/build.py | 2 +- src/datasource_cache.cpp | 59 +++++++++---------------- src/plugin.cpp | 68 ++++++++++++++++++++++++++--- 6 files changed, 101 insertions(+), 61 deletions(-) diff --git a/SConstruct b/SConstruct index 1bd4f5e94..1f85a2847 100644 --- a/SConstruct +++ b/SConstruct @@ -68,7 +68,6 @@ pretty_dep_names = { 'tiff':'TIFF C library | configure with TIFF_LIBS & TIFF_INCLUDES', 'png':'PNG C library | configure with PNG_LIBS & PNG_INCLUDES', 'icuuc':'ICU C++ library | configure with ICU_LIBS & ICU_INCLUDES or use ICU_LIB_NAME to specify custom lib name | more info: http://site.icu-project.org/', - 'ltdl':'GNU Libtool | more info: http://www.gnu.org/software/libtool', 'z':'Z compression library | more info: http://www.zlib.net/', 'm':'Basic math library, part of C++ stlib', 'pkg-config':'pkg-config tool | more info: http://pkg-config.freedesktop.org', @@ -309,8 +308,6 @@ opts.AddVariables( PathVariable('ICU_LIBS','Search path for ICU include files','/usr/' + LIBDIR_SCHEMA_DEFAULT, PathVariable.PathAccept), ('ICU_LIB_NAME', 'The library name for icu (such as icuuc, sicuuc, or icucore)', 'icuuc', PathVariable.PathAccept), - PathVariable('LTDL_INCLUDES', 'Search path for libltdl (part of libtool) include files', '/usr/include', PathVariable.PathAccept), - PathVariable('LTDL_LIBS','Search path for libltdl (ltdl.h) library files','/usr/' + LIBDIR_SCHEMA_DEFAULT, PathVariable.PathAccept), BoolVariable('PNG', 'Build Mapnik with PNG read and write support', 'True'), PathVariable('PNG_INCLUDES', 'Search path for libpng include files', '/usr/include', PathVariable.PathAccept), PathVariable('PNG_LIBS','Search path for libpng library files','/usr/' + LIBDIR_SCHEMA_DEFAULT, PathVariable.PathAccept), @@ -1115,7 +1112,7 @@ if not preconfigured: # Adding the required prerequisite library directories to the include path for # compiling and the library path for linking, respectively. - for required in ('ICU', 'SQLITE', 'LTDL'): + for required in ('ICU', 'SQLITE'): inc_path = env['%s_INCLUDES' % required] lib_path = env['%s_LIBS' % required] env.AppendUnique(CPPPATH = os.path.realpath(inc_path)) @@ -1140,7 +1137,6 @@ if not preconfigured: LIBSHEADERS = [ ['z', 'zlib.h', True,'C'], - ['ltdl', 'ltdl.h', True,'C'], [env['ICU_LIB_NAME'],'unicode/unistr.h',True,'C++'], ] diff --git a/include/mapnik/datasource_cache.hpp b/include/mapnik/datasource_cache.hpp index 4d9c41c78..74a70c992 100644 --- a/include/mapnik/datasource_cache.hpp +++ b/include/mapnik/datasource_cache.hpp @@ -35,8 +35,6 @@ // stl #include -struct lt__handle; - namespace mapnik { class PluginInfo; @@ -57,7 +55,6 @@ private: ~datasource_cache(); std::map > plugins_; bool registered_; - bool insert(std::string const& name,lt__handle * const module); std::vector plugin_directories_; }; } diff --git a/include/mapnik/plugin.hpp b/include/mapnik/plugin.hpp index 8058f1483..caf55d021 100644 --- a/include/mapnik/plugin.hpp +++ b/include/mapnik/plugin.hpp @@ -29,21 +29,29 @@ // stl #include -// ltdl -#include - namespace mapnik { + +// Opaque structure for handle +typedef struct _mapnik_lib_t mapnik_lib_t; + class PluginInfo : mapnik::noncopyable { -private: - std::string name_; - lt_dlhandle module_; public: - PluginInfo (std::string const& name,const lt_dlhandle module); + typedef const char * name_func(); + PluginInfo (std::string const& filename, + std::string const& library_name); ~PluginInfo(); std::string const& name() const; - lt_dlhandle handle() const; + bool valid() const; + std::string get_error() const; + void * get_symbol(std::string const& sym_name) const; + static void init(); + static void exit(); +private: + std::string filename_; + std::string name_; + mapnik_lib_t * module_; }; } diff --git a/src/build.py b/src/build.py index 5e0bb54d6..e6b9b9b8f 100644 --- a/src/build.py +++ b/src/build.py @@ -57,7 +57,7 @@ regex = 'boost_regex%s' % env['BOOST_APPEND'] system = 'boost_system%s' % env['BOOST_APPEND'] # clear out and re-set libs for this env -lib_env['LIBS'] = ['freetype','ltdl','z',env['ICU_LIB_NAME'],filesystem,system,regex] +lib_env['LIBS'] = ['freetype','z',env['ICU_LIB_NAME'],filesystem,system,regex] if env['PROJ']: lib_env['LIBS'].append('proj') diff --git a/src/datasource_cache.cpp b/src/datasource_cache.cpp index 0f302e413..70e0f4636 100644 --- a/src/datasource_cache.cpp +++ b/src/datasource_cache.cpp @@ -32,12 +32,8 @@ #include #include -// ltdl -#include - // stl #include -#include #include namespace mapnik { @@ -49,12 +45,12 @@ bool is_input_plugin(std::string const& filename) datasource_cache::datasource_cache() { - if (lt_dlinit()) throw std::runtime_error("lt_dlinit() failed"); + PluginInfo::init(); } datasource_cache::~datasource_cache() { - lt_dlexit(); + PluginInfo::exit(); } datasource_ptr datasource_cache::create(parameters const& params) @@ -87,23 +83,22 @@ datasource_ptr datasource_cache::create(parameters const& params) throw config_error(s); } - if (!itr->second->handle()) + if (!itr->second->valid()) { throw std::runtime_error(std::string("Cannot load library: ") + - lt_dlerror()); + itr->second->get_error()); } // http://www.mr-edd.co.uk/blog/supressing_gcc_warnings #ifdef __GNUC__ __extension__ #endif - create_ds* create_datasource = - reinterpret_cast(lt_dlsym(itr->second->handle(), "create")); + create_ds* create_datasource = reinterpret_cast(itr->second->get_symbol("create")); if (!create_datasource) { throw std::runtime_error(std::string("Cannot load symbols: ") + - lt_dlerror()); + itr->second->get_error()); } #ifdef MAPNIK_LOG @@ -129,12 +124,6 @@ datasource_ptr datasource_cache::create(parameters const& params) return ds; } -bool datasource_cache::insert(std::string const& type,const lt_dlhandle module) -{ - return plugins_.insert(std::make_pair(type,boost::make_shared - (type,module))).second; -} - std::string datasource_cache::plugin_directories() { return boost::algorithm::join(plugin_directories_,", "); @@ -185,47 +174,41 @@ void datasource_cache::register_datasources(std::string const& str) } } -bool datasource_cache::register_datasource(std::string const& str) +bool datasource_cache::register_datasource(std::string const& filename) { bool success = false; try { - lt_dlhandle module = lt_dlopen(str.c_str()); - if (module) + boost::shared_ptr plugin = boost::make_shared(filename,"datasource_name"); + if (plugin->valid()) { - // http://www.mr-edd.co.uk/blog/supressing_gcc_warnings -#ifdef __GNUC__ - __extension__ -#endif - datasource_name* ds_name = - reinterpret_cast(lt_dlsym(module, "datasource_name")); - if (ds_name && insert(ds_name(),module)) - { - MAPNIK_LOG_DEBUG(datasource_cache) - << "datasource_cache: Registered=" - << ds_name(); - - success = true; - } - else if (!ds_name) + if (plugin->name().empty()) { MAPNIK_LOG_ERROR(datasource_cache) << "Problem loading plugin library '" - << str << "' (plugin is lacking compatible interface)"; + << filename << "' (plugin is lacking compatible interface)"; + } + else + { + plugins_.insert(std::make_pair(plugin->name(),plugin)); + MAPNIK_LOG_DEBUG(datasource_cache) + << "datasource_cache: Registered=" + << plugin->name(); + success = true; } } else { MAPNIK_LOG_ERROR(datasource_cache) << "Problem loading plugin library: " - << str << " (dlopen failed - plugin likely has an unsatisfied dependency or incompatible ABI)"; + << filename << " (dlopen failed - plugin likely has an unsatisfied dependency or incompatible ABI)"; } } catch (std::exception const& ex) { MAPNIK_LOG_ERROR(datasource_cache) << "Exception caught while loading plugin library: " - << str << " (" << ex.what() << ")"; + << filename << " (" << ex.what() << ")"; } return success; } diff --git a/src/plugin.cpp b/src/plugin.cpp index 47c0d5f2e..eb7168fc0 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -21,30 +21,86 @@ *****************************************************************************/ #include -#include +#include + +#ifdef _WINDOWS + #include + #define handle HMODULE + #define dlsym GetProcAddress + #define dlclose FreeLibrary + #define dlerror GetLastError +#else + #include + #define handle void * +#endif + +// TODO - handle/report dlerror namespace mapnik { -PluginInfo::PluginInfo (std::string const& name,const lt_dlhandle module) - :name_(name),module_(module) {} +struct _mapnik_lib_t { + handle dl; +}; + +PluginInfo::PluginInfo(std::string const& filename, + std::string const& library_name) + : filename_(filename), + name_(), + module_(new mapnik_lib_t) + { +#ifdef _WINDOWS + if (module_) module_->dl = LoadLibraryA(filename.c_str()); +#else + if (module_) module_->dl = dlopen(filename.c_str(),RTLD_LAZY); +#endif + if (module_ && module_->dl) + { + name_func* name = reinterpret_cast(dlsym(module_->dl, library_name.c_str())); + if (name) name_ = name(); + } + } PluginInfo::~PluginInfo() { if (module_) { - lt_dlclose(module_),module_=0; + if (module_->dl) dlclose(module_->dl),module_->dl=0; + delete module_; } } + +void * PluginInfo::get_symbol(std::string const& sym_name) const +{ + return dlsym(module_->dl, sym_name.c_str()); +} + std::string const& PluginInfo::name() const { return name_; } -lt_dlhandle PluginInfo::handle() const +bool PluginInfo::valid() const { - return module_; + if (module_ && module_->dl && !name_.empty()) return true; + return false; } +std::string PluginInfo::get_error() const +{ + return std::string("could not open: '") + name_ + "'"; +} + +void PluginInfo::init() +{ + // do any initialization needed +} + +void PluginInfo::exit() +{ + // do any shutdown needed +} + + }