Fix lcov target
[senf.git] / SConstruct
1 # -*- python -*-
2
3 import sys, glob, os.path, fnmatch
4 import SENFSCons, senfutil
5
6 ###########################################################################
7 # Load utilities and setup libraries and configure build
8
9 env = Environment()
10
11 env.Decider('MD5-timestamp')
12 env.EnsureSConsVersion(1,2)
13
14 # Load all the local SCons tools
15 env.Tool('Doxygen')
16 env.Tool('Dia2Png')
17 env.Tool('PkgDraw')
18 env.Tool('InstallSubdir')
19 env.Tool('CopyToDir')
20 env.Tool('Boost')
21 env.Tool('CombinedObject')
22 env.Tool('PhonyTarget')
23 env.Tool('InstallDir')
24
25 env.Help("""
26 Additional top-level build targets:
27
28 prepare      Create all target files not part of the repository
29 default      Build all default targets (like calling scons with no arguments)
30 examples     Build all examples
31 all_tests    Build and run unit tests for all modules
32 all_docs     Build documentation for all modules
33 all          Build everything
34 install_all  Install SENF into $$PREFIX
35 deb          Build debian source and binary package
36 debsrc       Build debian source package
37 debbin       Build debian binary package
38 linklint     Check links of doxygen documentation with 'linklint'
39 fixlinks     Fix broken links in doxygen documentation
40 valgrind     Run all tests under valgrind/memcheck
41 lcov         Generate test coverage output in doc/lcov and lcov.info
42 """)
43
44 env.Append(
45    ENV                    = { 'PATH' : os.environ.get('PATH'), 'HOME' : os.environ.get('HOME') },
46    CLEAN_PATTERNS         = [ '*~', '#*#', '*.pyc', 'semantic.cache', '.sconsign*',
47                               '*.gcno', '*.gcda', '*.gcov' ],
48
49    CPPPATH                = [ '#' ],
50    LOCALLIBDIR            = '#',
51    LIBPATH                = [ '$LOCALLIBDIR' ],
52    LIBS                   = [ '$LIBSENF$LIBADDSUFFIX', 'rt', '$BOOSTREGEXLIB', 
53                               '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB', '$BOOSTFSLIB' ], 
54    TEST_EXTRA_LIBS        = [  ],
55
56    PREFIX                 = '#/dist',
57    LIBINSTALLDIR          = '$PREFIX${syslayout and "/lib" or ""}',
58    BININSTALLDIR          = '$PREFIX${syslayout and "/bin" or ""}',
59    INCLUDEINSTALLDIR      = '$PREFIX${syslayout and "/include" or ""}',
60    CONFINSTALLDIR         = '${syslayout and "$LIBINSTALLDIR/senf" or "$PREFIX"}',
61    OBJINSTALLDIR          = '$CONFINSTALLDIR',
62    DOCINSTALLDIR          = '$PREFIX${syslayout and "/share/doc/senf" or "/manual"}',
63    SCONSINSTALLDIR        = '$CONFINSTALLDIR/site_scons',
64
65    CPP_INCLUDE_EXTENSIONS = [ '.h', '.hh', '.ih', '.mpp', '.cci', '.ct', '.cti' ],
66    CPP_EXCLUDE_EXTENSIONS = [ '.test.hh' ],
67
68    # These options are insane. Only useful for inline debugging. Need at least 1G free RAM
69    INLINE_OPTS_DEBUG      = [ '-finline-limit=20000', '-fvisibility-inlines-hidden', 
70                               '-fno-inline-functions', '-Winline' 
71                               '--param','large-function-growth=10000',
72                               '--param', 'large-function-insns=10000', 
73                               '--param','inline-unit-growth=10000' ],
74    INLINE_OPTS_NORMAL     = [ '-finline-limit=5000' ],
75    INLINE_OPTS            = [ '$INLINE_OPTS_NORMAL' ],
76    CXXFLAGS               = [ '-Wall', '-Woverloaded-virtual', '-Wno-long-long', '$INLINE_OPTS',
77                               '$CXXFLAGS_' ],
78    CXXFLAGS_              = senfutil.BuildTypeOptions('CXXFLAGS'),
79    CXXFLAGS_final         = [ '-O3' ],
80    CXXFLAGS_normal        = [ '-O0', '-g' ],
81    CXXFLAGS_debug         = [ '$CXXFLAGS_normal' ],
82
83    CPPDEFINES             = [ '$expandLogOption', '$CPPDEFINES_' ],
84    expandLogOption        = senfutil.expandLogOption,
85    CPPDEFINES_            = senfutil.BuildTypeOptions('CPPDEFINES'),
86    CPPDEFINES_final       = [ ],
87    CPPDEFINES_normal      = [ 'SENF_DEBUG' ],
88    CPPDEFINES_debug       = [ '$CPPDEFINES_normal' ],
89
90    LINKFLAGS              = [ '-rdynamic', '$LINKFLAGS_' ],
91    LINKFLAGS_             = senfutil.BuildTypeOptions('LINKFLAGS'),
92    LINKFLAGS_final        = [ ],
93    LINKFLAGS_normal       = [ '-Wl,-S' ],
94    LINKFLAGS_debug        = [ '-g' ],
95 )
96
97 env.SetDefault(
98     LIBSENF           = "senf",
99     LCOV              = "lcov",
100     GENHTML           = "genhtml",
101     SCONS             = "./tools/scons -j$CONCURRENCY_LEVEL",
102     CONCURRENCY_LEVEL = env.GetOption('num_jobs') or 1,
103     TOPDIR            = env.Dir('#').abspath,
104 )
105
106 # Set variables from command line
107 senfutil.parseArguments(
108     env,
109     BoolVariable('final', 'Build final (optimized) build', False),
110     BoolVariable('debug', 'Link in debug symbols', False),
111     BoolVariable('syslayout', 'Install in to system layout directories (lib/, include/ etc)', False),
112 )
113
114 Export('env')
115
116 # Create Doxyfile.local otherwise doxygen will barf on this non-existent file
117 # Create it even when cleaning, to silence the doxygen builder warnings
118 if not os.path.exists("doclib/Doxyfile.local"):
119     Execute(Touch("doclib/Doxyfile.local"))
120
121 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp") \
122    and not os.environ.get("SCONS") and COMMAND_LINE_TARGETS != [ 'prepare' ]:
123     env.Execute([ "scons prepare" ])
124
125 # Load SConscripts
126
127 SConscriptChdir(0)
128 SConscript("debian/SConscript")
129 SConscriptChdir(1)
130 if os.path.exists('SConscript.local') : SConscript('SConscript.local')
131 SConscript("senf/SConscript")
132 SConscript("Examples/SConscript")
133 SConscript("HowTos/SConscript")
134 SConscript("doclib/SConscript")
135
136 ###########################################################################
137 # Define build targets
138
139 #### libsenf.a
140 libsenf = env.Library("$LOCALLIBDIR/${LIBSENF}${LIBADDSUFFIX}", env['ALLOBJECTS'])
141 env.Default(libsenf)
142 env.Install('$LIBINSTALLDIR', libsenf)
143
144 def create(target, source, env): 
145     file(str(target[0]), 'w').write(source[0].get_contents()+"\n")
146 env['BUILDERS']['CreateFile'] = Builder(action = create)
147
148 conf = env.CreateFile("${LOCALLIBDIR}/${LIBSENF}${LIBADDSUFFIX}.conf", 
149                       env.Value(env.subst("$_CPPDEFFLAGS")))
150 env.Default(conf)
151 env.Install('$CONFINSTALLDIR', conf)
152
153 #### install_all, default, all_tests, all
154 env.Install('${SCONSINSTALLDIR}', [ 'site_scons/__init__.py',
155                                     'site_scons/senfutil.py',
156                                     'site_scons/yaptu.py' ])
157 env.InstallDir('${SCONSINSTALLDIR}', [ 'site_scons/site_tools', 'site_scons/lib' ],
158                FILTER_SUFFIXES=[ '','.css','.pl','.py','.sh','.sty','.xml','.xsl','.yap' ])
159 env.Install('${INCLUDEINSTALLDIR}', 'boost')
160
161 env.Alias('install_all', env.FindInstalledFiles())
162 env.Alias('default', DEFAULT_TARGETS)
163 env.Alias('all_tests', env.FindAllBoostUnitTests())
164 env.Alias('all', [ 'default', 'all_tests', 'examples', 'all_docs' ])
165
166 #### prepare
167 env.PhonyTarget('prepare', [], [])
168
169 #### valgrind
170 env.PhonyTarget('valgrind', [ 'all_tests' ], [ """
171     find -name .test.bin 
172         | while read test; do
173             echo;
174             echo "Running $$test";
175             echo;
176             valgrind --tool=memcheck --error-exitcode=99 --suppressions=tools/valgrind.sup 
177                 $$test $BOOSTTESTARGS;
178             [ $$? -ne 99 ] || exit 1;
179         done
180 """.replace("\n"," ") ])
181
182 ### lcov
183 env.PhonyTarget('lcov', [], [
184         '$SCONS debug=1 CCFLAGS+="-fprofile-arcs -ftest-coverage" LIBS+="gcov" all_tests',
185         '$LCOV --directory $TOPDIR/senf --capture --output-file /tmp/senf_lcov.info --base-directory $TOPDIR',
186         '$LCOV --output-file lcov.info --remove /tmp/senf_lcov.info "*/include/*" "*/boost/*" "*.test.*" ',
187         '$GENHTML --output-directory doc/lcov --title all_tests lcov.info',
188         'rm /tmp/senf_lcov.info' ])
189
190 #### clean
191 env.Clean('all', '.prepare-stamp')
192 env.Clean('all', libsenf)
193 env.Clean('all', env.Dir('dist'))
194 env.Clean('all', 'lcov.info')
195
196 if env.GetOption('clean'):
197     env.Clean('all', [ os.path.join(path,f)
198                        for path, subdirs, files in os.walk('.')
199                        for pattern in env['CLEAN_PATTERNS']
200                        for f in fnmatch.filter(files,pattern) ])
201
202 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp"):
203     Execute(Touch(".prepare-stamp"))