From a42e6a5a8f803d9c47eec59197b3face6f96b4e8 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 3 Feb 2011 17:34:24 +0100 Subject: [PATCH] draft solution loading an INI file for module path resolution this would remove the need to compile any path into the EXE --- src/common/dummy-func.cpp | 176 +++++++++++++++++++++++++++++++++----- src/common/dummy-func.hpp | 9 +- 2 files changed, 154 insertions(+), 31 deletions(-) diff --git a/src/common/dummy-func.cpp b/src/common/dummy-func.cpp index 3892e6737..47250def3 100644 --- a/src/common/dummy-func.cpp +++ b/src/common/dummy-func.cpp @@ -17,28 +17,37 @@ extern "C" { } #include #include +#include #include +#include #include +#include +#include #include namespace lumiera { using std::string; + using std::ifstream; using boost::regex; using boost::smatch; using boost::regex_search; + using boost::sregex_iterator; namespace fsys = boost::filesystem; - + namespace opt = boost::program_options; + namespace { // Implementation helpers const size_t STRING_MAX_RELEVANT = 1000; - const char * const GUI_MODULE_TO_LOAD = "gtk_gui"; + const char * const BOOTSTRAP_INI = "$ORIGIN/setup.ini"; + const char * const GUI_MODULE_TO_LOAD = "gtk_gui.lum"; const char * const GET_PATH_TO_EXECUTABLE = "/proc/self/exe"; regex EXTRACT_RELATIVE_PATHSPEC ("\\$?ORIGIN/([^:]+)"); + regex EXTRACT_PATHSPEC ("(\\$?ORIGIN)?([^:]+)"); /** the real application would throw a custom exception... */ @@ -56,13 +65,16 @@ namespace lumiera { string catchMyself () { - string buff(STRING_MAX_RELEVANT+1, '\0' ); - ssize_t chars_read = readlink (GET_PATH_TO_EXECUTABLE, &buff[0], STRING_MAX_RELEVANT); - - if (0 > chars_read || chars_read == ssize_t(STRING_MAX_RELEVANT)) - dieHard ("unable to discover path of running executable"); - - buff.resize(chars_read); + static string buff(STRING_MAX_RELEVANT+1, '\0' ); + if (!buff.size()) + { + ssize_t chars_read = readlink (GET_PATH_TO_EXECUTABLE, &buff[0], STRING_MAX_RELEVANT); + + if (0 > chars_read || chars_read == ssize_t(STRING_MAX_RELEVANT)) + dieHard ("unable to discover path of running executable"); + + buff.resize(chars_read); + } return buff; } @@ -80,6 +92,134 @@ namespace lumiera { else dieHard ("no valid module loading location relative to executable defined in LUMIERA_PLUGIN_PATH"); } + + class SearchPathSplitter + : boost::noncopyable + { + sregex_iterator pos_, + end_; + + public: + SearchPathSplitter (string searchPath) + : pos_(searchPath.begin(),searchPath.end(), EXTRACT_PATHSPEC) + , end_() + { } + + bool + hasNext() + { + return pos_ != end_; + } + + string + next() + { + ++pos_; + if (!hasNext()) + dieHard ("Search path exhausted."); + + return resolveRelative(); + } + + private: + /** maybe resolve a path spec given relative to + * the current Executable location ($ORIGIN) */ + string + resolveRelative () + { + if (containsORIGINToken()) + return asAbsolutePath(); + else + return getFullPath(); + } + + smatch::value_type found(int group=0) { return (*pos_)[group]; } + + bool containsORIGINToken() { return found(1).matched; } + string getRelativePath() { return found(2); } + string getFullPath() { return found(); } + + string + asAbsolutePath() + { + fsys::path exePathName (catchMyself()); + fsys::path modPathName (exePathName.remove_leaf() / getRelativePath()); + + if (fsys::exists(modPathName) && !fsys::is_directory (modPathName)) + dieHard ("Error in search path: component"+modPathName.string()+"is not an existing directory"); + + return modPathName.string(); + } + }; + + + /** helper to establish the location to search for loadable modules. + * This is a simple demonstration of the basic technique used in the + * real application source to establish a plugin search path, based + * on the actual executable position plus compiled in and configured + * relative and absolute path specifications. + */ + string + resolveModulePath (string moduleName, string searchPath = "") + { + fsys::path modulePathName (moduleName); + SearchPathSplitter searchLocation(searchPath); + + while (true) + { + if (fsys::exists (modulePathName)) + { + INFO (config, "found module %s", modulePathName.string().c_str()); + return modulePathName.string(); + } + + // try / continue search path + if (searchLocation.hasNext()) + modulePathName = fsys::path() / searchLocation.next() / moduleName; + else + dieHard ("Module \""+moduleName+"\" not found" + + (searchPath.empty()? ".":" in search path: "+searchPath)); + } + } + + + + class Config + : boost::noncopyable + { + opt::options_description syntax; + opt::variables_map settings; + + public: + Config (string bootstrapIni) + : syntax("Lumiera installation and platform configuration") + , settings() + { + syntax.add_options() + ("BuildsystemDemo.gui", opt::value(), + "name of the Lumiera GUI plugin to load") + ("BuildsystemDemo.modulepath", opt::value(), + "search path for loadable modules. " + "May us $ORIGIN to refer to the EXE location") + ; + + ifstream configIn (resolveModulePath (bootstrapIni).c_str()); + + + opt::parsed_options parsed = + opt::parse_config_file (configIn, syntax); + + opt::store (parsed, settings); + opt::notify(settings); + } + + string + operator[] (const string key) const + { + return settings[key].as(); + } + }; + }//(End) implementation helpers @@ -91,7 +231,10 @@ namespace lumiera { void loadDummyGui() { - string moduleLocation = resolveModulePath (GUI_MODULE_TO_LOAD); + Config appConfig(BOOTSTRAP_INI); + string guiModule = appConfig["BuildsystemDemo.gui"]; + string moduleSearch = appConfig["BuildsystemDemo.modulepath"]; + string moduleLocation = resolveModulePath (guiModule, moduleSearch); void* handle = dlopen (moduleLocation.c_str(), RTLD_LAZY|RTLD_LOCAL); if (handle) @@ -111,19 +254,6 @@ namespace lumiera { } - string - resolveModulePath (string moduleName) - { - fsys::path exePathName (catchMyself()); - fsys::path modPathName (exePathName.remove_leaf() / getRelativeModuleLocation() / (moduleName+".lum") ); - - if (!fsys::exists (modPathName)) - dieHard ("Module "+modPathName.string()+" doesn't exist."); - - INFO (config, "found module %s", modPathName.string().c_str()); - return modPathName.string(); - } - } // namespace lumiera diff --git a/src/common/dummy-func.hpp b/src/common/dummy-func.hpp index dde394a6b..d15383b88 100644 --- a/src/common/dummy-func.hpp +++ b/src/common/dummy-func.hpp @@ -19,17 +19,10 @@ namespace lumiera { /** this is a function located in the liblumieracore.so, * which attempts to load the "pseudo-gui" as shared module * and invoke the gui-main. The sole purpose of this function - * is to demonstarte that the SCons build system is working. + * is to demonstrate that the SCons build system is working. */ void loadDummyGui(); - /** helper to establish the location to search for loadable modules. - * This is a simple demonstration of the basic technique used in the - * real application source to establish a plugin search path, based - * on the actual executable position plus compiled in and configured - * relative and absolute path specifications. - */ - string resolveModulePath (string moduleName); } // namespace lumiera #endif