← Back to team overview

yade-dev team mailing list archive

[Branch ~yade-dev/yade/trunk] Rev 1849: 1. Add YADE_LINK_EXTRA_LIB so that plugin can request to be linked with additional library (used ...

 

------------------------------------------------------------
revno: 1849
committer: Václav Šmilauer <eudoxos@xxxxxxxx>
branch nick: trunk
timestamp: Thu 2009-12-03 21:57:11 +0100
message:
  1. Add YADE_LINK_EXTRA_LIB so that plugin can request to be linked with additional library (used in MicroMacroAnalyser)
  2. Add -frounding-math when compiling with CGAL
  3. Lot of reorganization of python code. Yade is now fully usable (it seems) with the python main (yade-trunk-py), and also lodable from pure python
removed:
  gui/py/__init__.py
added:
  py/__init__.py.in
  py/config.py.in
modified:
  SConstruct
  core/Omega.cpp
  core/Omega.hpp
  core/main/main.py.in
  core/main/pyboot.cpp
  extra/SConscript
  gui/SConscript
  gui/py/PythonUI.cpp
  gui/py/PythonUI_rc.py
  gui/py/ipython.py
  gui/qt3/qt.py
  lib/factory/ClassFactory.hpp
  pkg/dem/Engine/StandAloneEngine/MicroMacroAnalyser.cpp
  py/SConscript
  py/system.py
  py/tests/wrapper.py
  py/yadeWrapper/yadeWrapper.cpp
  yadeSCons.py


--
lp:yade
https://code.launchpad.net/~yade-dev/yade/trunk

Your team Yade developers is subscribed to branch lp:yade.
To unsubscribe from this branch go to https://code.launchpad.net/~yade-dev/yade/trunk/+edit-subscription.
=== modified file 'SConstruct'
--- SConstruct	2009-12-01 22:24:00 +0000
+++ SConstruct	2009-12-03 20:57:11 +0000
@@ -374,6 +374,7 @@
 		if not ok: featureNotOK('log4cxx')
 	if 'cgal' in env['features']:
 		ok=conf.CheckLibWithHeader('CGAL','CGAL/Exact_predicates_inexact_constructions_kernel.h','c++','CGAL::Exact_predicates_inexact_constructions_kernel::Point_3();')
+		env.Append(CXXFLAGS='-frounding-math') # required by cgal, otherwise we get assertion failure at startup
 		if not ok: featureNotOK('cgal')
 	if env['useMiniWm3']: env.Append(LIBS='miniWm3',CPPDEFINES=['MINIWM3'])
 

=== modified file 'core/Omega.cpp'
--- core/Omega.cpp	2009-12-01 22:24:00 +0000
+++ core/Omega.cpp	2009-12-03 20:57:11 +0000
@@ -181,41 +181,49 @@
 	return (dynlibs[className].baseClasses.find(baseClassName)!=dynlibs[className].baseClasses.end());
 }
 
