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}',
151 # Set variables from command line
152 senfutil.parseArguments(
154 BoolVariable('final', 'Build final (optimized) build', False),
155 BoolVariable('debug', 'Link in debug symbols', False),
156 BoolVariable('profile', 'compile and link with the profiling enabled option', False),
157 BoolVariable('syslayout', 'Install in to system layout directories (lib/, include/ etc)', False),
158 BoolVariable('sparse_tests', 'Link tests against object files and not the senf lib', False)
161 # Add UNIX env vars matching IMPORT_ENV patterns into the execution environment
162 senfutil.importProcessEnv(env)
164 # Handle 'test_changes'
165 if 'test_changes' in COMMAND_LINE_TARGETS and not env.has_key('only_tests'):
166 import SparseTestHack
167 env['only_tests'] = " ".join(x.abspath for x in SparseTestHack.findSCMChanges(env))
169 if env.has_key('only_tests') : env['sparse_tests'] = True
173 ###########################################################################
176 SConscript('SConfigure')
178 # Only add this here, after all configure checks have run
180 env.Append(LIBS = '$LIBSENF$LIBADDSUFFIX',
181 EXTRA_LIBS = [ '$BOOSTREGEXLIB', '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB',
184 ###########################################################################
186 # Create Doxyfile.local otherwise doxygen will barf on this non-existent file
187 # Create it even when cleaning, to silence the doxygen builder warnings
188 if not os.path.exists("doclib/Doxyfile.local"):
189 Execute(Touch("doclib/Doxyfile.local"))
191 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp") \
192 and not os.environ.get("SCONS") and COMMAND_LINE_TARGETS != [ 'prepare' ]:
193 env.Execute([ "$SCONS prepare" ])
198 SConscript("debian/SConscript")
200 if os.path.exists('SConscript.local') : SConscript('SConscript.local')
201 if env['sparse_tests']:
202 import SparseTestHack
203 SparseTestHack.setup(env)
204 if env.subst('$BUILDDIR') == '#':
205 SConscript("SConscript")
207 SConscript("SConscript", variant_dir=env.subst('$BUILDDIR'), src_dir='#', duplicate=False)
208 SConscript("Examples/SConscript")
209 SConscript("HowTos/SConscript")
210 SConscript("doclib/SConscript")
211 if env['sparse_tests']:
212 verbose = 'test_changes' in COMMAND_LINE_TARGETS
213 SparseTestHack.build(env, verbose, verbose)
215 ###########################################################################
216 # Define build targets
218 #### install_all, default, all_tests, all
219 env.Install('${SCONSINSTALLDIR}', [ 'site_scons/__init__.py',
220 'site_scons/senfutil.py',
221 'site_scons/yaptu.py' ])
222 env.InstallDir('${SCONSINSTALLDIR}', [ 'site_scons/site_tools', 'site_scons/lib' ],
223 FILTER_SUFFIXES=[ '','.css','.pl','.py','.sh','.sty','.xml','.xsl','.yap' ])
224 env.Install('${INCLUDEINSTALLDIR}', 'boost_ext')
225 env.Install('${INCLUDEINSTALLDIR}/senf', 'senf/boost_intrusive')
227 env.Alias('install_all', env.FindInstalledFiles())
228 env.Alias('default', DEFAULT_TARGETS)
229 env.Alias('all_tests', env.FindAllBoostUnitTests())
230 env.Alias('test_changes', 'all_tests')
231 env.Alias('all', [ 'default', 'all_tests', 'examples', 'all_docs' ])
233 #### prepare and -c some
234 env.PhonyTarget('prepare', [], [])
235 env.PhonyTarget('some', [], [])
238 env.Alias('all_valgrinds')
239 if env.get('HAVE_VALGRIND'):
240 for test in env.FindAllBoostUnitTests():
241 stamp = env.Command(test[0].dir.File('.test-valgrind.stamp'),
242 [ test[0].dir.File('.test.bin'), 'tools/valgrind.sup' ],
243 [ """$VALGRIND --tool=memcheck
245 --suppressions=${SOURCES[1]}
247 ${SOURCES[0]} --result_code=no $BOOSTTESTARGS
248 """.replace("\n"," "),
250 alias = env.Command(test[0].dir.File('valgrind'), stamp, [ env.NopAction() ])
251 env.Alias('all_valgrinds', alias)
254 env.PhonyTarget('lcov', [], [
257 ' BUILDDIR="#/build/lcov"'
258 ' CCFLAGS+="-fprofile-arcs -ftest-coverage"'
263 ' --directory $TOPDIR/build/lcov/senf'
265 ' --output-file /tmp/senf_lcov.info'
266 ' --base-directory $TOPDIR',
268 ' --output-file lcov.info'
269 ' --remove /tmp/senf_lcov.info "*/include/*" "*/boost/*" "*.test.*"',
271 ' --output-directory doc/lcov'
272 ' --title all_tests lcov.info',
273 'rm /tmp/senf_lcov.info' ])
274 senfutil.CleanGlob(env, ['lcov','some','all'], [ '*.gcno', '*.gcda', '*.gcov' ])
275 env.Clean(['lcov', 'all'], [ 'lcov.info', env.Dir('doc/lcov'), env.Dir('build/lcov') ])
279 env.Clean('all', ('.prepare-stamp', env.Dir('dist'), env.Dir('build')))
281 senfutil.CleanGlob(env, 'all', '$CLEAN_PATTERNS')
282 senfutil.CleanGlob(env, ['some', 'all'], '$CLEAN_SOME_PATTERNS')
284 if env.GetOption('clean') and 'all' in BUILD_TARGETS:
285 env.Depends('all', ('lcov', 'all_valgrinds'))
286 # Disable writing to the deleted .sconsign file
287 import SCons.SConsign
288 SCons.SConsign.write = lambda : None
290 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp"):
291 Execute(Touch(".prepare-stamp"))
293 ### execute targets on remote hosts
294 for target in COMMAND_LINE_TARGETS:
296 realtarget, host = target.split('@',1)
297 cwd=env.GetLaunchDir()
298 home=os.environ['HOME']+'/'
299 if cwd.startswith(home) : cwd = cwd[len(home):]
300 args = [ '$SCONSARGS' ]
301 if env.GetLaunchDir() != os.getcwd():
303 env.PhonyTarget(target, [], [ "ssh $HOST scons $SCONSARGS -C $DIR $RTARGET" ],
304 HOST=host, RTARGET=realtarget, DIR=cwd, SCONSARGS=args)
306 env.PhonyTarget('clean', [], [
307 lambda **args: sys.stderr.write(
308 "=================================================================\n"
309 "'clean' is not a valid target, use the '-c' option instead:\n"
311 "=================================================================\n") ])