4 import SENFSCons, senfutil
6 ###########################################################################
7 # Load utilities and setup libraries and configure build
11 env.Decider('MD5-timestamp')
12 env.EnsureSConsVersion(1,2)
14 # Load all the local SCons tools
15 senfutil.loadTools(env)
18 Additional top-level build targets:
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
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
36 The following additional targets may be called within subdirectories, either
37 using '$ scons -u <target>' or '$ scons <directory>/<target>:
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
43 When cleaning up using '$ scons -c <target>', some targets are handled specially:
45 all Remove everything generated by the build including temporary and
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.
51 You may execute targets on a remote host via ssh (if the directory layout is the
54 $ scons <target>@[<user>@]<host>
56 Some more elaborate unit tests may be enabled by setting appropritate variables
57 in the shell (unix) environment
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
64 SENF_WLAN_TEST_INTERFACE
65 WLAN interface to use for testing. The interface should not be
68 SENF_ETH_TEST_INTERFACE
69 Ethernet interface to use for testing. The interface should not
72 Some unit tests will only run when executed to 'root'.
76 expandLogOption = senfutil.expandLogOption,
77 CXXFLAGS_ = env.BuildTypeOptions('CXXFLAGS'),
78 CPPDEFINES_ = env.BuildTypeOptions('CPPDEFINES'),
79 LINKFLAGS_ = env.BuildTypeOptions('LINKFLAGS'),
82 IMPORT_ENV = [ 'PATH', 'HOME', 'SSH_*', 'SENF*', 'CCACHE_*', 'DISTCC_*' ],
84 CLEAN_SOME_PATTERNS = [ '*~', '#*#', '*.pyc', 'semantic.cache' ],
85 CLEAN_PATTERNS = [ '.sconsign*', '.sconf_temp' ],
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' ],
95 CPP_INCLUDE_EXTENSIONS = [ '.h', '.hh', '.ih', '.mpp', '.cci', '.ct', '.cti' ],
96 CPP_EXCLUDE_EXTENSIONS = [ '.test.hh' ],
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 "${profile and '-pg' or None}" ],
109 CXXFLAGS_final = [ '-O3' ],
110 CXXFLAGS_normal = [ '-O2', '-g' ],
111 CXXFLAGS_debug = [ '-O0', '-g' ],
113 CPPDEFINES = [ '$expandLogOption', '$CPPDEFINES_' ],
114 CPPDEFINES_final = [ 'SENF_PPI_NOTRACE', 'BOOST_NO_MT', 'NDEBUG', 'BOOST_DISABLE_ASSERTS' ],
115 CPPDEFINES_normal = [ 'SENF_DEBUG' ],
116 CPPDEFINES_debug = [ '$CPPDEFINES_normal' ],
118 LINKFLAGS = [ '-rdynamic', '$LINKFLAGS_', "${profile and '-pg' or None}" ],
119 LINKFLAGS_final = [ ],
120 LINKFLAGS_normal = [ '-Wl,-S' ],
121 LINKFLAGS_debug = [ '-g' ],
125 LIBINSTALLDIR = '$PREFIX${syslayout and "/lib" or ""}',
126 BININSTALLDIR = '$PREFIX${syslayout and "/bin" or ""}',
127 INCLUDEINSTALLDIR = '$PREFIX${syslayout and "/include" or ""}',
128 CONFINSTALLDIR = '${syslayout and "$LIBINSTALLDIR/senf" or "$PREFIX"}',
129 OBJINSTALLDIR = '$CONFINSTALLDIR',
130 DOCINSTALLDIR = '$PREFIX${syslayout and "/share/doc/senf" or "/manual"}',
131 SCONSINSTALLDIR = '$CONFINSTALLDIR/site_scons',
133 BUILDDIR = '${FLAVOR and "#/build/$FLAVOR" or "#"}',
134 LOCALLIBDIR = '$BUILDDIR',
139 VALGRIND = "valgrind",
140 SCONSBIN = env.File("#/tools/scons"),
141 SCONSARGS = ([ '-Q', '-j$CONCURRENCY_LEVEL' ] +
142 [ '%s=%s' % (k,v) for k,v in ARGLIST ]),
143 SCONS = "@$SCONSBIN $SCONSARGS",
144 CONCURRENCY_LEVEL = env.GetOption('num_jobs') or 1,
145 TOPDIR = env.Dir('#').abspath,
146 LIBADDSUFFIX = '${FLAVOR and "_$FLAVOR" or ""}',
147 OBJADDSUFFIX = '${LIBADDSUFFIX}',
153 # Set variables from command line
154 senfutil.parseArguments(
156 BoolVariable('final', 'Build final (optimized) build', False),
157 BoolVariable('debug', 'Link in debug symbols', False),
158 BoolVariable('profile', 'compile and link with the profiling enabled option', False),
159 BoolVariable('syslayout', 'Install in to system layout directories (lib/, include/ etc)', False),
160 BoolVariable('sparse_tests', 'Link tests against object files and not the senf lib', False)
163 # Add UNIX env vars matching IMPORT_ENV patterns into the execution environment
164 senfutil.importProcessEnv(env)
166 # Handle 'test_changes'
167 if 'test_changes' in COMMAND_LINE_TARGETS and not env.has_key('only_tests'):
168 import SparseTestHack
169 env['only_tests'] = " ".join(x.abspath for x in SparseTestHack.findSCMChanges(env))
171 if env.has_key('only_tests') : env['sparse_tests'] = True
175 ###########################################################################
178 SConscript('SConfigure')
180 # Only add this here, after all configure checks have run
182 env.Append(LIBS = '$LIBSENF$LIBADDSUFFIX',
183 EXTRA_LIBS = [ '$BOOSTREGEXLIB', '$BOOSTSIGNALSLIB',
186 ###########################################################################
188 # Create Doxyfile.local otherwise doxygen will barf on this non-existent file
189 # Create it even when cleaning, to silence the doxygen builder warnings
190 if not os.path.exists("doclib/Doxyfile.local"):
191 Execute(Touch("doclib/Doxyfile.local"))
193 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp") \
194 and not os.environ.get("SCONS") and COMMAND_LINE_TARGETS != [ 'prepare' ]:
195 env.Execute([ "$SCONS prepare" ])
200 SConscript("debian/SConscript")
202 if os.path.exists('SConscript.local') : SConscript('SConscript.local')
203 if env['sparse_tests']:
204 import SparseTestHack
205 SparseTestHack.setup(env)
206 if env.subst('$BUILDDIR') == '#':
207 SConscript("SConscript")
209 SConscript("SConscript", variant_dir=env.subst('$BUILDDIR'), src_dir='#', duplicate=False)
210 SConscript("Examples/SConscript")
211 SConscript("HowTos/SConscript")
212 SConscript("doclib/SConscript")
213 if env['sparse_tests']:
214 verbose = 'test_changes' in COMMAND_LINE_TARGETS
215 SparseTestHack.build(env, verbose, verbose)
217 ###########################################################################
218 # Define build targets
220 #### install_all, default, all_tests, all
221 env.Install('${SCONSINSTALLDIR}', [ 'site_scons/__init__.py',
222 'site_scons/senfutil.py',
223 'site_scons/yaptu.py' ])
224 env.InstallDir('${SCONSINSTALLDIR}', [ 'site_scons/site_tools', 'site_scons/lib' ],
225 FILTER_SUFFIXES=[ '','.css','.pl','.py','.sh','.sty','.xml','.xsl','.yap' ])
226 env.Install('${INCLUDEINSTALLDIR}', 'boost_ext')
227 env.Install('${INCLUDEINSTALLDIR}/senf', 'senf/boost_intrusive')
229 env.Alias('install_all', env.FindInstalledFiles())
230 env.Alias('default', DEFAULT_TARGETS)
231 env.Alias('all_tests', env.FindAllBoostUnitTests())
232 env.Alias('test_changes', 'all_tests')
233 env.Alias('all', [ 'default', 'all_tests', 'examples', 'all_docs' ])
235 #### prepare and -c some
236 env.PhonyTarget('prepare', [], [])
237 env.PhonyTarget('some', [], [])
240 env.Alias('all_valgrinds')
241 if env.get('HAVE_VALGRIND'):
242 for test in env.FindAllBoostUnitTests():
243 stamp = env.Command(test[0].dir.File('.test-valgrind.stamp'),
244 [ test[0].dir.File('.test.bin'), 'tools/valgrind.sup' ],
245 [ """$VALGRIND --tool=memcheck
247 --suppressions=${SOURCES[1]}
249 ${SOURCES[0]} --result_code=no $BOOSTTESTARGS
250 """.replace("\n"," "),
252 alias = env.Command(test[0].dir.File('valgrind'), stamp, [ env.NopAction() ])
253 env.Alias('all_valgrinds', alias)
256 env.PhonyTarget('lcov', [], [
259 ' BUILDDIR="#/build/lcov"'
260 ' CCFLAGS+="-fprofile-arcs -ftest-coverage"'
265 ' --directory $TOPDIR/build/lcov/senf'
267 ' --output-file /tmp/senf_lcov.info'
268 ' --base-directory $TOPDIR',
270 ' --output-file lcov.info'
271 ' --remove /tmp/senf_lcov.info "*/include/*" "*/boost/*" "*.test.*"',
273 ' --output-directory doc/lcov'
274 ' --title all_tests lcov.info',
275 'rm /tmp/senf_lcov.info' ])
276 senfutil.CleanGlob(env, ['lcov','some','all'], [ '*.gcno', '*.gcda', '*.gcov' ])
277 env.Clean(['lcov', 'all'], [ 'lcov.info', env.Dir('doc/lcov'), env.Dir('build/lcov') ])
281 env.Clean('all', ('.prepare-stamp', env.Dir('dist'), env.Dir('build')))
283 senfutil.CleanGlob(env, 'all', '$CLEAN_PATTERNS')
284 senfutil.CleanGlob(env, ['some', 'all'], '$CLEAN_SOME_PATTERNS')
286 if env.GetOption('clean') and 'all' in BUILD_TARGETS:
287 env.Depends('all', ('lcov', 'all_valgrinds'))
288 # Disable writing to the deleted .sconsign file
289 import SCons.SConsign
290 SCons.SConsign.write = lambda : None
292 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp"):
293 Execute(Touch(".prepare-stamp"))
295 ### execute targets on remote hosts
296 for target in COMMAND_LINE_TARGETS:
298 realtarget, host = target.split('@',1)
299 cwd=env.GetLaunchDir()
300 home=os.environ['HOME']+'/'
301 if cwd.startswith(home) : cwd = cwd[len(home):]
302 args = [ '$SCONSARGS' ]
303 if env.GetLaunchDir() != os.getcwd():
305 env.PhonyTarget(target, [], [ "ssh $HOST scons $SCONSARGS -C $DIR $RTARGET" ],
306 HOST=host, RTARGET=realtarget, DIR=cwd, SCONSARGS=args)
308 env.PhonyTarget('clean', [], [
309 lambda **args: sys.stderr.write(
310 "=================================================================\n"
311 "'clean' is not a valid target, use the '-c' option instead:\n"
313 "=================================================================\n") ])