Fix lcov target
[senf.git] / SConstruct
index 7cf0362..fa07861 100644 (file)
@@ -1,8 +1,6 @@
 # -*- python -*-
 
-import sys, glob, os.path, datetime, pwd, time, fnmatch, string
-sys.path.append(Dir('#/senfscons').abspath)
-sys.path.append(Dir('#/doclib').abspath)
+import sys, glob, os.path, fnmatch
 import SENFSCons, senfutil
 
 ###########################################################################
@@ -10,61 +8,60 @@ import SENFSCons, senfutil
 
 env = Environment()
 
+env.Decider('MD5-timestamp')
+env.EnsureSConsVersion(1,2)
+
 # Load all the local SCons tools
-env.Tool('Doxygen', [ 'senfscons' ])
-env.Tool('Dia2Png', [ 'senfscons' ])
-env.Tool('PkgDraw', [ 'senfscons' ])
-env.Tool('InstallSubdir', [ 'senfscons' ])
-env.Tool('CopyToDir', [ 'senfscons' ])
-env.Tool('Boost', [ 'senfscons' ])
-env.Tool('CombinedObject', [ 'senfscons' ])
-env.Tool('PhonyTarget', [ 'senfscons' ])
+env.Tool('Doxygen')
+env.Tool('Dia2Png')
+env.Tool('PkgDraw')
+env.Tool('InstallSubdir')
+env.Tool('CopyToDir')
+env.Tool('Boost')
+env.Tool('CombinedObject')
+env.Tool('PhonyTarget')
+env.Tool('InstallDir')
 
 env.Help("""
 Additional top-level build targets:
 
 prepare      Create all target files not part of the repository
+default      Build all default targets (like calling scons with no arguments)
+examples     Build all examples
 all_tests    Build and run unit tests for all modules
 all_docs     Build documentation for all modules
 all          Build everything
-install_all  Install SENF into $PREFIX
+install_all  Install SENF into $$PREFIX
 deb          Build debian source and binary package
 debsrc       Build debian source package
 debbin       Build debian binary package
 linklint     Check links of doxygen documentation with 'linklint'
 fixlinks     Fix broken links in doxygen documentation
 valgrind     Run all tests under valgrind/memcheck
+lcov         Generate test coverage output in doc/lcov and lcov.info
 """)
 
