diff --git a/SConstruct b/SConstruct index 67232f01e..459ac9da4 100644 --- a/SConstruct +++ b/SConstruct @@ -59,14 +59,13 @@ def setupBasicEnvironment(): , SRCDIR=SRCDIR , BINDIR=BINDIR , CPPPATH="#"+SRCDIR # used to find includes, "#" means always absolute to build-root - , CPPDEFINES=[] # flags will be appended to this list + , CPPDEFINES=['-DCINELERRA_VERSION=\\"%s\\"' % VERSION ] # note: make it a list to append further defines ) handleNoBugSwitches(env) appendCppDefine(env,'DEBUG','DEBUG', 'NDEBUG') appendCppDefine(env,'OPENGL','USE_OPENGL') - appendCppDefine(env,'VERSION','VERSION') appendVal(env,'ARCHFLAGS', 'CPPFLAGS') # for both C and C++ appendVal(env,'OPTIMIZE', 'CPPFLAGS', val=' -O3') appendVal(env,'DEBUG', 'CPPFLAGS', val=' -g') @@ -215,17 +214,17 @@ def defineBuildTargets(env, artifacts): + srcSubtree(env,'proc') + srcSubtree(env,'common') # + srcSubtree(env,'lib') - + env.Object('$SRCDIR/main.cpp') ) + applobj = cinobj + env.Object('$SRCDIR/main.cpp') testobj = srcSubtree(env,'test/*', isShared=False) plugobj = srcSubtree(env,'plugin', isShared=True) - artifacts['cinelerra'] = env.Program('$BINDIR/cinelerra', cinobj) + artifacts['cinelerra'] = env.Program('$BINDIR/cinelerra', applobj) artifacts['plugins'] = env.SharedLibrary('$BINDIR/cinelerra-plugin', plugobj) # call subdir SConscript(s) for independent components SConscript(dirs=[SRCDIR+'/tool'], exports='env artifacts') - SConscript(dirs=[TESTDIR], exports='env artifacts testobj') + SConscript(dirs=[TESTDIR], exports='env artifacts cinobj testobj') def defineInstallTargets(env, artifacts): diff --git a/src/cinelerra.h b/src/cinelerra.h index 92496e74b..c2b95dd8c 100644 --- a/src/cinelerra.h +++ b/src/cinelerra.h @@ -25,7 +25,6 @@ #ifndef CINELERRA_H #define CINELERRA_H -#include #ifdef __cplusplus @@ -41,14 +40,18 @@ extern "C" { +#ifndef __cplusplus +#include "nobugcfg.h" -#ifdef __cplusplus /* ============== C++-Part ================= */ +#else /* ========================== C++-Part ================= */ /* common types frequently used... */ +#include "common/util.hpp" #include "common/time.hpp" -#include "common/appconfig.hpp" +#include "common/appconfig.hpp" // includes NoBug via "nobugcfg.h" +#include "common/error.hpp" namespace cinelerra diff --git a/src/common/appconfig.cpp b/src/common/appconfig.cpp index b4b3dfe96..769cde604 100644 --- a/src/common/appconfig.cpp +++ b/src/common/appconfig.cpp @@ -22,21 +22,32 @@ #include "common/appconfig.hpp" +#include "common/error.hpp" +#include "common/util.hpp" + +#define NOBUG_INIT_DEFS_ +#include "nobugcfg.h" +#undef NOBUG_INIT_DEFS_ -NOBUG_CPP_DEFINE_FLAG(config); - +using util::isnil; namespace cinelerra { - /** holds the single instance and triggers initialization */ - auto_ptr Appconfig::theApp_ (0); + /** This internal pointer to the single instance is deliberately + * not initialized (i.e. rely on implicit initialisation to 0), + * because when static init reaches this definition, the + * Appconfig::instance() probably already has been called + * by another compilation unit. This is ugliy, but preferable + * to beeing dependant on inclusion order of headers. */ + Appconfig* Appconfig::theApp_ ; -#ifndef VERSION -#define VERSION 3++devel +#ifndef CINELERRA_VERSION +#define CINELERRA_VERSION "3++devel" #endif + /** perform initialization on first access. * A call is placed in static initialization code * included in cinelerra.h; thus it will happen @@ -49,30 +60,26 @@ namespace cinelerra NOBUG_INIT; ////////// - (*configParam_)["version"] = "VERSION"; + INFO(config, "Basic application configuration triggered."); + (*configParam_)["version"] = CINELERRA_VERSION; } - ////////////////////////////TODO: ein richtiges utility draus machen.... - bool isnil(string val) - { - return 0 == val.length(); - }; - ////////////////////////////TODO /** access the configuation value for a given key. * @return empty string for unknown keys, else the corresponding configuration value */ - string + const string & Appconfig::get (const string & key) throw() { try { - string& val = (*instance().configParam_)[key]; + const string& val = (*instance().configParam_)[key]; WARN_IF( isnil(val), config, "undefined config parameter \"%s\" requested.", key.c_str()); + return val; } catch (...) diff --git a/src/common/appconfig.hpp b/src/common/appconfig.hpp index 3dd578100..9cf20f9f9 100644 --- a/src/common/appconfig.hpp +++ b/src/common/appconfig.hpp @@ -20,6 +20,18 @@ */ +/** @file appconfig.hpp + ** This header is special, as it causes global system initialisation + ** to happen. On inclusion, it places static initialisation code, + ** which on first run will create the Appconfig singleton instance. + ** Additionally, the inclusion, configuration and initialisation + ** of the NoBug library is handled here. Global definitions + ** for NoBug are placed into the corresponding translation unit + ** appconfig.cpp" + ** + ** @see nobugcfg.h + */ + #ifndef CINELERRA_APPCONFIG_H #define CINELERRA_APPCONFIG_H @@ -28,16 +40,14 @@ #include #include +#include "nobugcfg.h" + using std::string; using std::auto_ptr; -#include -NOBUG_DECLARE_FLAG(config); - - namespace cinelerra { @@ -45,20 +55,20 @@ namespace cinelerra /** * Singleton to hold inevitable global flags and constants - * and for performing erarly (static) global initialization tasks. + * and for performing early (static) global initialization tasks. */ class Appconfig { private: /** holds the single instance and triggers initialization */ - static auto_ptr theApp_; + static Appconfig* theApp_; /** perform initialization on first access. * A call is placed in static initialization code - * included in cinelerra.h; thus it will happen - * ubiquitous very early. + * included via cinelerra.h (see below), + * thus it will happen rather early. */ Appconfig () ; @@ -66,21 +76,22 @@ namespace cinelerra public: static Appconfig& instance() { - if (!theApp_.get()) theApp_.reset (new Appconfig ()); + if (!theApp_) theApp_ = new Appconfig (); return *theApp_; } /** access the configuation value for a given key. - * @return empty string for unknown keys, else the corresponding configuration value + * @return empty string for unknown keys, config value else + * @todo do we need such a facility? */ - static string get (const string & key) throw(); + static const string & get (const string& key) throw(); private: typedef std::map Configmap; typedef auto_ptr PConfig; - /** the following is just placeholder code! + /** @TODO the following is just placeholder code! * Appconfig could do such things if necessary. */ PConfig configParam_; @@ -92,8 +103,8 @@ namespace cinelerra namespace { - /** generate "magic code" causing early static initialization */ - Appconfig* init (&Appconfig::instance ()); + /** "magic code" to cause early static initialization */ + Appconfig& init (Appconfig::instance ()); } } // namespace cinelerra diff --git a/src/common/error.hpp b/src/common/error.hpp index b851630ef..973fa1d8a 100644 --- a/src/common/error.hpp +++ b/src/common/error.hpp @@ -41,6 +41,8 @@ namespace cinelerra class Error : public std::exception { public: + virtual ~Error () throw() {}; + /** yield a diagnostig message characterizing the problem */ virtual const char* what () const throw(); diff --git a/src/common/util.hpp b/src/common/util.hpp new file mode 100644 index 000000000..f0a8bfc2f --- /dev/null +++ b/src/common/util.hpp @@ -0,0 +1,53 @@ +/* + TIME.hpp - unified representation of a time point, including conversion functions + + Copyright (C) CinelerraCV + 2007, Christian Thaeter + + 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 UTIL_HPP_ +#define UTIL_HPP_ + +#include +#include + + +namespace util + { + using std::string; + + + /** a family of util functions providing a "no value whatsoever" test */ + inline bool isnil(const string& val) + { + return 0 == val.length(); + } + + inline bool isnil(const string* pval) + { + return !pval || 0 == pval->length(); + } + + inline bool isnil(const char* pval) + { + return !pval || 0 == std::strlen(pval); + } + +} // namespace util +#endif /*UTIL_HPP_*/ diff --git a/src/main.cpp b/src/main.cpp index 3d4c1ef20..ccc1dd481 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,9 +26,14 @@ #include "cinelerra.h" using std::cout; +using std::endl; +using cinelerra::Appconfig; + int main (int argc, char* argv[]) { - cout << "hello cinelerra again\n"; + cout << "*** Cinelerra NLE for Linux ***" << endl + << " Version: " << Appconfig::get("version") << endl; + assert(true); return 0; } diff --git a/src/nobugcfg.h b/src/nobugcfg.h new file mode 100644 index 000000000..c89a284af --- /dev/null +++ b/src/nobugcfg.h @@ -0,0 +1,84 @@ +/* + NOBUGCFG.h - global configuration and definitions for NoBug + + + Copyright (C) CinelerraCV + 2007, Christian Thaeter + 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. + +*/ + +/** @file nobugcfg.h + ** This header is for including and configuring NoBug. + ** The idea is that configuration and some globally used flag + ** declarations are to be kept in one central location. Normally, + ** this header will be included by appconfig.hpp, which in turn gets + ** included by cinelerra.h + ** @par Besides the usual guarded declarations, this header contains + ** one section with the corresponding definitions. This section + ** is to be called by appconfig.cpp only, which deals with application + ** wide configuration values contained in the Singleton class Appconfig. + ** Incidentally, the constructor of Appconfig issues the NOBUG_INIT call + ** + */ + + +#ifndef NOBUGCFG_H /* ============= Part 1: DECLARATIONS ======== */ +#define NOBUGCFG_H + +#include + + /* configuration of NoBug goes here... */ + +#include + + + /* declare flags used throughout the code base... */ + NOBUG_DECLARE_FLAG(config); + NOBUG_DECLARE_FLAG(test); + + +#endif /*NOBUGCFG_H ======= (End) Part 1: DECLARATIONS ======== */ + + + + + + +#ifdef NOBUG_INIT_DEFS_ /*========== Part 2: DEFINITIONS ========= */ + +/* ================================= common C Part ========= */ + + + + + + +#ifdef __cplusplus /* ============== C++-Part ============== */ + + + /* flags used throughout the code base... */ + NOBUG_CPP_DEFINE_FLAG(config); + NOBUG_CPP_DEFINE_FLAG(test); + + + +#endif /* ===================== (End) C++-Part ============= */ + + + +#endif /*NOBUG_INIT_DEFS_ ==== (End) Part 2: DEFINITIONS ========= */ diff --git a/src/proc/mobject/session/relativeplacement.hpp b/src/proc/mobject/session/relativeplacement.hpp index ca3041928..1836d689d 100644 --- a/src/proc/mobject/session/relativeplacement.hpp +++ b/src/proc/mobject/session/relativeplacement.hpp @@ -44,8 +44,8 @@ namespace mobject * the possible kinds of RelativePlacements */ enum RelType - { SAMETIME /** place subject at the same time as the anchor */ - , ATTACH /** attach subject to anchor (e.g. an effect to a clip) */ + { SAMETIME /**< place subject at the same time as the anchor */ + , ATTACH /**< attach subject to anchor (e.g. an effect to a clip) */ }; protected: diff --git a/src/test/helper/run.hpp b/src/test/helper/run.hpp index 4d5cfb0b3..e34394af2 100644 --- a/src/test/helper/run.hpp +++ b/src/test/helper/run.hpp @@ -27,7 +27,7 @@ #include #include -#include "common/factory.hpp" + #include "test/helper/suite.hpp" @@ -36,8 +36,6 @@ namespace test using std::string; using std::auto_ptr; - using cinelerra::Factory; - using cinelerra::factory::SubclassPtr; typedef std::vector * Arg; diff --git a/src/test/helper/suite.cpp b/src/test/helper/suite.cpp index f90a149ac..45a1adef6 100644 --- a/src/test/helper/suite.cpp +++ b/src/test/helper/suite.cpp @@ -25,23 +25,30 @@ #include #include #include -#include "test/helper/suite.hpp" -#include "test/helper/run.hpp" - -#include #include #include +#include "test/helper/suite.hpp" +#include "test/helper/run.hpp" +#include "common/error.hpp" +#include "common/util.hpp" + +#include "nobugcfg.h" + + namespace test { using std::map; using std::vector; using std::auto_ptr; using std::tr1::shared_ptr; + + using util::isnil; typedef map TestMap; typedef shared_ptr PTestMap; typedef map GroupMap; + /** helper to collect and manage the test cases. @@ -65,7 +72,10 @@ namespace test void Registry::add2group (Launcher* test, string testID, string groupID) { - // TODO: ASSERT test!=null, testID.length > 0 ... + REQUIRE( test ); + REQUIRE( !isnil(testID) ); + REQUIRE( !isnil(groupID) ); + PTestMap& group = getGroup(groupID); if (!group) group.reset( new TestMap ); @@ -86,9 +96,8 @@ namespace test void Suite::enroll (Launcher* test, string testID, string groups) { - // TODO learn to use NoBug for logging - std::cerr << "enroll( testID=" << testID << ")\n"; - // TODO: ASSERT test!=null, testID.length() > 0... + REQUIRE( test ); + REQUIRE( !isnil(testID) ); std::istringstream ss(groups); string group; @@ -112,9 +121,12 @@ namespace test Suite::Suite(string groupID) : groupID_(groupID) { - std::cerr << "Suite( groupID="<< groupID << ")\n"; + REQUIRE( !isnil(groupID) ); + TRACE(test, "Test-Suite( groupID=%s )\n", groupID.c_str () ); + if (!testcases.getGroup(groupID)) - throw "empty testsuite"; /////////// TODO Errorhandling! + throw cinelerra::error::Invalid (); + //throw "empty testsuite"; /////////// TODO Errorhandling! } @@ -125,15 +137,10 @@ namespace test void Suite::run (int argc, char* argv[]) { - /////////////////////////////////////////////////////TODO:DEBUG - std::cerr << "Suite::run( (" << argc << "[" ; - for ( int i=0; i= 2) { diff --git a/src/test/helper/suite.hpp b/src/test/helper/suite.hpp index 6dfefe663..8060aaab3 100644 --- a/src/test/helper/suite.hpp +++ b/src/test/helper/suite.hpp @@ -25,7 +25,6 @@ #define TESTHELPER_SUITE_H #include -#include "common/factory.hpp" diff --git a/src/tool/SConscript b/src/tool/SConscript index f3a3abf76..fe3a35dcc 100644 --- a/src/tool/SConscript +++ b/src/tool/SConscript @@ -5,6 +5,13 @@ Import('env','artifacts') -# build the ubiquitous Hello World application (note: C source) -artifacts['tools'] = env.Program('#$BINDIR/hello-world','hello.c') +# at the moment (8/07), Ichthyo tries to find out how to configure NoBug +# does it help, if we set the NOBUG_LOG to the environment used for building?? +env = env.Clone() +env['ENV']['NOBUG_LOG'] = 'ttt:WARNING' + +# build the ubiquitous Hello World application (note: C source) +artifacts['tools'] = [ env.Program('#$BINDIR/hello-world','hello.c') + + env.Program('#$BINDIR/try', 'try.cpp') #### to try out some feature: + ] diff --git a/src/tool/try.cpp b/src/tool/try.cpp new file mode 100644 index 000000000..b948ada31 --- /dev/null +++ b/src/tool/try.cpp @@ -0,0 +1,35 @@ +/* try.cpp - for trying out some language features.... + * scons will create the binary bin/try + * + */ + +// 8/07 - how to control NOBUG?? + + +#include + +#define NOBUG_LOG_LIMIT LOG_ERR + +#include + +NOBUG_DECLARE_FLAG(ttt); + +NOBUG_DEFINE_FLAG(ttt); + +int main (int argc, char* argv[]) + { + + NOBUG_INIT; + + NOBUG_INIT_FLAG_LIMIT(ttt, LOG_WARNING); + + TRACE(ttt,"trace"); + INFO(ttt,"info"); + NOTICE(ttt,"notice"); + WARN(ttt,"warning"); + ERROR(ttt,"error"); + + TRACE(NOBUG_ON,"allways on?"); + + return 0; + } diff --git a/tests/SConscript b/tests/SConscript index a5fe4a697..584d2fb24 100644 --- a/tests/SConscript +++ b/tests/SConscript @@ -3,10 +3,10 @@ ## SConscript - SCons buildscript for the Testsuite (called by SConstruct) ## -Import('env','artifacts','testobj') +Import('env','artifacts','cinobj','testobj') # build an application running the testsuite -artifacts['testsuite'] = env.Program('mainsuite',testobj + ['#$SRCDIR/test/mainsuite.cpp']) +artifacts['testsuite'] = env.Program('mainsuite', cinobj + testobj + ['#$SRCDIR/test/mainsuite.cpp']) # TODO: we could apply much more "magic" here # - build /every/ $TESTDIR/*.cpp into an application diff --git a/wiki/index.html b/wiki/index.html index 517fd7095..9724d3d62 100755 --- a/wiki/index.html +++ b/wiki/index.html @@ -747,11 +747,12 @@ config.macros.timeline.handler = function(place,macroName,params,wikifier,paramS } //}}} -
+
for __Building__
 * gcc (4.1), glibc6 (2.3), libstdc++6 (4.1)
 * [[build system|BuildSystem]] dependencies: SCons (0.96.90), Python (2.3)
 * NoBug for Logging, Tracing, Asserting (can be obtained from [[Pipapo.org|http://www.pipapo.org/pipawiki/NoBug]])
+* ~NoBug needs [[valgrind|Valgrind]] (3.2), execinfo.h and libpthread (&rarr; glibc)
 * std::tr1 &mdash; esp. for the former BOOST::shared_ptr (which is now proposed standard)
 * BOOST
 //usually, newer versions are OK//
diff --git a/wiki/support_library.html b/wiki/support_library.html
index 25561df2a..ee542d807 100644
--- a/wiki/support_library.html
+++ b/wiki/support_library.html
@@ -646,7 +646,12 @@ Error: #f88
[[SupportLibrary]]
-
+
+
We distinguish the way how to cope with Errors, i.e. the ErrorHandlingPolicy, and the actual implementation
+* for code with C semantics &rarr; ErrorHandling-C
+* for C++ code &rarr; ErrorHandling-Cpp
+
+
! Proposal:
 We need some centralized way to handle errors and doing hard aborts.
 
@@ -700,6 +705,19 @@ thus a {{{CINELERRA_ERROR_DEFINE(NFOO, "Foo not found")}}} will result
 !! Allocation
 The next point is allocation failures. These are possible by C/C++ standard but don't actually happen anymore in Linux (except in few rare cases). Instead of gracefully handling this errors I'll add a {{{CINELERRA_DIE(message)}}} macro to this library later. This macro will just do (NoBug) logging and then doing a hard abort. It should be a macro because we want to preserve file/line location for logging.
 
+
+
+
+
Basically, the C++ error handling techniques are layered on top of the [[C solution|ErrorHandling-C]].
+!Proposal:
+We use a common base class for all our application specific exceptions. These exceptions can be thought of as a classification of error situations, thus the hierarchical approach. The purpose of throwing such a //classified exception// is
+* to do a controlled partial failure
+* to trigger automatic cleanup without the need to implement the details
+
+!!Requirements for the Exception Interface
+* a means for capturing and transporting detail informations
+* the possibility to link to the ''root cause'' of an exception, even after having passed several subsystem barriers.
+* getting standardized error messages automatically