From babbe33d1d2190548ab3e5a36562837b6c98788b Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 4 Feb 2011 16:10:59 +0100 Subject: [PATCH] Demonstration of complete bootstrap, loading INI and resolving GUI module path --- SConstruct | 1 + data/config/dummy_lumiera.ini | 8 +-- data/config/setup.ini | 20 ++++++++ src/common/dummy-func.cpp | 91 +++++++++++++++++++---------------- src/common/dummy-func.hpp | 11 +++++ 5 files changed, 86 insertions(+), 45 deletions(-) create mode 100644 data/config/setup.ini diff --git a/SConstruct b/SConstruct index c176dd6f3..99ee764bb 100644 --- a/SConstruct +++ b/SConstruct @@ -348,6 +348,7 @@ def defineBuildTargets(env, artifacts): artifacts['corelib'] = core artifacts['support'] = lLib artifacts['lumiera'] = ( env.Program('lumiera', ['src/lumiera/main.cpp'], LIBS=core, install=True) + + env.ConfigData(env.path.srcConf+'setup.ini') + env.ConfigData(env.path.srcConf+'dummy_lumiera.ini') ) diff --git a/data/config/dummy_lumiera.ini b/data/config/dummy_lumiera.ini index cfe91da1e..a8408c41b 100644 --- a/data/config/dummy_lumiera.ini +++ b/data/config/dummy_lumiera.ini @@ -1,4 +1,4 @@ -/* This is an dummy Lumiera config file - * - * Actually Lumiera can't yet load any config, as of 1/2011 - */ +# This is an dummy Lumiera config file +# +# Actually Lumiera can't yet load any extended config, as of 1/2011 +# diff --git a/data/config/setup.ini b/data/config/setup.ini new file mode 100644 index 000000000..e4a00f4e2 --- /dev/null +++ b/data/config/setup.ini @@ -0,0 +1,20 @@ +########################################################### +# ### Lumiera installation and platform configuration ### +# +# (file located relative to the Lumiera executable) +# + +[BuildsystemDemo] +# This is dummy/demonstration executable +# built from the "scons" git tree. It serves to +# document and evolve the SCons buildsystem in isolation +# and for tests of the packaging and build process. +# +gui = gtk_gui.lum +modulepath = $ORIGIN/modules + +[Lumiera] +# Lumiera video editor main application +# +# Nothing configurable as of 1/2011 +# diff --git a/src/common/dummy-func.cpp b/src/common/dummy-func.cpp index 47250def3..e4ed350b2 100644 --- a/src/common/dummy-func.cpp +++ b/src/common/dummy-func.cpp @@ -5,10 +5,6 @@ -#ifndef LUMIERA_PLUGIN_PATH -#error please define the plugin search path as -DLUMIERA_PLUGIN_PATH, e.g. as $INSTALL_PREFIX/lib/lumiera -#endif - #include "common/dummy-func.hpp" @@ -35,19 +31,22 @@ namespace lumiera { using boost::regex_search; using boost::sregex_iterator; + typedef smatch::value_type const& SubMatch; + + + namespace fsys = boost::filesystem; namespace opt = boost::program_options; - + + namespace { // Implementation helpers const size_t STRING_MAX_RELEVANT = 1000; - const char * const BOOTSTRAP_INI = "$ORIGIN/setup.ini"; - const char * const GUI_MODULE_TO_LOAD = "gtk_gui.lum"; + const char * const BOOTSTRAP_INI = "$ORIGIN/config/setup.ini"; const char * const GET_PATH_TO_EXECUTABLE = "/proc/self/exe"; - regex EXTRACT_RELATIVE_PATHSPEC ("\\$?ORIGIN/([^:]+)"); - regex EXTRACT_PATHSPEC ("(\\$?ORIGIN)?([^:]+)"); + regex EXTRACT_PATHSPEC ("(\\$?ORIGIN/)?([^:]+)"); /** the real application would throw a custom exception... */ @@ -66,7 +65,7 @@ namespace lumiera { catchMyself () { static string buff(STRING_MAX_RELEVANT+1, '\0' ); - if (!buff.size()) + if (!buff[0]) { ssize_t chars_read = readlink (GET_PATH_TO_EXECUTABLE, &buff[0], STRING_MAX_RELEVANT); @@ -79,20 +78,16 @@ namespace lumiera { } - /** extract from the PLUGIN_PATH a path specification - * given relative to the location of the executable, - * as denoted by the 'ORIGIN' token - */ - string - getRelativeModuleLocation() - { - smatch match; - if (regex_search (string(LUMIERA_PLUGIN_PATH), match, EXTRACT_RELATIVE_PATHSPEC)) - return (match[1]); - else - dieHard ("no valid module loading location relative to executable defined in LUMIERA_PLUGIN_PATH"); - } + /** + * Helper: Access a path Specification as a sequence of filesystem Paths. + * This iterator class dissects a ':'-separated path list. The individual + * components may use the symbol \c $ORIGIN to denote the directory holding + * the current executable. After resolving this symbol, a valid absolute or + * relative filesystem path should result, which must not denote an existing + * file (directory is OK). + * @note #fetch picks the current component and advances the iteration. + */ class SearchPathSplitter : boost::noncopyable { @@ -100,25 +95,26 @@ namespace lumiera { end_; public: - SearchPathSplitter (string searchPath) + SearchPathSplitter (string const& searchPath) : pos_(searchPath.begin(),searchPath.end(), EXTRACT_PATHSPEC) , end_() { } bool - hasNext() + isValid() const { return pos_ != end_; } string - next() + fetch () { - ++pos_; - if (!hasNext()) + if (!isValid()) dieHard ("Search path exhausted."); - return resolveRelative(); + string currentPathElement = resolveRelative(); + ++pos_; + return currentPathElement; } private: @@ -133,7 +129,7 @@ namespace lumiera { return getFullPath(); } - smatch::value_type found(int group=0) { return (*pos_)[group]; } + SubMatch found(int group=0) { return (*pos_)[group]; } bool containsORIGINToken() { return found(1).matched; } string getRelativePath() { return found(2); } @@ -146,13 +142,13 @@ namespace lumiera { 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"); + dieHard ("Error in search path: component \""+modPathName.string()+"\" is not a directory"); - return modPathName.string(); + return modPathName.directory_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 @@ -174,22 +170,26 @@ namespace lumiera { } // try / continue search path - if (searchLocation.hasNext()) - modulePathName = fsys::path() / searchLocation.next() / moduleName; + if (searchLocation.isValid()) + modulePathName = fsys::path() / searchLocation.fetch() / moduleName; else dieHard ("Module \""+moduleName+"\" not found" + (searchPath.empty()? ".":" in search path: "+searchPath)); - } - } + } } + /** + * Encapsulate an INI-style configuration file. + * The acceptable settings are defined in the ctor. + * Implementation based on boost::program_options + */ class Config : boost::noncopyable { opt::options_description syntax; opt::variables_map settings; - + public: Config (string bootstrapIni) : syntax("Lumiera installation and platform configuration") @@ -203,8 +203,8 @@ namespace lumiera { "May us $ORIGIN to refer to the EXE location") ; - ifstream configIn (resolveModulePath (bootstrapIni).c_str()); - + ifstream configIn (resolve(bootstrapIni).c_str()); + opt::parsed_options parsed = opt::parse_config_file (configIn, syntax); @@ -218,6 +218,15 @@ namespace lumiera { { return settings[key].as(); } + + private: + string + resolve (fsys::path iniSpec) + { + string file = iniSpec.leaf(); + string searchpath = iniSpec.branch_path().string(); + return resolveModulePath (file, searchpath); + } }; }//(End) implementation helpers @@ -233,7 +242,7 @@ namespace lumiera { { Config appConfig(BOOTSTRAP_INI); string guiModule = appConfig["BuildsystemDemo.gui"]; - string moduleSearch = appConfig["BuildsystemDemo.modulepath"]; + string moduleSearch = appConfig["BuildsystemDemo.modulepath"]; string moduleLocation = resolveModulePath (guiModule, moduleSearch); void* handle = dlopen (moduleLocation.c_str(), RTLD_LAZY|RTLD_LOCAL); diff --git a/src/common/dummy-func.hpp b/src/common/dummy-func.hpp index d15383b88..43e43726a 100644 --- a/src/common/dummy-func.hpp +++ b/src/common/dummy-func.hpp @@ -20,6 +20,17 @@ namespace lumiera { * which attempts to load the "pseudo-gui" as shared module * and invoke the gui-main. The sole purpose of this function * is to demonstrate that the SCons build system is working. + * + * \par requirements + * While this isn't the actual implementation used in Lumiera, + * we try to mimic or demonstrate the techniques used to resolve + * the actual module to be loaded. So there are some requirements + * - \c $ORIGIN/config/setup.ini exists and defines... + * - a section [BuildsystemDemo], which holds + * - a setting gui = gtk_gui.lum + * - a module search path, typically: modulepath = $ORIGIN/modules + * Here the token \c $ORIGIN is automatically resolved to the directory + * holding the current executable, by reading the symlink \c /proc/self/exe */ void loadDummyGui();