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 if env['PARSEFLAGS']:
164 env.MergeFlags(env['PARSEFLAGS'])
166 # Add UNIX env vars matching IMPORT_ENV patterns into the execution environment
167 senfutil.importProcessEnv(env)
169 # Handle 'test_changes'
170 if 'test_changes' in COMMAND_LINE_TARGETS and not env.has_key('only_tests'):
171 import SparseTestHack
172 env['only_tests'] = " ".join(x.abspath for x in SparseTestHack.findSCMChanges(env))
174 if env.has_key('only_tests') : env['sparse_tests'] = True
178 ###########################################################################
181 SConscript('SConfigure')
183 # Only add this here, after all configure checks have run
185 env.Append(LIBS = '$LIBSENF$LIBADDSUFFIX',
186 EXTRA_LIBS = [ '$BOOSTREGEXLIB', '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB',
189 ###########################################################################
191 # Create Doxyfile.local otherwise doxygen will barf on this non-existent file
192 # Create it even when cleaning, to silence the doxygen builder warnings
193 if not os.path.exists("doclib/Doxyfile.local"):
194 Execute(Touch("doclib/Doxyfile.local"))
196 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp") \
197 and not os.environ.get("SCONS") and COMMAND_LINE_TARGETS != [ 'prepare' ]:
198 env.Execute([ "$SCONS prepare" ])
203 SConscript("debian/SConscript")
205 if os.path.exists('SConscript.local') : SConscript('SConscript.local')
206 if env['sparse_tests']:
207 import SparseTestHack
208 SparseTestHack.setup(env)
209 if env.subst('$BUILDDIR') == '#':
210 SConscript("SConscript")
212 SConscript("SConscript", variant_dir=env.subst('$BUILDDIR'), src_dir='#', duplicate=False)
213 SConscript("Examples/SConscript")
214 SConscript("HowTos/SConscript")
215 SConscript("doclib/SConscript")
216 if env['sparse_tests']:
217 verbose = 'test_changes' in COMMAND_LINE_TARGETS
218 SparseTestHack.build(env, verbose, verbose)
220 ###########################################################################
221 # Define build targets
223 #### install_all, default, all_tests, all
224 env.Install('${SCONSINSTALLDIR}', [ 'site_scons/__init__.py',
225 'site_scons/senfutil.py',
226 'site_scons/yaptu.py' ])
227 env.InstallDir('${SCONSINSTALLDIR}', [ 'site_scons/site_tools', 'site_scons/lib' ],
228 FILTER_SUFFIXES=[ '','.css','.pl','.py','.sh','.sty','.xml','.xsl','.yap' ])
229 env.Install('${INCLUDEINSTALLDIR}', 'boost_ext')
230 env.Install('${INCLUDEINSTALLDIR}/senf', 'senf/boost_intrusive')
232 env.Alias('install_all', env.FindInstalledFiles())
233 env.Alias('default', DEFAULT_TARGETS)
234 env.Alias('all_tests', env.FindAllBoostUnitTests())
235 env.Alias('test_changes', 'all_tests')
236 env.Alias('all', [ 'default', 'all_tests', 'examples', 'all_docs' ])
238 #### prepare and -c some
239 env.PhonyTarget('prepare', [], [])
240 env.PhonyTarget('some', [], [])
243 env.Alias('all_valgrinds')
244 if env.get('HAVE_VALGRIND'):
245 for test in env.FindAllBoostUnitTests():
246 stamp = env.Command(test[0].dir.File('.test-valgrind.stamp'),
247 [ test[0].dir.File('.test.bin'), 'tools/valgrind.sup' ],
248 [ """$VALGRIND --tool=memcheck
250 --suppressions=${SOURCES[1]}
252 ${SOURCES[0]} --result_code=no $BOOSTTESTARGS
253 """.replace("\n"," "),
255 alias = env.Command(test[0].dir.File('valgrind'), stamp, [ env.NopAction() ])
256 env.Alias('all_valgrinds', alias)
259 env.PhonyTarget('lcov', [], [
262 ' BUILDDIR="#/build/lcov"'
263 ' CCFLAGS+="-fprofile-arcs -ftest-coverage"'
268 ' --directory $TOPDIR/build/lcov/senf'
270 ' --output-file /tmp/senf_lcov.info'
271 ' --base-directory $TOPDIR',
273 ' --output-file lcov.info'
274 ' --remove /tmp/senf_lcov.info "*/include/*" "*/boost/*" "*.test.*"',
276 ' --output-directory doc/lcov'
277 ' --title all_tests lcov.info',
278 'rm /tmp/senf_lcov.info' ])
279 senfutil.CleanGlob(env, ['lcov','some','all'], [ '*.gcno', '*.gcda', '*.gcov' ])
280 env.Clean(['lcov', 'all'], [ 'lcov.info', env.Dir('doc/lcov'), env.Dir('build/lcov') ])
284 env.Clean('all', ('.prepare-stamp', env.Dir('dist'), env.Dir('build')))
286 senfutil.CleanGlob(env, 'all', '$CLEAN_PATTERNS')
287 senfutil.CleanGlob(env, ['some', 'all'], '$CLEAN_SOME_PATTERNS')
289 if env.GetOption('clean') and 'all' in BUILD_TARGETS:
290 env.Depends('all', ('lcov', 'all_valgrinds'))
291 # Disable writing to the deleted .sconsign file
292 import SCons.SConsign
293 SCons.SConsign.write = lambda : None
295 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp"):
296 Execute(Touch(".prepare-stamp"))
298 ### execute targets on remote hosts
299 for target in COMMAND_LINE_TARGETS:
301 realtarget, host = target.split('@',1)
302 cwd=env.GetLaunchDir()
303 home=os.environ['HOME']+'/'
304 if cwd.startswith(home) : cwd = cwd[len(home):]
305 args = [ '$SCONSARGS' ]
306 if env.GetLaunchDir() != os.getcwd():
308 env.PhonyTarget(target, [], [ "ssh $HOST scons $SCONSARGS -C $DIR $RTARGET" ],
309 HOST=host, RTARGET=realtarget, DIR=cwd, SCONSARGS=args)
311 env.PhonyTarget('clean', [], [
312 lambda **args: sys.stderr.write(
313 "=================================================================\n"
314 "'clean' is not a valid target, use the '-c' option instead:\n"
316 "=================================================================\n") ])