-class BuildTypeOptions:
-    def __init__(self, var):
-        self._var = var
-
-    def __call__(self, target, source, env, for_signature):
-        type = env['final'] and "final" or env['debug'] and "debug" or "normal"
-        return env[self._var + "_" + type]
-
-env.Replace(
-   PKGDRAW                = 'doclib/pkgdraw',
-)
-
 env.Append(
-   ENV                    = { 'PATH' : os.environ.get('PATH') },
-   CLEAN_PATTERNS         = [ '*~', '#*#', '*.pyc', 'semantic.cache', '.sconsign*', '.sconsign' ],
+   ENV                    = { 'PATH' : os.environ.get('PATH'), 'HOME' : os.environ.get('HOME') },
+   CLEAN_PATTERNS         = [ '*~', '#*#', '*.pyc', 'semantic.cache', '.sconsign*',
+                              '*.gcno', '*.gcda', '*.gcov' ],
 
-   CPPPATH                = [ '#/include' ],
+   CPPPATH                = [ '#' ],
    LOCALLIBDIR            = '#',
    LIBPATH                = [ '$LOCALLIBDIR' ],
    LIBS                   = [ '$LIBSENF$LIBADDSUFFIX', 'rt', '$BOOSTREGEXLIB', 
                               '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB', '$BOOSTFSLIB' ], 
    TEST_EXTRA_LIBS        = [  ],
 
-   PREFIX                 = '/usr/local',
-   LIBINSTALLDIR          = '$PREFIX/lib',
-   BININSTALLDIR          = '$PREFIX/bin',
-   INCLUDEINSTALLDIR      = '$PREFIX/include',
-   OBJINSTALLDIR          = '$LIBINSTALLDIR',
-   DOCINSTALLDIR          = '$PREFIX/doc',
+   PREFIX                 = '#/dist',
+   LIBINSTALLDIR          = '$PREFIX${syslayout and "/lib" or ""}',
+   BININSTALLDIR          = '$PREFIX${syslayout and "/bin" or ""}',
+   INCLUDEINSTALLDIR      = '$PREFIX${syslayout and "/include" or ""}',
+   CONFINSTALLDIR         = '${syslayout and "$LIBINSTALLDIR/senf" or "$PREFIX"}',
+   OBJINSTALLDIR          = '$CONFINSTALLDIR',
+   DOCINSTALLDIR          = '$PREFIX${syslayout and "/share/doc/senf" or "/manual"}',
+   SCONSINSTALLDIR        = '$CONFINSTALLDIR/site_scons',
+
    CPP_INCLUDE_EXTENSIONS = [ '.h', '.hh', '.ih', '.mpp', '.cci', '.ct', '.cti' ],
    CPP_EXCLUDE_EXTENSIONS = [ '.test.hh' ],
 
@@ -78,80 +75,93 @@ env.Append(
    INLINE_OPTS            = [ '$INLINE_OPTS_NORMAL' ],
    CXXFLAGS               = [ '-Wall', '-Woverloaded-virtual', '-Wno-long-long', '$INLINE_OPTS',
                               '$CXXFLAGS_' ],
-   CXXFLAGS_              = BuildTypeOptions('CXXFLAGS'),
+   CXXFLAGS_              = senfutil.BuildTypeOptions('CXXFLAGS'),
    CXXFLAGS_final         = [ '-O3' ],
    CXXFLAGS_normal        = [ '-O0', '-g' ],
    CXXFLAGS_debug         = [ '$CXXFLAGS_normal' ],
 
    CPPDEFINES             = [ '$expandLogOption', '$CPPDEFINES_' ],
    expandLogOption        = senfutil.expandLogOption,
-   CPPDEFINES_            = BuildTypeOptions('CPPDEFINES'),
+   CPPDEFINES_            = senfutil.BuildTypeOptions('CPPDEFINES'),
    CPPDEFINES_final       = [ ],
    CPPDEFINES_normal      = [ 'SENF_DEBUG' ],
    CPPDEFINES_debug       = [ '$CPPDEFINES_normal' ],
 
    LINKFLAGS              = [ '-rdynamic', '$LINKFLAGS_' ],
-   LINKFLAGS_             = BuildTypeOptions('LINKFLAGS'),
+   LINKFLAGS_             = senfutil.BuildTypeOptions('LINKFLAGS'),
    LINKFLAGS_final        = [ ],
    LINKFLAGS_normal       = [ '-Wl,-S' ],
-   LINKFLAGS_debug        = [ ],
+   LINKFLAGS_debug        = [ '-g' ],
 )
 
 env.SetDefault(
-    LIBSENF = "senf",
-    final   = 0,
-    debug   = 0,
+    LIBSENF           = "senf",
+    LCOV              = "lcov",
+    GENHTML           = "genhtml",
+    SCONS             = "./tools/scons -j$CONCURRENCY_LEVEL",
+    CONCURRENCY_LEVEL = env.GetOption('num_jobs') or 1,
+    TOPDIR            = env.Dir('#').abspath,
 )
 
 # Set variables from command line
-env.Replace(**ARGUMENTS)
+senfutil.parseArguments(
+    env,
+    BoolVariable('final', 'Build final (optimized) build', False),
+    BoolVariable('debug', 'Link in debug symbols', False),
+    BoolVariable('syslayout', 'Install in to system layout directories (lib/, include/ etc)', False),
+)
 
 Export('env')
 
 # Create Doxyfile.local otherwise doxygen will barf on this non-existent file
 # Create it even when cleaning, to silence the doxygen builder warnings
-if not os.path.exists("Doxyfile.local"):
-    Execute(Touch("Doxyfile.local"))
-
-# Create local_config.h
-if not env.GetOption('clean') and not os.path.exists("local_config.hh"):
-    Execute(Touch("local_config.hh"))
+if not os.path.exists("doclib/Doxyfile.local"):
+    Execute(Touch("doclib/Doxyfile.local"))
 
 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp") \
    and not os.environ.get("SCONS") and COMMAND_LINE_TARGETS != [ 'prepare' ]:
     env.Execute([ "scons prepare" ])
 
-# Load SConscripts. Need to load some first (they change the global environment)
-initSConscripts = [ 
-    "debian/SConscript",
-    "doclib/SConscript",
-]
+# Load SConscripts
 
-SConscript(initSConscripts)
-
-if os.path.exists('SConscript.local'):
-    SConscript('SConscript.local')
-
-SConscript(list(set(glob.glob("*/SConscript")) - set(initSConscripts)))
+SConscriptChdir(0)
+SConscript("debian/SConscript")
+SConscriptChdir(1)
+if os.path.exists('SConscript.local') : SConscript('SConscript.local')
+SConscript("senf/SConscript")
+SConscript("Examples/SConscript")
+SConscript("HowTos/SConscript")
+SConscript("doclib/SConscript")
 
 ###########################################################################
 # Define build targets
 
-#### doc
-env.Depends(SENFSCons.Doxygen(env), env.Value(env['ENV']['REVISION']))
-
 #### libsenf.a
-libsenf = env.Library(env.subst("$LIBSENF$LIBADDSUFFIX"), env['ALLOBJECTS'])
+libsenf = env.Library("$LOCALLIBDIR/${LIBSENF}${LIBADDSUFFIX}", env['ALLOBJECTS'])
 env.Default(libsenf)
-
-env.InstallSubdir(target = '$INCLUDEINSTALLDIR', source = [ 'config.hh' ])
 env.Install('$LIBINSTALLDIR', libsenf)
 
+def create(target, source, env): 
+    file(str(target[0]), 'w').write(source[0].get_contents()+"\n")
+env['BUILDERS']['CreateFile'] = Builder(action = create)
+
+conf = env.CreateFile("${LOCALLIBDIR}/${LIBSENF}${LIBADDSUFFIX}.conf", 
+                      env.Value(env.subst("$_CPPDEFFLAGS")))
+env.Default(conf)
+env.Install('$CONFINSTALLDIR', conf)
+
 #### install_all, default, all_tests, all
+env.Install('${SCONSINSTALLDIR}', [ 'site_scons/__init__.py',
+                                    'site_scons/senfutil.py',
+                                    'site_scons/yaptu.py' ])
+env.InstallDir('${SCONSINSTALLDIR}', [ 'site_scons/site_tools', 'site_scons/lib' ],
+               FILTER_SUFFIXES=[ '','.css','.pl','.py','.sh','.sty','.xml','.xsl','.yap' ])
+env.Install('${INCLUDEINSTALLDIR}', 'boost')
+
 env.Alias('install_all', env.FindInstalledFiles())
 env.Alias('default', DEFAULT_TARGETS)
 env.Alias('all_tests', env.FindAllBoostUnitTests())
-env.Alias('all', [ 'default', 'all_tests', 'all_docs' ])
+env.Alias('all', [ 'default', 'all_tests', 'examples', 'all_docs' ])
 
 #### prepare
 env.PhonyTarget('prepare', [], [])
@@ -163,16 +173,25 @@ env.PhonyTarget('valgrind', [ 'all_tests' ], [ """
             echo;
             echo "Running $$test";
             echo;
-            valgrind --tool=memcheck --error-exitcode=99 --suppressions=valgrind.sup 
+            valgrind --tool=memcheck --error-exitcode=99 --suppressions=tools/valgrind.sup 
                 $$test $BOOSTTESTARGS;
             [ $$? -ne 99 ] || exit 1;
         done
 """.replace("\n"," ") ])
 
+### lcov
+env.PhonyTarget('lcov', [], [
+        '$SCONS debug=1 CCFLAGS+="-fprofile-arcs -ftest-coverage" LIBS+="gcov" all_tests',
+        '$LCOV --directory $TOPDIR/senf --capture --output-file /tmp/senf_lcov.info --base-directory $TOPDIR',
+        '$LCOV --output-file lcov.info --remove /tmp/senf_lcov.info "*/include/*" "*/boost/*" "*.test.*" ',
+        '$GENHTML --output-directory doc/lcov --title all_tests lcov.info',
+        'rm /tmp/senf_lcov.info' ])
+
 #### clean
 env.Clean('all', '.prepare-stamp')
 env.Clean('all', libsenf)
-env.Clean('all', 'linklint')
+env.Clean('all', env.Dir('dist'))
+env.Clean('all', 'lcov.info')
 
 if env.GetOption('clean'):
     env.Clean('all', [ os.path.join(path,f)