Packet: added Packet::reparse() and ::clearAnnotations() member
[senf.git] / SConstruct
1 # -*- python -*-
2
3 import sys, os.path
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 senfutil.loadTools(env)
16
17 env.Help("""
18 Additional top-level build targets:
19
20 prepare         Create all target files not part of the repository
21 default         Build all default targets (like calling scons with no arguments)
22 examples        Build all examples
23 all_tests       Build and run unit tests for all modules
24 test_changes    Build tests only for files with local changes (queries svn or git)
25 all_docs        Build documentation for all modules
26 all             Build everything
27 install_all     Install SENF into $$PREFIX
28 deb             Build debian source and binary package
29 debsrc          Build debian source package
30 debbin          Build debian binary package
31 linklint        Check links of doxygen documentation with 'linklint'
32 fixlinks        Fix broken links in doxygen documentation
33 all_valgrinds   Run all tests under valgrind/memcheck
34 lcov            Generate test coverage output in doc/lcov and lcov.info
35
36 The following additional targets may be called within subdirectories, either
37 using '$ scons -u <target>'  or '$ scons <directory>/<target>:
38
39 test            Build and run unit test for this module
40 doc             Build the documentation of this module
41 valgrind        Run the unit test of this module under valgrind
42
43 When cleaning up using '$ scons -c <target>', some targets are handled specially:
44
45 all             Remove everything generated by the build including temporary and
46                 backup files
47
48 some            Remove all files not needed for building like temporary or backup
49                 files. This target is only valid when called as clean target.
50
51 You may execute targets on a remote host via ssh (if the directory layout is the
52 same) by calling
53
54     $ scons <target>@[<user>@]<host>
55
56 Some more elaborate unit tests may be enabled by setting appropritate variables
57 in the shell (unix) environment
58
59 SENF_TIMING_CRITICAL_TESTS
60                 Enables unit tests which depend on timing measurements. These
61                 unit tests should only be run on a single core and an otherwise
62                 idle system.
63
64 SENF_WLAN_TEST_INTERFACE
65                 WLAN interface to use for testing. The interface should not be
66                 actively in use.
67
68 SENF_ETH_TEST_INTERFACE
69                 Ethernet interface to use for testing. The interface should not
70                 be actively in use.
71
72 Some unit tests will only run when executed to 'root'.
73 """)
74
75 env.Replace(
76     expandLogOption        = senfutil.expandLogOption,
77     CXXFLAGS_              = env.BuildTypeOptions('CXXFLAGS'),
78     CPPDEFINES_            = env.BuildTypeOptions('CPPDEFINES'),
79     LINKFLAGS_             = env.BuildTypeOptions('LINKFLAGS'),
80 )
81 env.Append(
82     IMPORT_ENV             = [ 'PATH', 'HOME', 'SSH_*', 'SENF*', 'CCACHE_*', 'DISTCC_*' ],
83
84     CLEAN_SOME_PATTERNS    = [ '*~', '#*#', '*.pyc', 'semantic.cache' ],
85     CLEAN_PATTERNS         = [ '.sconsign*', '.sconf_temp' ],
86
87     CPPPATH                = [ '#', '$BUILDDIR',
88                                '${NEED_BOOST_EXT and "#/boost_ext" or None}' ],
89     LIBPATH                = [ '$LOCALLIBDIR' ],
90     LIBS                   = [ '$EXTRA_LIBS' ],
91     EXTRA_LIBS             = [ 'rt' ],
92     TEST_EXTRA_LIBS        = [  ],
93     VALGRINDARGS           = [ '--num-callers=50' ],
94
95     CPP_INCLUDE_EXTENSIONS = [ '.h', '.hh', '.ih', '.mpp', '.cci', '.ct', '.cti' ],
96     CPP_EXCLUDE_EXTENSIONS = [ '.test.hh' ],
97
98     # INLINE_OPTS_DEBUG are insane. Only useful for inline debugging. Need at least 1G free RAM
99     INLINE_OPTS_DEBUG      = [ '-finline-limit=20000', '-fvisibility-inlines-hidden',
100                                '-fno-inline-functions', '-Winline'
101                                '--param','large-function-growth=10000',
102                                '--param', 'large-function-insns=10000',
103                                '--param','inline-unit-growth=10000' ],
104     INLINE_OPTS_NORMAL     = [ '-finline-limit=5000', '--param', 'inline-unit-growth=60' ],
105     INLINE_OPTS            = [ '$INLINE_OPTS_NORMAL' ],
106     CXXFLAGS               = [ '-Wall', '-Woverloaded-virtual', '-Wno-long-long', '$INLINE_OPTS',
107                                '-pipe', '$CXXFLAGS_', '-fno-strict-aliasing' ],
108     CXXFLAGS_final         = [ '-O3' ],
109     CXXFLAGS_normal        = [ '-O2', '-g' ],
110     CXXFLAGS_debug         = [ '-O0', '-g' ],
111
112     CPPDEFINES             = [ '$expandLogOption', '$CPPDEFINES_' ],
113     CPPDEFINES_final       = [ 'SENF_PPI_NOTRACE', 'BOOST_NO_MT', 'NDEBUG', 'BOOST_DISABLE_ASSERTS' ],
114     CPPDEFINES_normal      = [ 'SENF_DEBUG' ],
115     CPPDEFINES_debug       = [ '$CPPDEFINES_normal' ],
116
117     LINKFLAGS              = [ '-rdynamic', '$LINKFLAGS_' ],
118     LINKFLAGS_final        = [ ],
119     LINKFLAGS_normal       = [ '-Wl,-S' ],
120     LINKFLAGS_debug        = [ '-g' ],
121 )
122 env.SetDefault(
123     PREFIX                 = '#/dist',
124     LIBINSTALLDIR          = '$PREFIX${syslayout and "/lib" or ""}',
125     BININSTALLDIR          = '$PREFIX${syslayout and "/bin" or ""}',
126     INCLUDEINSTALLDIR      = '$PREFIX${syslayout and "/include" or ""}',
127     CONFINSTALLDIR         = '${syslayout and "$LIBINSTALLDIR/senf" or "$PREFIX"}',
128     OBJINSTALLDIR          = '$CONFINSTALLDIR',
129     DOCINSTALLDIR          = '$PREFIX${syslayout and "/share/doc/senf" or "/manual"}',
130     SCONSINSTALLDIR        = '$CONFINSTALLDIR/site_scons',
131
132     BUILDDIR               = '${FLAVOR and "#/build/$FLAVOR" or "#"}',
133     LOCALLIBDIR            = '$BUILDDIR',
134
135     LIBSENF                = "senf",
136     LCOV                   = "lcov",
137     GENHTML                = "genhtml",
138     VALGRIND               = "valgrind",
139     SCONSBIN               = env.File("#/tools/scons"),
140     SCONSARGS              = ([ '-Q', '-j$CONCURRENCY_LEVEL' ] +
141                               [ '%s=%s' % (k,v) for k,v in ARGLIST ]),
142     SCONS                  = "@$SCONSBIN $SCONSARGS",
143     CONCURRENCY_LEVEL      = env.GetOption('num_jobs') or 1,
144     TOPDIR                 = env.Dir('#').abspath,
145     LIBADDSUFFIX           = '${FLAVOR and "_$FLAVOR" or ""}',
146     OBJADDSUFFIX           = '${LIBADDSUFFIX}',
147     FLAVOR                 = '',
148 )
149
150 # Set variables from command line
151 senfutil.parseArguments(
152     env,
153     BoolVariable('final', 'Build final (optimized) build', False),
154     BoolVariable('debug', 'Link in debug symbols', False),
155     BoolVariable('syslayout', 'Install in to system layout directories (lib/, include/ etc)', False),
156     BoolVariable('sparse_tests', 'Link tests against object files and not the senf lib', False)
157 )
158
159 # Add UNIX env vars matching IMPORT_ENV patterns into the execution environment
160 senfutil.importProcessEnv(env)
161
162 # Handle 'test_changes'
163 if 'test_changes' in COMMAND_LINE_TARGETS and not env.has_key('only_tests'):
164     import SparseTestHack
165     env['only_tests'] = " ".join(x.abspath for x in SparseTestHack.findSCMChanges(env))
166
167 if env.has_key('only_tests') : env['sparse_tests'] = True
168
169 Export('env')
170
171 ###########################################################################
172 # Configure
173
174 SConscript('SConfigure')
175
176 # Only add this here, after all configure checks have run
177
178 env.Append(LIBS = '$LIBSENF$LIBADDSUFFIX',
179            EXTRA_LIBS = [ '$BOOSTREGEXLIB', '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB',
180                           '$BOOSTFSLIB' ])
181
182 ###########################################################################
183
184 # Create Doxyfile.local otherwise doxygen will barf on this non-existent file
185 # Create it even when cleaning, to silence the doxygen builder warnings
186 if not os.path.exists("doclib/Doxyfile.local"):
187     Execute(Touch("doclib/Doxyfile.local"))
188
189 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp") \
190    and not os.environ.get("SCONS") and COMMAND_LINE_TARGETS != [ 'prepare' ]:
191     env.Execute([ "$SCONS prepare" ])
192
193 # Load SConscripts
194
195 SConscriptChdir(0)
196 SConscript("debian/SConscript")
197 SConscriptChdir(1)
198 if os.path.exists('SConscript.local') : SConscript('SConscript.local')
199 if env['sparse_tests']:
200     import SparseTestHack
201     SparseTestHack.setup(env)
202 if env.subst('$BUILDDIR') == '#':
203     SConscript("SConscript")
204 else:
205     SConscript("SConscript", variant_dir=env.subst('$BUILDDIR'), src_dir='#', duplicate=False)
206 SConscript("Examples/SConscript")
207 SConscript("HowTos/SConscript")
208 SConscript("doclib/SConscript")
209 if env['sparse_tests']:
210     verbose = 'test_changes' in COMMAND_LINE_TARGETS
211     SparseTestHack.build(env, verbose, verbose)
212
213 ###########################################################################
214 # Define build targets
215
216 #### install_all, default, all_tests, all
217 env.Install('${SCONSINSTALLDIR}', [ 'site_scons/__init__.py',
218                                     'site_scons/senfutil.py',
219                                     'site_scons/yaptu.py' ])
220 env.InstallDir('${SCONSINSTALLDIR}', [ 'site_scons/site_tools', 'site_scons/lib' ],
221                FILTER_SUFFIXES=[ '','.css','.pl','.py','.sh','.sty','.xml','.xsl','.yap' ])
222 env.Install('${INCLUDEINSTALLDIR}', 'boost_ext')
223 env.Install('${INCLUDEINSTALLDIR}/senf', 'senf/boost_intrusive')
224
225 env.Alias('install_all', env.FindInstalledFiles())
226 env.Alias('default', DEFAULT_TARGETS)
227 env.Alias('all_tests', env.FindAllBoostUnitTests())
228 env.Alias('test_changes', 'all_tests')
229 env.Alias('all', [ 'default', 'all_tests', 'examples', 'all_docs' ])
230
231 #### prepare and -c some
232 env.PhonyTarget('prepare', [], [])
233 env.PhonyTarget('some', [], [])
234
235 #### valgrind
236 env.Alias('all_valgrinds')
237 if env.get('HAVE_VALGRIND'):
238     for test in env.FindAllBoostUnitTests():
239         stamp = env.Command(test[0].dir.File('.test-valgrind.stamp'),
240                             [ test[0].dir.File('.test.bin'), 'tools/valgrind.sup' ],
241                             [ """$VALGRIND --tool=memcheck
242                                           --error-exitcode=1
243                                           --suppressions=${SOURCES[1]}
244                                           $VALGRINDARGS
245                                               ${SOURCES[0]} --result_code=no $BOOSTTESTARGS
246                               """.replace("\n"," "),
247                               Touch("$TARGET") ])
248         alias = env.Command(test[0].dir.File('valgrind'), stamp, [ env.NopAction() ])
249         env.Alias('all_valgrinds', alias)
250
251 ### lcov
252 env.PhonyTarget('lcov', [], [
253         '$SCONS'
254         '    debug=1'
255         '    BUILDDIR="#/build/lcov"'
256         '    CCFLAGS+="-fprofile-arcs -ftest-coverage"'
257         '    LIBS+="gcov"'
258         '        all_tests',
259         '$LCOV'
260         '    --follow'
261         '    --directory $TOPDIR/build/lcov/senf'
262         '    --capture'
263         '    --output-file /tmp/senf_lcov.info'
264         '    --base-directory $TOPDIR',
265         '$LCOV'
266         '    --output-file lcov.info'
267         '    --remove /tmp/senf_lcov.info "*/include/*" "*/boost/*" "*.test.*"',
268         '$GENHTML'
269         '    --output-directory doc/lcov'
270         '    --title all_tests lcov.info',
271         'rm /tmp/senf_lcov.info' ])
272 senfutil.CleanGlob(env, ['lcov','some','all'], [ '*.gcno', '*.gcda', '*.gcov' ])
273 env.Clean(['lcov', 'all'], [ 'lcov.info', env.Dir('doc/lcov'), env.Dir('build/lcov') ])
274
275 #### clean
276
277 env.Clean('all', ('.prepare-stamp', env.Dir('dist'), env.Dir('build')))
278
279 senfutil.CleanGlob(env, 'all', '$CLEAN_PATTERNS')
280 senfutil.CleanGlob(env, ['some', 'all'], '$CLEAN_SOME_PATTERNS')
281
282 if env.GetOption('clean') and 'all' in BUILD_TARGETS:
283     env.Depends('all', ('lcov', 'all_valgrinds'))
284     # Disable writing to the deleted .sconsign file
285     import SCons.SConsign
286     SCons.SConsign.write = lambda : None
287
288 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp"):
289     Execute(Touch(".prepare-stamp"))
290
291 ### execute targets on remote hosts
292 for target in COMMAND_LINE_TARGETS:
293     if '@' in target:
294         realtarget, host = target.split('@',1)
295         cwd=env.GetLaunchDir()
296         home=os.environ['HOME']+'/'
297         if cwd.startswith(home) : cwd = cwd[len(home):]
298         args = [ '$SCONSARGS' ]
299         if env.GetLaunchDir() != os.getcwd():
300             args.append('-u')
301         env.PhonyTarget(target, [], [ "ssh $HOST scons $SCONSARGS -C $DIR $RTARGET" ],
302                         HOST=host, RTARGET=realtarget, DIR=cwd, SCONSARGS=args)
303
304 env.PhonyTarget('clean', [], [
305         lambda **args: sys.stderr.write(
306             "=================================================================\n"
307             "'clean' is not a valid target, use the '-c' option instead:\n"
308             "    $ scons -c all\n"
309             "=================================================================\n") ])