Better valgrind build 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 all_valgrinds  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 for test in env.FindAllBoostUnitTests():
171     stamp = env.Command(test[0].dir.File('.test-valgrind.stamp'), 
172                         [ test[0].dir.File('.test.bin'), test ],
173                         [ """valgrind --tool=memcheck 
174                                       --error-exitcode=99 
175                                       --suppressions=tools/valgrind.sup 
176                                           $SOURCE $BOOSTTESTARGS;
177                              [ $$? -ne 99 ] || exit 1""".replace("\n"," "),
178                           Touch("$TARGET") ])
179     alias = env.Command(test[0].dir.File('valgrind'), stamp, [ env.NopAction() ])
180     env.Alias('all_valgrinds', alias)
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"))