Demonstration of complete bootstrap, loading INI and resolving GUI module path
This commit is contained in:
parent
a42e6a5a8f
commit
babbe33d1d
5 changed files with 86 additions and 45 deletions
|
|
@ -348,6 +348,7 @@ def defineBuildTargets(env, artifacts):
|
||||||
artifacts['corelib'] = core
|
artifacts['corelib'] = core
|
||||||
artifacts['support'] = lLib
|
artifacts['support'] = lLib
|
||||||
artifacts['lumiera'] = ( env.Program('lumiera', ['src/lumiera/main.cpp'], LIBS=core, install=True)
|
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')
|
+ env.ConfigData(env.path.srcConf+'dummy_lumiera.ini')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
/* This is an dummy Lumiera config file
|
# This is an dummy Lumiera config file
|
||||||
*
|
#
|
||||||
* Actually Lumiera can't yet load any config, as of 1/2011
|
# Actually Lumiera can't yet load any extended config, as of 1/2011
|
||||||
*/
|
#
|
||||||
|
|
|
||||||
20
data/config/setup.ini
Normal file
20
data/config/setup.ini
Normal file
|
|
@ -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
|
||||||
|
#
|
||||||
|
|
@ -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"
|
#include "common/dummy-func.hpp"
|
||||||
|
|
||||||
|
|
@ -35,19 +31,22 @@ namespace lumiera {
|
||||||
using boost::regex_search;
|
using boost::regex_search;
|
||||||
using boost::sregex_iterator;
|
using boost::sregex_iterator;
|
||||||
|
|
||||||
|
typedef smatch::value_type const& SubMatch;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace fsys = boost::filesystem;
|
namespace fsys = boost::filesystem;
|
||||||
namespace opt = boost::program_options;
|
namespace opt = boost::program_options;
|
||||||
|
|
||||||
|
|
||||||
namespace { // Implementation helpers
|
namespace { // Implementation helpers
|
||||||
|
|
||||||
const size_t STRING_MAX_RELEVANT = 1000;
|
const size_t STRING_MAX_RELEVANT = 1000;
|
||||||
|
|
||||||
const char * const BOOTSTRAP_INI = "$ORIGIN/setup.ini";
|
const char * const BOOTSTRAP_INI = "$ORIGIN/config/setup.ini";
|
||||||
const char * const GUI_MODULE_TO_LOAD = "gtk_gui.lum";
|
|
||||||
const char * const GET_PATH_TO_EXECUTABLE = "/proc/self/exe";
|
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... */
|
/** the real application would throw a custom exception... */
|
||||||
|
|
@ -66,7 +65,7 @@ namespace lumiera {
|
||||||
catchMyself ()
|
catchMyself ()
|
||||||
{
|
{
|
||||||
static string buff(STRING_MAX_RELEVANT+1, '\0' );
|
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);
|
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
|
class SearchPathSplitter
|
||||||
: boost::noncopyable
|
: boost::noncopyable
|
||||||
{
|
{
|
||||||
|
|
@ -100,25 +95,26 @@ namespace lumiera {
|
||||||
end_;
|
end_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SearchPathSplitter (string searchPath)
|
SearchPathSplitter (string const& searchPath)
|
||||||
: pos_(searchPath.begin(),searchPath.end(), EXTRACT_PATHSPEC)
|
: pos_(searchPath.begin(),searchPath.end(), EXTRACT_PATHSPEC)
|
||||||
, end_()
|
, end_()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
bool
|
bool
|
||||||
hasNext()
|
isValid() const
|
||||||
{
|
{
|
||||||
return pos_ != end_;
|
return pos_ != end_;
|
||||||
}
|
}
|
||||||
|
|
||||||
string
|
string
|
||||||
next()
|
fetch ()
|
||||||
{
|
{
|
||||||
++pos_;
|
if (!isValid())
|
||||||
if (!hasNext())
|
|
||||||
dieHard ("Search path exhausted.");
|
dieHard ("Search path exhausted.");
|
||||||
|
|
||||||
return resolveRelative();
|
string currentPathElement = resolveRelative();
|
||||||
|
++pos_;
|
||||||
|
return currentPathElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -133,7 +129,7 @@ namespace lumiera {
|
||||||
return getFullPath();
|
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; }
|
bool containsORIGINToken() { return found(1).matched; }
|
||||||
string getRelativePath() { return found(2); }
|
string getRelativePath() { return found(2); }
|
||||||
|
|
@ -146,13 +142,13 @@ namespace lumiera {
|
||||||
fsys::path modPathName (exePathName.remove_leaf() / getRelativePath());
|
fsys::path modPathName (exePathName.remove_leaf() / getRelativePath());
|
||||||
|
|
||||||
if (fsys::exists(modPathName) && !fsys::is_directory (modPathName))
|
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.
|
/** helper to establish the location to search for loadable modules.
|
||||||
* This is a simple demonstration of the basic technique used in the
|
* This is a simple demonstration of the basic technique used in the
|
||||||
* real application source to establish a plugin search path, based
|
* real application source to establish a plugin search path, based
|
||||||
|
|
@ -174,22 +170,26 @@ namespace lumiera {
|
||||||
}
|
}
|
||||||
|
|
||||||
// try / continue search path
|
// try / continue search path
|
||||||
if (searchLocation.hasNext())
|
if (searchLocation.isValid())
|
||||||
modulePathName = fsys::path() / searchLocation.next() / moduleName;
|
modulePathName = fsys::path() / searchLocation.fetch() / moduleName;
|
||||||
else
|
else
|
||||||
dieHard ("Module \""+moduleName+"\" not found"
|
dieHard ("Module \""+moduleName+"\" not found"
|
||||||
+ (searchPath.empty()? ".":" in search path: "+searchPath));
|
+ (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
|
class Config
|
||||||
: boost::noncopyable
|
: boost::noncopyable
|
||||||
{
|
{
|
||||||
opt::options_description syntax;
|
opt::options_description syntax;
|
||||||
opt::variables_map settings;
|
opt::variables_map settings;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Config (string bootstrapIni)
|
Config (string bootstrapIni)
|
||||||
: syntax("Lumiera installation and platform configuration")
|
: syntax("Lumiera installation and platform configuration")
|
||||||
|
|
@ -203,8 +203,8 @@ namespace lumiera {
|
||||||
"May us $ORIGIN to refer to the EXE location")
|
"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::parsed_options parsed =
|
||||||
opt::parse_config_file (configIn, syntax);
|
opt::parse_config_file (configIn, syntax);
|
||||||
|
|
@ -218,6 +218,15 @@ namespace lumiera {
|
||||||
{
|
{
|
||||||
return settings[key].as<string>();
|
return settings[key].as<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
string
|
||||||
|
resolve (fsys::path iniSpec)
|
||||||
|
{
|
||||||
|
string file = iniSpec.leaf();
|
||||||
|
string searchpath = iniSpec.branch_path().string();
|
||||||
|
return resolveModulePath (file, searchpath);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}//(End) implementation helpers
|
}//(End) implementation helpers
|
||||||
|
|
@ -233,7 +242,7 @@ namespace lumiera {
|
||||||
{
|
{
|
||||||
Config appConfig(BOOTSTRAP_INI);
|
Config appConfig(BOOTSTRAP_INI);
|
||||||
string guiModule = appConfig["BuildsystemDemo.gui"];
|
string guiModule = appConfig["BuildsystemDemo.gui"];
|
||||||
string moduleSearch = appConfig["BuildsystemDemo.modulepath"];
|
string moduleSearch = appConfig["BuildsystemDemo.modulepath"];
|
||||||
string moduleLocation = resolveModulePath (guiModule, moduleSearch);
|
string moduleLocation = resolveModulePath (guiModule, moduleSearch);
|
||||||
|
|
||||||
void* handle = dlopen (moduleLocation.c_str(), RTLD_LAZY|RTLD_LOCAL);
|
void* handle = dlopen (moduleLocation.c_str(), RTLD_LAZY|RTLD_LOCAL);
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,17 @@ namespace lumiera {
|
||||||
* which attempts to load the "pseudo-gui" as shared module
|
* which attempts to load the "pseudo-gui" as shared module
|
||||||
* and invoke the gui-main. The sole purpose of this function
|
* and invoke the gui-main. The sole purpose of this function
|
||||||
* is to demonstrate that the SCons build system is working.
|
* 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();
|
void loadDummyGui();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue