diff --git a/data/config/setup.ini b/data/config/setup.ini index e4a00f4e2..c1da6425b 100644 --- a/data/config/setup.ini +++ b/data/config/setup.ini @@ -4,17 +4,9 @@ # (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. +[Lumiera] +# Setup of the Lumiera video editor main application. +# $ORIGIN denotes the directory of the executable. # gui = gtk_gui.lum modulepath = $ORIGIN/modules - -[Lumiera] -# Lumiera video editor main application -# -# Nothing configurable as of 1/2011 -# diff --git a/src/common/appstate.cpp b/src/common/appstate.cpp index 391a550f7..c47dea849 100644 --- a/src/common/appstate.cpp +++ b/src/common/appstate.cpp @@ -41,6 +41,9 @@ extern "C" { using util::cStr; +#define LOCATION_OF_BOOTSTRAP_INI "$ORIGIN/config/setup.ini" + + namespace lumiera { @@ -60,7 +63,6 @@ namespace lumiera { LifecycleHook schedule_ (ON_BASIC_INIT, &createAppStateInstance); - lib::Literal GET_PATH_TO_EXECUTABLE ("/proc/self/exe"); } @@ -77,7 +79,8 @@ namespace lumiera { * client codes POV it just behaves like intended). */ AppState::AppState() - : subsystems_(0) + : setup_(LOCATION_OF_BOOTSTRAP_INI) + , subsystems_(0) , emergency_(false) , core_up_ (false) { } @@ -102,8 +105,8 @@ namespace lumiera { #define _THROW_IF \ - if (lumiera_error_peek()) \ - throw error::Fatal (lumiera_error()); + maybeThrow ("internal failure while initialising the "\ + "Lumiera application framework"); diff --git a/src/common/appstate.hpp b/src/common/appstate.hpp index 6472b5102..0f2a4ee14 100644 --- a/src/common/appstate.hpp +++ b/src/common/appstate.hpp @@ -21,7 +21,7 @@ */ /** @file appstate.hpp - ** Registering and managing some application-global services. + ** Registering and managing primary application-global services. ** This can be considered the "main" object of the Lumiera application ** Besides encapsulating the logic for starting up the fundamental parts ** of the application, there is a mechanism for registering \em subsystems @@ -30,6 +30,7 @@ ** callbacks) and provides the top-level catch-all error handling. ** ** @see LifecycleHook + ** @see BasicSetup ** @see Subsys ** @see main.cpp ** @see logging.h @@ -42,6 +43,7 @@ #include "lib/symbol.hpp" #include "common/option.hpp" #include "common/subsys.hpp" +#include "common/basic-setup.hpp" #include #include @@ -60,6 +62,7 @@ namespace lumiera { /** + * The Lumiera Application state and basic initialisation. * Singleton to hold global flags directing the overall application behaviour, * for triggering lifecycle events and performing early initialisation tasks. * AppState services are available already from static initialisation code. @@ -123,6 +126,8 @@ namespace lumiera { private: typedef scoped_ptr PSub; + BasicSetup setup_; + PSub subsystems_; bool emergency_; diff --git a/src/common/basic-setup.cpp b/src/common/basic-setup.cpp new file mode 100644 index 000000000..1492695c3 --- /dev/null +++ b/src/common/basic-setup.cpp @@ -0,0 +1,96 @@ +/* + BasicSetup - elementary self-configuration of the application + + Copyright (C) Lumiera.org + 2011, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "common/basic-setup.hpp" +#include "lib/searchpath.hpp" +#include "lib/error.hpp" +#include "lib/util.hpp" + +extern "C" { +#include +} +#include +#include +#include + + +namespace lumiera { + + using std::string; + using std::ifstream; + + namespace fsys = boost::filesystem; + namespace opt = boost::program_options; + + namespace { // details of the bootstrap process... + + + // Helper to locate a module using a search path spec + using lib::resolveModulePath; + + /** use the general mechanism for resolving a search path + * to get the absolute path of the \c setup.ini */ + string + resolve (fsys::path iniSpec) + { + string file = iniSpec.leaf(); + string searchpath = iniSpec.branch_path().string(); + return resolveModulePath (file, searchpath); + } + + }//(End) implementation details + + + + /** + * Creating the BasicSetup object performs the + * initial self-configuration of the Lumiera Application. + * For this, the \c setup.ini file is located relative to the + * current application executable, read in and parsed into a + * map of setup variables. + */ + BasicSetup::BasicSetup (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 (resolve(bootstrapIni).c_str()); + + + opt::parsed_options parsed = + opt::parse_config_file (configIn, syntax); + + opt::store (parsed, settings); + opt::notify(settings); + } + + + +} // namespace lumiera diff --git a/src/common/basic-setup.hpp b/src/common/basic-setup.hpp new file mode 100644 index 000000000..ec1759e3d --- /dev/null +++ b/src/common/basic-setup.hpp @@ -0,0 +1,88 @@ +/* + BASIC-SETUP.hpp - elementary self-configuration of the application + + Copyright (C) Lumiera.org + 2011, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +#ifndef COMMON_BASIC_SETUP_H +#define COMMON_BASIC_SETUP_H + +#include "lib/error.hpp" + +#include +#include +#include + + +namespace lumiera { + + using std::string; + + namespace opt = boost::program_options; + + + /** + * Represents the elementary self-configuration + * of a running Lumiera application instance. + * This basic setup is tied to the location of the + * Lumiera executable; from there the initial configuration + * locates a \c setup.ini to read in the fundamental settings. + * This is even prerequisite for loading any extension modules + * or reading in extended application configuration; usually + * this bootstrap process happens at or before the start of + * the \c main() function. Any failure leads to immediate + * termination of the application. + * + * \par WIP 2011 -- preliminary configuration solution + * The full-blown Configuration subsystem is just drafted + * and way from being usable. Thus we'll use this basic + * configuration as a replacement for the time being. + * + * @see configfacade.hpp + * @see AppState + */ + class BasicSetup + : boost::noncopyable + { + opt::options_description syntax; + opt::variables_map settings; + + public: + BasicSetup (string bootstrapIni); + + string + operator[] (string const& key) const + { + return settings[key].as(); + } + + opt::variable_value const& + get (string const& key) + { + return settings[key]; + } + + + private: + }; + + +} // namespace lumiera +#endif diff --git a/src/common/bootstrap.cpp b/src/common/bootstrap.cpp deleted file mode 100644 index 12eb75e01..000000000 --- a/src/common/bootstrap.cpp +++ /dev/null @@ -1,269 +0,0 @@ -/* - dummy-func.cpp - placeholder with dummy functions to demonstrate building/loading shared modules - -* *************************************************************************************************/ - - - - -#include "lib/error.hpp" -#include "common/bootstrap.hpp" - -extern "C" { -#include -} -#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; - - 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/config/setup.ini"; - const char * const GET_PATH_TO_EXECUTABLE = "/proc/self/exe"; - - regex EXTRACT_PATHSPEC ("(\\$?ORIGIN/)?([^:]+)"); - - - /** the real application would throw a custom exception... */ - void - dieHard (string msg) - { - NOBUG_ERROR (NOBUG_ON, "Fatal Error: %s ", msg.c_str()); - abort(); - } - - - /** figure out the absolute path - * of the currently running executable - */ - string - catchMyself () - { - static string buff(STRING_MAX_RELEVANT+1, '\0' ); - if (!buff[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); - } - return buff; - } - - - - /** - * 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 - { - sregex_iterator pos_, - end_; - - public: - SearchPathSplitter (string const& searchPath) - : pos_(searchPath.begin(),searchPath.end(), EXTRACT_PATHSPEC) - , end_() - { } - - bool - isValid() const - { - return pos_ != end_; - } - - string - fetch () - { - if (!isValid()) - dieHard ("Search path exhausted."); - - string currentPathElement = resolveRelative(); - ++pos_; - return currentPathElement; - } - - private: - /** maybe resolve a path spec given relative to - * the current Executable location ($ORIGIN) */ - string - resolveRelative () - { - if (containsORIGINToken()) - return asAbsolutePath(); - else - return getFullPath(); - } - - SubMatch 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 a directory"); - - 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 - * 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.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") - , 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 (resolve(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(); - } - - private: - string - resolve (fsys::path iniSpec) - { - string file = iniSpec.leaf(); - string searchpath = iniSpec.branch_path().string(); - return resolveModulePath (file, searchpath); - } - }; - - }//(End) implementation helpers - - - - - - - - void - loadDummyGui() - { - 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) - { - typedef void (*VoidFunc)(void); - - VoidFunc entryPoint = (VoidFunc) dlsym (handle, "start_dummy_gui"); - - if (!entryPoint) - dieHard ("unable to resolve the entry point symbol after loading the GUI module."); - - else - (*entryPoint) (); // activate loaded module - } - else - dieHard ("unable to load "+moduleLocation); - } - - - - -} // namespace lumiera diff --git a/src/common/bootstrap.hpp b/src/common/bootstrap.hpp deleted file mode 100644 index aa2a41f0b..000000000 --- a/src/common/bootstrap.hpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - dummy-func.hpp - placeholder with dummy functions to demonstrate building shared modules - -* ******************************************************************************************/ - - -#ifndef COMMON_DUMMY_FUNC_H -#define COMMON_DUMMY_FUNC_H - -#include - - -namespace lumiera { - - using std::string; - - /** 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 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(); - - -} // namespace lumiera -#endif diff --git a/src/common/option.hpp b/src/common/option.hpp index 012844ea3..1d706e5d5 100644 --- a/src/common/option.hpp +++ b/src/common/option.hpp @@ -51,7 +51,8 @@ namespace lumiera { * vector will contain only the remaining * unrecognised parts. */ - class Option : private boost::noncopyable + class Option + : boost::noncopyable { public: Option (lib::Cmdline& cmdline); diff --git a/src/lib/searchpath.cpp b/src/lib/searchpath.cpp index 02f9f2e0a..809cc4889 100644 --- a/src/lib/searchpath.cpp +++ b/src/lib/searchpath.cpp @@ -26,25 +26,22 @@ #include "lib/symbol.hpp" +/** how to retrieve the absolute path of the currently running executable + * on a Linux system: read the link provided by the kernel through /proc + */ +#define GET_PATH_TO_EXECUTABLE "/proc/self/exe" + + + namespace lib { - LUMIERA_ERROR_DEFINE (FILE_NOT_DIRECTORY, "path element points at a file instead of a directory"); - - namespace { - - Literal GET_PATH_TO_EXECUTABLE ("/proc/self/exe"); - } - - regex SearchPathSplitter::EXTRACT_PATHSPEC ("(\\$?ORIGIN/)?([^:]+)"); - - /** @internal helper to figure out the installation directory, * as given by the absolute path of the currently executing program * @warning this is Linux specific code */ diff --git a/src/tool/try.cpp b/src/tool/try.cpp index 01a99925b..bdfca7100 100644 --- a/src/tool/try.cpp +++ b/src/tool/try.cpp @@ -30,21 +30,19 @@ extern "C" { #include } -//#include "lib/error.hpp" -//#include "lib/symbol.hpp" +#include "lib/error.hpp" +#include "lib/symbol.hpp" using std::string; using std::cout; using std::endl; -//using lib::Literal; -//using lib::STRING_MAX_RELEVANT; -const size_t STRING_MAX_RELEVANT = 1000; +using lib::Literal; +using lib::STRING_MAX_RELEVANT; -//namespace error = lumiera::error; +namespace error = lumiera::error; -//Literal GET_PATH_TO_EXECUTABLE ("/proc/self/exe"); -const char * const GET_PATH_TO_EXECUTABLE ("/proc/self/exe"); +Literal GET_PATH_TO_EXECUTABLE ("/proc/self/exe"); string catchMyself () @@ -53,8 +51,7 @@ catchMyself () 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)) -// throw error::Fatal ("unable to discover path of running executable") - throw string("unable to discover path of running executable"); + throw error::Fatal ("unable to discover path of running executable"); buff.resize(chars_read); return buff; diff --git a/tests/lib/search-path-splitter-test.cpp b/tests/lib/search-path-splitter-test.cpp index e4e824090..bd58190e3 100644 --- a/tests/lib/search-path-splitter-test.cpp +++ b/tests/lib/search-path-splitter-test.cpp @@ -25,7 +25,6 @@ #include "lib/test/test-helper.hpp" #include "lib/searchpath.hpp" -#include "common/appstate.hpp" #include