+void Omega::loadPlugins(vector<string> pluginFiles){
+	FOREACH(const string& plugin, pluginFiles){
+		LOG_DEBUG("Loading plugin "<<plugin);
+		if(!ClassFactory::instance().load(plugin)){
+			string err=ClassFactory::instance().lastError();
+			if(err.find(": undefined symbol: ")!=std::string::npos){
+				size_t pos=err.rfind(":");	assert(pos!=std::string::npos);
+				std::string sym(err,pos+2); //2 removes ": " from the beginning
+				int status=0; char* demangled_sym=abi::__cxa_demangle(sym.c_str(),0,0,&status);
+				LOG_FATAL(plugin<<": undefined symbol `"<<demangled_sym<<"'"); LOG_FATAL(plugin<<": "<<err); LOG_FATAL("Bailing out.");
+			}
+			else {
+				LOG_FATAL(plugin<<": "<<err<<" ."); /* leave space to not to confuse c++filt */ LOG_FATAL("Bailing out.");
+			}
+			abort();
+		}
+	}
+	list<string>& plugins(ClassFactory::instance().pluginClasses);
+	plugins.sort(); plugins.unique();
+	buildDynlibDatabase(vector<string>(plugins.begin(),plugins.end()));
+}
+
 void Omega::scanPlugins(vector<string> baseDirs){
-	// silently skip non-existent plugin directories
+	vector<string> pluginFiles;
 	FOREACH(const string& baseDir, baseDirs){
+		// silently skip non-existent plugin directories
 		if(!filesystem::exists(baseDir)) continue;
 		try{
 			filesystem::recursive_directory_iterator Iend;
 			for(filesystem::recursive_directory_iterator I(baseDir); I!=Iend; ++I){ 
 				filesystem::path pth=I->path();
 				if(filesystem::is_directory(pth) || !algorithm::starts_with(pth.leaf(),"lib") || !algorithm::ends_with(pth.leaf(),".so")) { LOG_DEBUG("File not considered a plugin: "<<pth.leaf()<<"."); continue; }
-				LOG_DEBUG("Trying "<<pth.leaf());
 				filesystem::path name(filesystem::basename(pth));
 				if(name.leaf().length()<1) continue; // filter out 0-length filenames
-				string plugin=name.leaf();
-				if(!ClassFactory::instance().load(pth.string())){
-					string err=ClassFactory::instance().lastError();
-					if(err.find(": undefined symbol: ")!=std::string::npos){
-						size_t pos=err.rfind(":");	assert(pos!=std::string::npos);
-						std::string sym(err,pos+2); //2 removes ": " from the beginning
-						int status=0; char* demangled_sym=abi::__cxa_demangle(sym.c_str(),0,0,&status);
-						LOG_FATAL(plugin<<": undefined symbol `"<<demangled_sym<<"'"); LOG_FATAL(plugin<<": "<<err); LOG_FATAL("Bailing out.");
-					}
-					else {
-						LOG_FATAL(plugin<<": "<<err<<" ."); /* leave space to not to confuse c++filt */ LOG_FATAL("Bailing out.");
-					}
-					abort();
-				}
+				LOG_DEBUG("Will load plugin "<<pth.leaf());
+				pluginFiles.push_back(pth.string());
 			}
 		} catch(filesystem::basic_filesystem_error<filesystem::path>& e) {
 			LOG_FATAL("Error from recursive plugin directory scan (unreadable directory?): "<<e.what());
 			throw;
 		}
 	}
-	list<string>& plugins(ClassFactory::instance().pluginClasses);
-	plugins.sort(); plugins.unique();
-	buildDynlibDatabase(vector<string>(plugins.begin(),plugins.end()));
+	loadPlugins(pluginFiles);
 }
 
 void Omega::loadSimulationFromStream(std::istream& stream){

=== modified file 'core/Omega.hpp'
--- core/Omega.hpp	2009-12-01 14:56:39 +0000
+++ core/Omega.hpp	2009-12-03 20:57:11 +0000
@@ -127,6 +127,7 @@
 
 		const		map<string,DynlibDescriptor>& getDynlibsDescriptor();
 		void		scanPlugins(vector<string> baseDirs);
+		void		loadPlugins(vector<string> pluginFiles);
 		bool		isInheritingFrom(const string& className, const string& baseClassName );
 
 		void		setTimeStep(const Real);

=== modified file 'core/main/main.py.in'
--- core/main/main.py.in	2009-12-02 23:01:36 +0000
+++ core/main/main.py.in	2009-12-03 20:57:11 +0000
@@ -2,84 +2,67 @@
 # encoding: utf-8
 # syntax:python
 
-import sys,ctypes
-try:
-	import dl
-except ImportError:
-	import DLFCN as dl
-# see file:///usr/share/doc/python2.6/html/library/sys.html#sys.setdlopenflags
-# and various web posts on the topic, e.g.
-# * http://gcc.gnu.org/faq.html#dso
-# * http://www.code-muse.com/blog/?p=58
-# * http://wiki.python.org/moin/boost.python/CrossExtensionModuleDependencies
-sys.setdlopenflags(dl.RTLD_NOW | dl.RTLD_GLOBAL)
-# important: initialize c++ by importing libstdc++ directly
-# see http://www.abclinuxu.cz/poradna/programovani/show/286322
-# https://bugs.launchpad.net/bugs/490744
-libstdcxx='${libstdcxx}' # substituted by scons
-ctypes.cdll.LoadLibrary(libstdcxx)
-
-
-
-# find what is our version, based on argv[0]
-# should be improved
-import sys,re,os,os.path
-m=re.match('(.*)/bin/yade(-.*)-py',sys.argv[0])
-if not m: raise RuntimeError("Unable to find prefix and yade version from argv[0]=='%s'."%sys.argv[0])
-prefix,suffix=m.group(1),m.group(2)
-libDir=prefix+'/lib/yade'+suffix
-pluginDirs=[libDir+dir for dir in ('','/plugins','/gui','/extra') if os.path.exists(libDir+dir)]
-sys.path.append(libDir+'/py')
-
-# this works, cool!
-## os.environ['OMP_NUM_THREADS']=str(1)
-
-# now we can import yade's c++ modules just fine
-import yade.boot
-yade.boot.initialize(pluginDirs,True)
-
-from math import *
-from yade.wrapper import *
-from miniWm3Wrap import *
-from yade._customConverters import *
-from yade import runtime
-from yade import utils
-
-# get some scons things here
-runtime.features='${features}'.split(',') # substituted by scons
-
-runtime.prefix,runtime.suffix=prefix,suffix
-runtime.argv=sys.argv
-# todo
-runtime.stopAfter=False
-# todo
-runtime.nonInteractive=False
-# todo
-runtime.simulation=''
-runtime.script=''
-for arg in sys.argv:
-	if arg.endswith('.xml') or arg.endswith('.xml.bz2'): runtime.simulation=arg
-	elif arg.endswith('.py'): runtime.script=arg
-
+import sys,os,os.path
+# get yade path (allow YADE_PREFIX to override)
+prefix,suffix='${PREFIX}' if not os.environ.has_key('YADE_PREFIX') else os.environ('YADE_PREFIX'),'${SUFFIX}'
+sys.path.append(os.path.join(prefix,'lib','yade'+suffix,'py'))
+
+# initialization and c++ plugins import
+import yade
+# other parts we will need soon
+import yade.config
+import yade.wrapper
+import yade.log
+
+
+# handle command-line options first
+import optparse
+par=optparse.OptionParser(usage='%prog [options] [ simulation.xml[.bz2] | script.py [script options]]',prog='Yade',version='%s (%s)'%(yade.config.version,','.join(yade.config.features)))
+par.add_option('-j','--threads',help='Number of OpenMP threads to run; defaults to number of cores.',dest='threads',type='int')
+par.add_option('-x',help='Exit when the script finishes',dest='exitAfter')
+if 'log4cxx' in yade.config.features:
+	par.add_option('-v',help='Increase logging verbosity; first occurence sets default logging level to info, second to debug, third to trace.',action='count',dest='verbosity')
+if yade.config.debug:
+	par.add_option('--no-gdb',help='Do not show backtrace when yade crashes.',dest='noGdb',action='store_true',)
+
+opts,args=par.parse_args()
+
+if opts.threads:
+	os.environ['OMP_NUM_THREADS']=str(opts.threads)
+if yade.config.debug and opts.noGdb:
+	yade.wrapper.Omega().disableGdb()
+if 'log4cxx' in yade.config.features and opts.verbosity:
+	yade.log.setLevel([yade.log.INFO,yade.log.DEBUG,yade.log.TRACE][min(opts.verbosity,3)])
+
+# open GUI if possible
 try:
 	import yade.qt
 	yade.qt.Controller()
 except ImportError: pass
-#
-# this fills __builtins__ with wrapped types and proxy classes; it could be factored out, though
-#
-execfile(prefix+'/lib/yade'+suffix+'/gui/PythonUI_rc.py')
-
-
-#setupPythonRuntime()
-
-#sys.argv[0]='<embedded python interpreter>'
-if 0:
-	if 0:
+
+# be nice to users
+from math import *
+from miniWm3Wrap import *
+
+# something to run?
+if len(args)>0:
+	if args[0].endswith('.xml') or args[0].endswith('.xml.bz2'):
+		if len(args)>1: raise RuntimeError('Extra arguments to XML simulation to run: '+' '.join(args[1:]))
+		print "Running simulation "+args[0]
+		O=yade.wrapper.Omega(); O.load(args[0]); O.run()
+	if args[0].endswith('.py'):
+		print "Running script "+args[0]
+		yade.runtime.argv=args[1:]
+		execfile(args[0])
+		if opts.exitAfter: sys.exit(0)
+
+# show python command-line
+if 1:
+	if 1:
 		from IPython.Shell import IPShellEmbed
-		ipshell=IPShellEmbed(exit_msg='Bye.',rc_override={'execfile':[runtime.prefix+'/lib/yade'+runtime.suffix+'/py/yade/ipython.py']})
+		ipshell=IPShellEmbed(exit_msg='Bye.',rc_override={'execfile':[prefix+'/lib/yade'+suffix+'/py/yade/ipython.py']})
 		ipshell()
 	else:
 		import bpython
 		bpython.embed()
-
+O.exitNoBacktrace()

=== modified file 'core/main/pyboot.cpp'
--- core/main/pyboot.cpp	2009-12-02 23:01:36 +0000
+++ core/main/pyboot.cpp	2009-12-03 20:57:11 +0000
@@ -11,7 +11,20 @@
 #include<boost/python.hpp>
 
 #ifdef YADE_LOG4CXX
-	log4cxx::LoggerPtr logger=log4cxx::Logger::getLogger("yade.python");
+	log4cxx::LoggerPtr logger=log4cxx::Logger::getLogger("yade.boot");
+	/* initialize here so that ClassFactory can use log4cxx without warnings */
+	__attribute__((constructor)) void initLog4cxx() {
+		#ifdef LOG4CXX_TRACE
+			log4cxx::LevelPtr debugLevel=log4cxx::Level::getDebug(), infoLevel=log4cxx::Level::getInfo(), warnLevel=log4cxx::Level::getWarn();
+		#else
+			log4cxx::LevelPtr debugLevel=log4cxx::Level::DEBUG, infoLevel=log4cxx::Level::INFO, warnLevel=log4cxx::Level::WARN;
+		#endif
+
+		log4cxx::BasicConfigurator::configure();
+		log4cxx::LoggerPtr localLogger=log4cxx::Logger::getLogger("yade");
+		localLogger->setLevel(getenv("YADE_DEBUG")?debugLevel:warnLevel);
+		LOG4CXX_DEBUG(localLogger,"Log4cxx initialized.");
+	}
 #endif
 
 #ifdef YADE_DEBUG
@@ -28,19 +41,8 @@
 	}		
 #endif
 
