Demonstration how the application could resolve the module loading location
The real application likely will consult the configuration file to search alternative module installation locations.
This commit is contained in:
parent
29e2233e6a
commit
208b552955
3 changed files with 122 additions and 16 deletions
12
SConstruct
12
SConstruct
|
|
@ -104,8 +104,8 @@ def setupBasicEnvironment(localDefinitions):
|
||||||
appendVal(env,'DEBUG', 'CCFLAGS', val=' -ggdb')
|
appendVal(env,'DEBUG', 'CCFLAGS', val=' -ggdb')
|
||||||
|
|
||||||
# setup search path for Lumiera plugins
|
# setup search path for Lumiera plugins
|
||||||
appendCppDefine(env,'PKGLIBDIR','LUMIERA_PLUGIN_PATH=\\"$PKGLIBDIR/:./modules\\"'
|
appendCppDefine(env,'PKGLIBDIR','LUMIERA_PLUGIN_PATH=\\"$PKGLIBDIR/:ORIGIN/modules\\"'
|
||||||
,'LUMIERA_PLUGIN_PATH=\\"$DESTDIR/lib/lumiera/:./modules\\"')
|
,'LUMIERA_PLUGIN_PATH=\\"ORIGIN/modules\\"')
|
||||||
appendCppDefine(env,'PKGDATADIR','LUMIERA_CONFIG_PATH=\\"$PKGLIBDIR/:.\\"'
|
appendCppDefine(env,'PKGDATADIR','LUMIERA_CONFIG_PATH=\\"$PKGLIBDIR/:.\\"'
|
||||||
,'LUMIERA_CONFIG_PATH=\\"$DESTDIR/share/lumiera/:.\\"')
|
,'LUMIERA_CONFIG_PATH=\\"$DESTDIR/share/lumiera/:.\\"')
|
||||||
|
|
||||||
|
|
@ -248,10 +248,14 @@ def configurePlatform(env):
|
||||||
if not conf.CheckCXXHeader('boost/config.hpp'):
|
if not conf.CheckCXXHeader('boost/config.hpp'):
|
||||||
problems.append('We need the C++ boost-libraries.')
|
problems.append('We need the C++ boost-libraries.')
|
||||||
else:
|
else:
|
||||||
if not conf.CheckCXXHeader('boost/shared_ptr.hpp'):
|
if not conf.CheckCXXHeader('boost/scoped_ptr.hpp'):
|
||||||
problems.append('We need boost::shared_ptr (shared_ptr.hpp).')
|
problems.append('We need boost::scoped_ptr (scoped_ptr.hpp).')
|
||||||
|
if not conf.CheckCXXHeader('boost/format.hpp'):
|
||||||
|
problems.append('We need boost::format (header).')
|
||||||
if not conf.CheckLibWithHeader('boost_program_options-mt','boost/program_options.hpp','C++'):
|
if not conf.CheckLibWithHeader('boost_program_options-mt','boost/program_options.hpp','C++'):
|
||||||
problems.append('We need boost::program_options (including binary lib for linking).')
|
problems.append('We need boost::program_options (including binary lib for linking).')
|
||||||
|
if not conf.CheckLibWithHeader('boost_filesystem-mt','boost/filesystem.hpp','C++'):
|
||||||
|
problems.append('We need the boost::filesystem (including binary lib for linking).')
|
||||||
if not conf.CheckLibWithHeader('boost_regex-mt','boost/regex.hpp','C++'):
|
if not conf.CheckLibWithHeader('boost_regex-mt','boost/regex.hpp','C++'):
|
||||||
problems.append('We need the boost regular expression lib (incl. binary lib for linking).')
|
problems.append('We need the boost regular expression lib (incl. binary lib for linking).')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,42 +1,129 @@
|
||||||
/*
|
/*
|
||||||
dummy-func.cpp - placeholder with dummy functions to demonstrate building shared modules
|
dummy-func.cpp - placeholder with dummy functions to demonstrate building/loading shared modules
|
||||||
|
|
||||||
* ******************************************************************************************/
|
* *************************************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#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"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <unistd.h>
|
||||||
|
}
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <nobug.h>
|
#include <nobug.h>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <boost/regex.hpp>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
namespace lumiera {
|
namespace lumiera {
|
||||||
|
|
||||||
const char * const GUI_MODULE_NAME = "modules/gtk_gui.lum";
|
|
||||||
|
|
||||||
typedef void (*VoidFunc)(void);
|
using std::string;
|
||||||
|
using boost::regex;
|
||||||
|
using boost::smatch;
|
||||||
|
using boost::regex_search;
|
||||||
|
|
||||||
|
namespace fsys = boost::filesystem;
|
||||||
|
|
||||||
|
namespace { // Implementation helpers
|
||||||
|
|
||||||
|
const size_t STRING_MAX_RELEVANT = 1000;
|
||||||
|
|
||||||
|
const char * const GUI_MODULE_TO_LOAD = "gtk_gui";
|
||||||
|
const char * const GET_PATH_TO_EXECUTABLE = "/proc/self/exe";
|
||||||
|
|
||||||
|
regex EXTRACT_RELATIVE_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 ()
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
return buff;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** 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");
|
||||||
|
}
|
||||||
|
}//(End) implementation helpers
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
loadDummyGui()
|
loadDummyGui()
|
||||||
{
|
{
|
||||||
void* handle = dlopen (GUI_MODULE_NAME, RTLD_LAZY|RTLD_LOCAL);
|
string moduleLocation = resolveModulePath (GUI_MODULE_TO_LOAD);
|
||||||
|
|
||||||
|
void* handle = dlopen (moduleLocation.c_str(), RTLD_LAZY|RTLD_LOCAL);
|
||||||
if (handle)
|
if (handle)
|
||||||
{
|
{
|
||||||
|
typedef void (*VoidFunc)(void);
|
||||||
|
|
||||||
VoidFunc entryPoint = (VoidFunc) dlsym (handle, "start_dummy_gui");
|
VoidFunc entryPoint = (VoidFunc) dlsym (handle, "start_dummy_gui");
|
||||||
|
|
||||||
if (!entryPoint)
|
if (!entryPoint)
|
||||||
ERROR (lumiera, "unable to resolve the entry point symbol after loading the GUI module.");
|
dieHard ("unable to resolve the entry point symbol after loading the GUI module.");
|
||||||
|
|
||||||
else
|
else
|
||||||
(*entryPoint) ();
|
(*entryPoint) (); // activate loaded module
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ERROR (lumiera, "unable to load %s", GUI_MODULE_NAME);
|
dieHard ("unable to load "+moduleLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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
|
} // namespace lumiera
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,18 @@
|
||||||
* ******************************************************************************************/
|
* ******************************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef COMMON_DUMMY_FUNC_H
|
||||||
|
#define COMMON_DUMMY_FUNC_H
|
||||||
|
|
||||||
#include "include/nobugcfg.h"
|
#include "include/nobugcfg.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
namespace lumiera {
|
namespace lumiera {
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
/** this is a function located in the liblumieracore.so,
|
/** this is a function located in the liblumieracore.so,
|
||||||
* 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
|
||||||
|
|
@ -16,5 +23,13 @@ namespace lumiera {
|
||||||
*/
|
*/
|
||||||
void loadDummyGui();
|
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
|
} // namespace lumiera
|
||||||
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue