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', '-fno-threadsafe-statics','-fno-stack-protector',
110 '-ffunction-sections' ],
111 CXXFLAGS_normal = [ '-O2', '-g' ],
112 CXXFLAGS_debug = [ '-O0', '-g' ],
114 CPPDEFINES = [ '$expandLogOption', '$CPPDEFINES_' ],
115 CPPDEFINES_final = [ 'SENF_PPI_NOTRACE', 'NDEBUG',
116 'BOOST_NO_MT', 'BOOST_DISABLE_ASSERTS', 'BOOST_DISABLE_THREADS' ],
117 CPPDEFINES_normal = [ 'SENF_DEBUG' ],
118 CPPDEFINES_debug = [ '$CPPDEFINES_normal' ],
120 LINKFLAGS = [ '-rdynamic', '$LINKFLAGS_', "${profile and '-pg' or None}" ],
121 LINKFLAGS_final = [ '-Wl,--gc-sections' ],
122 LINKFLAGS_normal = [ '-Wl,-S' ],
123 LINKFLAGS_debug = [ '-g' ],
127 LIBINSTALLDIR = '$PREFIX${syslayout and "/lib" or ""}',
128 BININSTALLDIR = '$PREFIX${syslayout and "/bin" or ""}',
129 INCLUDEINSTALLDIR = '$PREFIX${syslayout and "/include" or ""}',
130 CONFINSTALLDIR = '${syslayout and "$LIBINSTALLDIR/senf" or "$PREFIX"}',
131 OBJINSTALLDIR = '$CONFINSTALLDIR',
132 DOCINSTALLDIR = '$PREFIX${syslayout and "/share/doc/senf" or "/manual"}',
133 SCONSINSTALLDIR = '$CONFINSTALLDIR/site_scons',
135 BUILDDIR = '${FLAVOR and "#/build/$FLAVOR" or "#"}',
136 LOCALLIBDIR = '$BUILDDIR',
141 VALGRIND = "valgrind",
142 SCONSBIN = env.File("#/tools/scons"),
143 SCONSARGS = ([ '-Q', '-j$CONCURRENCY_LEVEL' ] +
144 [ '%s=%s' % (k,v) for k,v in ARGLIST ]),
145 SCONS = "@$SCONSBIN $SCONSARGS",
146 CONCURRENCY_LEVEL = env.GetOption('num_jobs') or 1,
147 TOPDIR = env.Dir('#').abspath,
148 LIBADDSUFFIX = '${FLAVOR and "_$FLAVOR" or ""}',
149 OBJADDSUFFIX = '${LIBADDSUFFIX}',
155 # Set variables from command line
156 senfutil.parseArguments(
158 BoolVariable('final', 'Build final (optimized) build', False),
159 BoolVariable('debug', 'Link in debug symbols', False),
160 BoolVariable('profile', 'compile and link with the profiling enabled option', False),
161 BoolVariable('syslayout', 'Install in to system layout directories (lib/, include/ etc)', False),
162 BoolVariable('sparse_tests', 'Link tests against object files and not the senf lib', False)
165 # Add UNIX env vars matching IMPORT_ENV patterns into the execution environment
166 senfutil.importProcessEnv(env)
168 # Handle 'test_changes'
169 if 'test_changes' in COMMAND_LINE_TARGETS and not env.has_key('only_tests'):
170 import SparseTestHack
171 env['only_tests'] = " ".join(x.abspath for x in SparseTestHack.findSCMChanges(env))
173 if env.has_key('only_tests') : env['sparse_tests'] = True
177 ###########################################################################
180 SConscript('SConfigure')
182 # Only add this here, after all configure checks have run
184 env.Append(LIBS = [ '$LIBSENF$LIBADDSUFFIX',
185 '$BOOSTREGEXLIB', '$BOOSTSIGNALSLIB',
186 '$BOOSTFSLIB', '$BOOSTSYSTEMLIB' ])
188 ###########################################################################
190 # Create Doxyfile.local otherwise doxygen will barf on this non-existent file
191 # Create it even when cleaning, to silence the doxygen builder warnings
192 if not os.path.exists("doclib/Doxyfile.local"):
193 Execute(Touch("doclib/Doxyfile.local"))
195 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp") \
196 and not os.environ.get("SCONS") and COMMAND_LINE_TARGETS != [ 'prepare' ]:
197 env.Execute([ "$SCONS prepare" ])
202 SConscript("debian/SConscript")
204 if os.path.exists('SConscript.local') : SConscript('SConscript.local')
205 if env['sparse_tests']:
206 import SparseTestHack
207 SparseTestHack.setup(env)
208 if env.subst('$BUILDDIR') == '#':
209 SConscript("SConscript")
211 SConscript("SConscript", variant_dir=env.subst('$BUILDDIR'), src_dir='#', duplicate=False)
212 SConscript("Examples/SConscript")
213 SConscript("HowTos/SConscript")
214 SConscript("doclib/SConscript")
215 if env['sparse_tests']:
216 verbose = 'test_changes' in COMMAND_LINE_TARGETS
217 SparseTestHack.build(env, verbose, verbose)
219 ###########################################################################
220 # Define build targets
222 #### install_all, default, all_tests, all
223 env.Install('${SCONSINSTALLDIR}', [ 'site_scons/__init__.py',
224 'site_scons/senfutil.py',
225 'site_scons/yaptu.py' ])
226 env.InstallDir('${SCONSINSTALLDIR}', [ 'site_scons/site_tools', 'site_scons/lib' ],
227 FILTER_SUFFIXES=[ '','.css','.pl','.py','.sh','.sty','.xml','.xsl','.yap' ])
228 env.Install('${INCLUDEINSTALLDIR}', 'boost_ext')
229 env.Install('${INCLUDEINSTALLDIR}/senf', 'senf/boost_intrusive')
231 env.Alias('install_all', env.FindInstalledFiles())
232 env.Alias('default', DEFAULT_TARGETS)
233 env.Alias('all_tests', env.FindAllBoostUnitTests())
234 env.Alias('test_changes', 'all_tests')
235 env.Alias('all', [ 'default', 'all_tests', 'examples', 'all_docs' ])
237 #### prepare and -c some
238 env.PhonyTarget('prepare', [], [])
239 env.PhonyTarget('some', [], [])
242 env.Alias('all_valgrinds')
243 if env.get('HAVE_VALGRIND'):
244 for test in env.FindAllBoostUnitTests():
245 stamp = env.Command(test[0].dir.File('.test-valgrind.stamp'),
246 [ test[0].dir.File('.test.bin'), 'tools/valgrind.sup' ],
247 [ """$VALGRIND --tool=memcheck
249 --suppressions=${SOURCES[1]}
251 ${SOURCES[0]} --result_code=no $BOOSTTESTARGS
252 """.replace("\n"," "),
254 alias = env.Command(test[0].dir.File('valgrind'), stamp, [ env.NopAction() ])
255 env.Alias('all_valgrinds', alias)
258 env.PhonyTarget('lcov', [], [
261 ' BUILDDIR="#/build/lcov"'
262 ' CCFLAGS+="-fprofile-arcs -ftest-coverage"'
267 ' --directory $TOPDIR/build/lcov/senf'
269 ' --output-file /tmp/senf_lcov.info'
270 ' --base-directory $TOPDIR',
272 ' --output-file lcov.info'
273 ' --remove /tmp/senf_lcov.info "*/include/*" "*/boost/*" "*.test.*"',
275 ' --output-directory doc/lcov'
276 ' --title all_tests lcov.info',
277 'rm /tmp/senf_lcov.info' ])
278 senfutil.CleanGlob(env, ['lcov','some','all'], [ '*.gcno', '*.gcda', '*.gcov' ])
279 env.Clean(['lcov', 'all'], [ 'lcov.info', env.Dir('doc/lcov'), env.Dir('build/lcov') ])
283 env.Clean('all', ('.prepare-stamp', env.Dir('dist'), env.Dir('build')))
285 senfutil.CleanGlob(env, 'all', '$CLEAN_PATTERNS')
286 senfutil.CleanGlob(env, ['some', 'all'], '$CLEAN_SOME_PATTERNS')
288 if env.GetOption('clean') and 'all' in BUILD_TARGETS:
289 env.Depends('all', ('lcov', 'all_valgrinds'))
290 # Disable writing to the deleted .sconsign file
291 import SCons.SConsign
292 SCons.SConsign.write = lambda : None
294 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp"):
295 Execute(Touch(".prepare-stamp"))
297 ### execute targets on remote hosts
298 for target in COMMAND_LINE_TARGETS:
300 realtarget, host = target.split('@',1)
301 cwd=env.GetLaunchDir()
302 home=os.environ['HOME']+'/'
303 if cwd.startswith(home) : cwd = cwd[len(home):]
304 args = [ '$SCONSARGS' ]
305 if env.GetLaunchDir() != os.getcwd():
307 env.PhonyTarget(target, [], [ "ssh $HOST scons $SCONSARGS -C $DIR $RTARGET" ],
308 HOST=host, RTARGET=realtarget, DIR=cwd, SCONSARGS=args)
310 env.PhonyTarget('clean', [], [
311 lambda **args: sys.stderr.write(
312 "=================================================================\n"
313 "'clean' is not a valid target, use the '-c' option instead:\n"
315 "=================================================================\n") ])