-/* Initialize yade, scan given directories for plugins and load them */
-void yadeInitialize(python::list& dd, bool gdb){
-	#ifdef YADE_LOG4CXX
-		#ifdef LOG4CXX_TRACE
-			log4cxx::LevelPtr debugLevel=log4cxx::Level::getDebug(), infoLevel=log4cxx::Level::getInfo(), warnLevel=log4cxx::Level::getWarn();
-		#else
-			log4cxx::LevelPtr debugLevel=log4cxx::Level::DEBUG, infoLevel=log4cxx::Level::INFO, warnLevel=log4cxx::Level::WARN;
-		#endif
-
-		log4cxx::BasicConfigurator::configure();
-		log4cxx::LoggerPtr localLogger=log4cxx::Logger::getLogger("yade");
-		localLogger->setLevel(getenv("YADE_DEBUG")?debugLevel:warnLevel);
-	#endif
+/* Initialize yade, loading given plugins */
+void yadeInitialize(python::list& pp){
 
 	PyEval_InitThreads();
 
@@ -49,23 +51,18 @@
 	O.origArgv=NULL; O.origArgc=0; // not needed, anyway
 	O.initTemps();
 	#ifdef YADE_DEBUG
-		if(gdb){
-			ofstream gdbBatch;
-			O.gdbCrashBatch=O.tmpFilename();
-			gdbBatch.open(O.gdbCrashBatch.c_str()); gdbBatch<<"attach "<<lexical_cast<string>(getpid())<<"\nset pagination off\nthread info\nthread apply all backtrace\ndetach\nquit\n"; gdbBatch.close();
-			signal(SIGABRT,crashHandler);
-			signal(SIGSEGV,crashHandler);
-		}
+		ofstream gdbBatch;
+		O.gdbCrashBatch=O.tmpFilename();
+		gdbBatch.open(O.gdbCrashBatch.c_str()); gdbBatch<<"attach "<<lexical_cast<string>(getpid())<<"\nset pagination off\nthread info\nthread apply all backtrace\ndetach\nquit\n"; gdbBatch.close();
+		signal(SIGABRT,crashHandler);
+		signal(SIGSEGV,crashHandler);
 	#endif
-	vector<string> dd2; for(int i=0; i<python::len(dd); i++) dd2.push_back(python::extract<string>(dd[i]));
-	//TODO: call Omega::instance().buildDynlibDatabase(dd2); and scan directories for plugins in the python boot part (gets rid of ugly Omega code once no c++ main exists)
-	Omega::instance().scanPlugins(dd2);
+	vector<string> ppp; for(int i=0; i<python::len(pp); i++) ppp.push_back(python::extract<string>(pp[i]));
+	Omega::instance().loadPlugins(ppp);
 }
 void yadeFinalize(){ Omega::instance().cleanupTemps(); }
 
 BOOST_PYTHON_MODULE(boot){
-	// FIXME: still a crasher with openmp or OpenGL...
-	// cerr<<"[boot]"<<endl;
 	python::scope().attr("initialize")=&yadeInitialize;
 	python::scope().attr("finalize")=&yadeFinalize; //,"Finalize yade (only to be used internally).")
 }

=== modified file 'extra/SConscript'
--- extra/SConscript	2009-11-25 21:21:17 +0000
+++ extra/SConscript	2009-12-03 20:57:11 +0000
@@ -10,3 +10,21 @@
 ])
 
 
+
+if 'cgal' in env['features']:
+	# TesselationWrapper is library compiled here, but is required by MicroMacroAnalyser in pkg/dem.
+	# Because there is no way to compile non-plugin library in pkg/, it is compiled here and
+	# YADE_LINK_EXTRA_LIB is used in MicroMacroAnalyser.cpp to declare the dependency.
+	#
+	# It also means however, that if you have exclude='extra', then TesselationWrapper will not be built
+	# and linking of microMacroAnalyser will fail. Keep that in mind.
+	#
+	# Best place for TesselationWrapper would in lib/, same as e.g. lib/import/ which contains routines
+	# for STL import used by the importer.
+	#
+	env.Install('$PREFIX/lib/yade$SUFFIX/extra',[
+		env.SharedLibrary('TesselationWrapper',env.Combine('TesselationWrapperAll.cpp',Split('triangulation/KinematicLocalisationAnalyser.cpp triangulation/Operations.cpp triangulation/RegularTriangulation.cpp triangulation/stdafx.cpp triangulation/Tenseur3.cpp triangulation/Tesselation.cpp triangulation/TesselationWrapper.cpp triangulation/test.cpp triangulation/TriaxialState.cpp'))),
+	])
+
+
+

=== modified file 'gui/SConscript'
--- gui/SConscript	2009-11-29 11:03:25 +0000
+++ gui/SConscript	2009-12-03 20:57:11 +0000
@@ -50,7 +50,6 @@
 # these modules will not be imported directly (probably)
 # the rest was moved to py/ directory
 env.Install('$PREFIX/lib/yade$SUFFIX/py/yade',[
-	env.File('__init__.py','py'),
 	env.File('runtime.py','py'),
 	env.File('ipython.py','py'),
 	env.File('PythonTCPServer.py','py'),

=== modified file 'gui/py/PythonUI.cpp'
--- gui/py/PythonUI.cpp	2009-11-15 09:32:52 +0000
+++ gui/py/PythonUI.cpp	2009-12-03 20:57:11 +0000
@@ -117,7 +117,7 @@
 			// wrap those in python::handle<> ??
 			PYTHON_DEFINE_STRING("prefix",prefix);
 			PYTHON_DEFINE_STRING("suffix",SUFFIX);
-			PYTHON_DEFINE_STRING("executable",Omega::instance().origArgv[0]);
+			if(Omega::instance().origArgv) PYTHON_DEFINE_STRING("executable",Omega::instance().origArgv[0]);
 			PYTHON_DEFINE_STRING("simulation",Omega::instance().getSimulationFileName());
 			PYTHON_DEFINE_STRING("script",runScript);
 			PYTHON_DEFINE_RAW("features",features);

=== modified file 'gui/py/PythonUI_rc.py'
--- gui/py/PythonUI_rc.py	2009-12-02 23:01:36 +0000
+++ gui/py/PythonUI_rc.py	2009-12-03 20:57:11 +0000
@@ -12,8 +12,6 @@
 from yade import utils
 
 import yade.system
-yade.system.setExitHandlers()
-yade.system.injectCtors()
 yade.system.runServers()
 
 
@@ -53,13 +51,14 @@
 		else:
 			sys.argv[0]='<embedded python interpreter>'
 			from IPython.Shell import IPShellEmbed
-			ipshell = IPShellEmbed(banner=r"""
+			banner=r"""
 		__   __    ____          ____                      _      
 		\ \ / /_ _|  _ \  ___   / ___|___  _ __  ___  ___ | | ___ 
 		 \ V / _` | | | |/ _ \ | |   / _ \| '_ \/ __|/ _ \| |/ _ \ 
 		  | | (_| | |_| |  __/ | |__| (_) | | | \__ \ (_) | |  __/
 		  |_|\__,_|____/ \___|  \____\___/|_| |_|___/\___/|_|\___|
-		""",exit_msg='Bye.'
+		"""
+			ipshell = IPShellEmbed(banner='',exit_msg=None
 			,rc_override={'execfile':[runtime.prefix+'/lib/yade'+runtime.suffix+'/py/yade/ipython.py']})
 
 			ipshell()

=== removed file 'gui/py/__init__.py'
--- gui/py/__init__.py	2008-05-01 06:29:44 +0000
+++ gui/py/__init__.py	1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
-# The purpose of this file is twofold: 
-# 1. it tells python that yade (this directory) is package of python modules
-#	see http://http://www.python.org/doc/2.1.3/tut/node8.html#SECTION008400000000000000000
-#
-# 2. import the runtime namespace (will be populated from within c++
-#
-import runtime # will appear as yade.runtime in the global namespace

=== modified file 'gui/py/ipython.py'
--- gui/py/ipython.py	2009-11-13 11:27:22 +0000
+++ gui/py/ipython.py	2009-12-03 20:57:11 +0000
@@ -18,4 +18,12 @@
 import IPython.ipapi
 ip=IPython.ipapi.get()
 ip.set_hook('complete_command',yade_completers,re_key='.*\\b[a-zA-Z0-9_]+\[["\'][^"\'\]]*$')
+
+o=ip.options
+# from http://www.cv.nrao.edu/~rreid/casa/tips/ipy_user_conf.py
+o.separate_in,o.separate_out,o.separate_out2="0","0","0"
+# from ipython manpage
+o.prompt_in1="Yade [\#]: "
+o.prompt_in2="Yade ..\D. "
+o.prompt_out="Yade [\#]: "
 #ip.options.profile='yade'

=== modified file 'gui/qt3/qt.py'
--- gui/qt3/qt.py	2009-11-15 09:32:52 +0000
+++ gui/qt3/qt.py	2009-12-03 20:57:11 +0000
@@ -38,8 +38,8 @@
 	O.engines=origEngines
 
 
-import yade.runtime
-if 'deprecated' in yade.runtime.features:
+import yade.config
+if 'deprecated' in yade.config.features:
 	def makePlayerVideo(playerDb,out,viewerState=None,dispParamsNo=-1,stride=1,fps=24,postLoadHook=None,startWait=False):
 		"""Create video by replaying a simulation. Snapshots are taken to temporary files,
 		encoded to a .ogg stream (theora codec); temps are deleted at the end.

=== modified file 'lib/factory/ClassFactory.hpp'
--- lib/factory/ClassFactory.hpp	2009-11-29 11:03:25 +0000
+++ lib/factory/ClassFactory.hpp	2009-12-03 20:57:11 +0000
@@ -190,4 +190,5 @@
 #define YADE_PLUGIN(plugins) namespace{ __attribute__((constructor)) void BOOST_PP_CAT(registerThisPluginClasses_,BOOST_PP_SEQ_HEAD(plugins)) (void){ const char* info[]={__FILE__ , BOOST_PP_SEQ_FOR_EACH(_YADE_PLUGIN_REPEAT,~,plugins) NULL}; ClassFactory::instance().registerPluginClasses(info);} } BOOST_PP_SEQ_FOR_EACH(_YADE_PLUGIN_BOOST_REGISTER,~,plugins)
 //! Macro informing build file generator what features that particular file depends on. Has no effect at compile-time. Can be specified multiple times within a single (.cpp) file
 #define YADE_REQUIRE_FEATURE(feature)
+#define YADE_LINK_EXTRA_LIB(lib)
 

=== modified file 'pkg/dem/Engine/StandAloneEngine/MicroMacroAnalyser.cpp'
--- pkg/dem/Engine/StandAloneEngine/MicroMacroAnalyser.cpp	2009-12-03 10:35:56 +0000
+++ pkg/dem/Engine/StandAloneEngine/MicroMacroAnalyser.cpp	2009-12-03 20:57:11 +0000
@@ -23,7 +23,11 @@
 #include<yade/extra/KinematicLocalisationAnalyser.hpp>
 #include<yade/extra/TriaxialState.h>
 
+YADE_PLUGIN((MicroMacroAnalyser));
 YADE_REQUIRE_FEATURE(CGAL)
+// see comment in extra/SConscript
+YADE_LINK_EXTRA_LIB(TesselationWrapper)
+
 
 CREATE_LOGGER(MicroMacroAnalyser);
 
@@ -223,6 +227,5 @@
 
 
 
-YADE_PLUGIN((MicroMacroAnalyser));
 
 

=== modified file 'py/SConscript'
--- py/SConscript	2009-12-02 23:01:36 +0000
+++ py/SConscript	2009-12-03 20:57:11 +0000
@@ -20,6 +20,8 @@
 		linkPlugins(['Shop','SpherePack']),
 		]),
 	env.SharedLibrary('_packObb',['_packObb.cpp'],SHLIBPREFIX=''),
+	env.ScanReplace('__init__.py.in'),
+	env.ScanReplace('config.py.in'),
 	env.File('utils.py'),
 	env.File('ymport.py'),
 	env.File('eudoxos.py'),

=== added file 'py/__init__.py.in'
--- py/__init__.py.in	1970-01-01 00:00:00 +0000
+++ py/__init__.py.in	2009-12-03 20:57:11 +0000
@@ -0,0 +1,55 @@
+# The purpose of this file is twofold: 
+# 1. it tells python that yade (this directory) is package of python modules
+#	see http://http://www.python.org/doc/2.1.3/tut/node8.html#SECTION008400000000000000000
+#
+# 2. import the runtime namespace (will be populated from within c++)
+#
+
+"""Common initialization core for yade.
+
+This file is executed when anything is imported from yade for the first time.
+It loads yade plugins and injects c++ class constructors to the __builtins__
+(that might change in the future, though) namespace, making them available
+everywhere.
+"""
+
+import ctypes,sys
+try:
+	import dl
+except ImportError:
+	import DLFCN as dl
+# see file:///usr/share/doc/python2.6/html/library/sys.html#sys.setdlopenflags
+# and various web posts on the topic, e.g.
+# * http://gcc.gnu.org/faq.html#dso
+# * http://www.code-muse.com/blog/?p=58
+# * http://wiki.python.org/moin/boost.python/CrossExtensionModuleDependencies
+sys.setdlopenflags(dl.RTLD_NOW | dl.RTLD_GLOBAL)
+# important: initialize c++ by importing libstdc++ directly
+# see http://www.abclinuxu.cz/poradna/programovani/show/286322
+# https://bugs.launchpad.net/bugs/490744
+libstdcxx='${libstdcxx}' # substituted by scons
+ctypes.cdll.LoadLibrary(libstdcxx)
+#
+# now ready for c++ imports
+
+# find plugin directory
+import os,os.path
+import config
+libDir=(config.prefix if not os.environ.has_key('YADE_PREFIX') else os.environ['YADE_PREFIX'])+'/lib/yade'+config.suffix
+# find plugins recursively
+plugins=[]
+for root,dirs,files in os.walk(libDir,followlinks=True):
+	for f in files:
+		if not (f.startswith('lib') and f.endswith('.so')): continue
+		plugin=os.path.join(libDir,root,f)
+		plugins.append(plugin)
+	
+
+# c++ initialization code
+import boot,system,wrapper
+boot.initialize(plugins)
+# create types
+__builtins__.update(system.cxxCtorsDict())
+__builtins__['O']=wrapper.Omega()
+system.setExitHandlers() # avoid backtrace if crash at finalization (log4cxx)
+

=== added file 'py/config.py.in'
--- py/config.py.in	1970-01-01 00:00:00 +0000
+++ py/config.py.in	2009-12-03 20:57:11 +0000
@@ -0,0 +1,15 @@
+"""
+Compile-time configuration for yade.
+
+Template file is processed by scons to create the actual configuration at build-time.
+"""
+
+prefix='${PREFIX}'
+suffix='${SUFFIX}'
+libstdcxx='${libstdcxx}'
+features='${features}'.split(',')
+revision='${realVersion}'
+version='${version}'
+debug='${debug}'
+
+libDir=prefix+'/lib/yade'+suffix

=== modified file 'py/system.py'
--- py/system.py	2009-12-02 23:01:36 +0000
+++ py/system.py	2009-12-03 20:57:11 +0000
@@ -8,7 +8,7 @@
 from yade import wrapper
 from yade._customConverters import *
 from yade import runtime
-__builtins__['O']=wrapper.Omega()
+O=wrapper.Omega()
 
 def childClasses(base):
 	"""Recursively enumerate classes deriving from given base (as string). Returns set."""
@@ -47,15 +47,16 @@
 }
 
 
-def injectCtors(proxyNamespace=__builtins__):
-	"""Input wrapped classes as well as proxies for their derived types into the __builtins__ namespace. Should be invoked at yade startup.
+def cxxCtorsDict(proxyNamespace=__builtins__):
+	"""Return dictionary of class constructors for yade's c++ types, which should be used to update a namespace.
 	
-	Root classes are those that are directly wrapped by boost::python. These are only imported to proxyNamespace.
+	Root classes are those that are directly wrapped by boost::python. These are only put to the dict.
 
 	Derived classes (from these root classes) are faked by creating a callable which invokes appropriate root class constructor with the derived class parameter and passes remaining arguments to it.
 
 	Classes that are neither root nor derived are exposed via callable object that constructs a Serializable of given type and passes the parameters.
 	"""
+	proxyNamespace={}
 	# classes derived from wrappers (but not from Serializable directly)
 	for root in _pyRootClasses:
 		try:
@@ -80,6 +81,7 @@
 				import warnings; warnings.warn("Class `%s' was renamed to (or replaced by) `%s', update your code!"%(self.old,self.new),DeprecationWarning,stacklevel=2);
 				return proxyNamespace[self.new](*args,**kw)
 		proxyNamespace[oldName]=warnWrap(oldName,_deprecated[oldName])
+	return proxyNamespace
 
 def setExitHandlers():
 	"""Set exit handler to avoid gdb run if log4cxx crashes at exit.

=== modified file 'py/tests/wrapper.py'
--- py/tests/wrapper.py	2009-12-01 14:56:39 +0000
+++ py/tests/wrapper.py	2009-12-03 20:57:11 +0000
@@ -11,19 +11,12 @@
 from miniWm3Wrap import *
 from yade._customConverters import *
 from math import *
-
-
-# copied from PythonUI_rc, should be in some common place (utils? runtime?)
-def listChildClassesRecursive(base):
-	ret=set(O.childClasses(base)); ret2=set()
-	for bb in ret:
-		ret2|=listChildClassesRecursive(bb)
-	return ret | ret2
+from yade import system
 
 
 rootClasses=set(['StandAloneEngine','DeusExMachina','InteractingGeometry','BoundingVolume','InteractionGeometry','InteractionPhysics','FileGenerator','BoundingVolumeFunctor','InteractionGeometryFunctor','InteractionPhysicsFunctor','ConstitutiveLaw','Material','State'])
 
-allClasses=listChildClassesRecursive('Serializable')
+allClasses=system.childClasses('Serializable')
 
 class TestObjectInstantiation(unittest.TestCase):
 	def setUp(self):
@@ -42,7 +35,7 @@
 	def testRootDerivedCtors(self):
 		# classes that are not root classes but derive from them can be instantiated by their name
 		for r in rootClasses:
-			for c in listChildClassesRecursive(r):
+			for c in system.childClasses(r):
 				obj=eval(c)(); self.assert_(obj.name==c,'Failed for '+c)
 	def testRootDerivedCtors_attrs_few(self):
 		# attributes passed when using the Foo(attr1=value1,attr2=value2) syntax

=== modified file 'py/yadeWrapper/yadeWrapper.cpp'
--- py/yadeWrapper/yadeWrapper.cpp	2009-12-02 23:01:36 +0000
+++ py/yadeWrapper/yadeWrapper.cpp	2009-12-03 20:57:11 +0000
@@ -527,6 +527,10 @@
 		if(OMEGA.getWorld()->isPeriodic){ return python::make_tuple(OMEGA.getWorld()->cellMin,OMEGA.getWorld()->cellMax); }
 		return python::make_tuple();
 	}
+	void disableGdb(){
+		signal(SIGSEGV,SIG_DFL);
+		signal(SIGABRT,SIG_DFL);
+	}
 	void exitNoBacktrace(int status=0){
 		signal(SIGSEGV,termHandler); /* unset the handler that runs gdb and prints backtrace */
 		exit(status);
@@ -722,6 +726,7 @@
 		.add_property("numThreads",&pyOmega::numThreads_get /* ,&pyOmega::numThreads_set*/ ,"Get maximum number of threads openMP can use.")
 		.add_property("periodicCell",&pyOmega::periodicCell_get,&pyOmega::periodicCell_set, "Get/set periodic cell minimum and maximum (tuple of 2 Vector3's), or () for no periodicity.")
 		.def("exitNoBacktrace",&pyOmega::exitNoBacktrace,omega_exitNoBacktrace_overloads(python::args("status"),"Disable our SEGV handler and exit."))
+		.def("disableGdb",&pyOmega::disableGdb,"Revert SEGV and ABRT handlers to system defaults.")
 		#ifdef YADE_BOOST_SERIALIZATION
 			.def("saveXML",&pyOmega::saveXML,"[EXPERIMENTAL] function saving to XML file using boost::serialization.")
 		#endif

=== modified file 'yadeSCons.py'
--- yadeSCons.py	2009-12-01 14:22:18 +0000
+++ yadeSCons.py	2009-12-03 20:57:11 +0000
@@ -4,10 +4,6 @@
 	import os.path,re,os
 	if os.path.exists('RELEASE'):
 		return file('RELEASE').readline().strip()
-	if os.path.exists('.svn'):
-		for l in os.popen("LC_ALL=C svn info").readlines():
-			m=re.match(r'Revision: ([0-9]+)',l)
-			if m: return 'svn'+m.group(1)
 	if os.path.exists('.bzr'):
 		for l in os.popen("LC_ALL=C bzr version-info 2>/dev/null").readlines():
 			m=re.match(r'revno: ([0-9]+)',l)
@@ -81,6 +77,9 @@
 					m=re.match('^\s*YADE_REQUIRE_FEATURE\((.*)\).*$',l)
 					if m:
 						featureDeps.add(m.group(1).upper())
+					m=re.match('^s*YADE_LINK_EXTRA_LIB\((.*)\).*$',l)
+					if m:
+						linkDeps.add('!'+m.group(1)) # hack!! see getPLuginLibs
 					m=re.match('^\s*#include\s*"([^/]*)".*$',l)
 					if m:
 						inc=m.group(1); incBaseName=m.group(1).split('.')[0]
@@ -129,6 +128,8 @@
 	for dep in p.deps:
 		if dep in plugInfo.keys():
 			ret.add(plugInfo[dep].obj)
+		elif dep.startswith('!'):
+			ret.add(dep[1:])
 		else:
 			pass
 			#print p.src+':',dep,"not a plugin?"


Follow ups