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_GCC = [ '-finline-limit=5000', '--param', 'inline-unit-growth=60' ],
105 INLINE_OPTS = [ '${str(CXX).split("/")[-1] == "g++" and "$INLINE_OPTS_GCC" or None}' ],
106 CXXFLAGS_CLANG = [ '-Wno-unneeded-internal-declaration' ], # needed for BOOST_PARAMETER_KEYWORD
107 CXXFLAGS = [ '-Wall', '-Woverloaded-virtual', '-Wno-long-long', '$INLINE_OPTS',
108 '-pipe', '$CXXFLAGS_', '-fno-strict-aliasing',
109 "${profile and '-pg' or None}",
110 '${str(CXX).split("/")[-1] == "clang++" and "$CXXFLAGS_CLANG" or None}' ],
111 CXXFLAGS_final = [ '-O3', '-fno-threadsafe-statics','-fno-stack-protector',
112 "${profile and ' ' or '-ffunction-sections'}" ],
113 CXXFLAGS_normal = [ '-O2', '-g' ],
114 CXXFLAGS_debug = [ '-O0', '-g' ],
116 CPPDEFINES = [ '$expandLogOption', '$CPPDEFINES_' ],
117 CPPDEFINES_final = [ 'SENF_PPI_NOTRACE', 'NDEBUG',
118 'BOOST_NO_MT', 'BOOST_DISABLE_ASSERTS', 'BOOST_DISABLE_THREADS' ],
119 CPPDEFINES_normal = [ 'SENF_DEBUG' ],
120 CPPDEFINES_debug = [ '$CPPDEFINES_normal' ],
122 LINKFLAGS = [ '-rdynamic', '$LINKFLAGS_', "${profile and '-pg' or None}" ],
123 LINKFLAGS_final = [ "${profile and ' ' or '-Wl,--gc-sections'}" ],
124 LINKFLAGS_normal = [ '-Wl,-S' ],
125 LINKFLAGS_debug = [ '-g' ],
129 LIBINSTALLDIR = '$PREFIX${syslayout and "/lib" or ""}',
130 BININSTALLDIR = '$PREFIX${syslayout and "/bin" or ""}',
131 INCLUDEINSTALLDIR = '$PREFIX${syslayout and "/include" or ""}',
132 CONFINSTALLDIR = '${syslayout and "$LIBINSTALLDIR/senf" or "$PREFIX"}',
133 OBJINSTALLDIR = '$CONFINSTALLDIR',
134 DOCINSTALLDIR = '$PREFIX${syslayout and "/share/doc/senf" or "/manual"}',
135 SCONSINSTALLDIR = '$CONFINSTALLDIR/site_scons',
137 BUILDDIR = '${FLAVOR and "#/build/$FLAVOR" or "#"}',
138 LOCALLIBDIR = '$BUILDDIR',
143 VALGRIND = "valgrind",
144 SCONSBIN = env.File("#/tools/scons"),
145 SCONSARGS = ([ '-Q', '-j$CONCURRENCY_LEVEL' ] +
146 [ '%s=%s' % (k,v) for k,v in ARGLIST ]),
147 SCONS = "@$SCONSBIN $SCONSARGS",
148 CONCURRENCY_LEVEL = env.GetOption('num_jobs') or 1,
149 TOPDIR = env.Dir('#').abspath,
150 LIBADDSUFFIX = '${FLAVOR and "_$FLAVOR" or ""}',
151 OBJADDSUFFIX = '${LIBADDSUFFIX}',
157 # Set variables from command line
158 senfutil.parseArguments(
160 BoolVariable('final', 'Build final (optimized) build', False),
161 BoolVariable('debug', 'Link in debug symbols', False),
162 BoolVariable('profile', 'compile and link with the profiling enabled option', False),
163 BoolVariable('syslayout', 'Install in to system layout directories (lib/, include/ etc)', False),
164 BoolVariable('sparse_tests', 'Link tests against object files and not the senf lib', False)
167 # Add UNIX env vars matching IMPORT_ENV patterns into the execution environment
168 senfutil.importProcessEnv(env)
170 # Handle 'test_changes'
171 if 'test_changes' in COMMAND_LINE_TARGETS and not env.has_key('only_tests'):
172 import SparseTestHack
173 env['only_tests'] = " ".join(x.abspath for x in SparseTestHack.findSCMChanges(env))
175 if env.has_key('only_tests') : env['sparse_tests'] = True
179 ###########################################################################
182 SConscript('SConfigure')
184 # Only add this here, after all configure checks have run
186 env.Append(LIBS = [ '$LIBSENF$LIBADDSUFFIX',
187 '$BOOSTREGEXLIB', '$BOOSTSIGNALSLIB',
188 '$BOOSTFSLIB', '$BOOSTSYSTEMLIB', '$BOOSTDATETIMELIB' ])
190 ###########################################################################
192 # Create Doxyfile.local otherwise doxygen will barf on this non-existent file
193 # Create it even when cleaning, to silence the doxygen builder warnings
194 if not os.path.exists("doclib/Doxyfile.local"):
195 Execute(Touch("doclib/Doxyfile.local"))
197 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp") \
198 and not os.environ.get("SCONS") and COMMAND_LINE_TARGETS != [ 'prepare' ]:
199 env.Execute([ "$SCONS prepare" ])
204 SConscript("debian/SConscript")
206 if os.path.exists('SConscript.local') : SConscript('SConscript.local')
207 if env['sparse_tests']:
208 import SparseTestHack
209 SparseTestHack.setup(env)
210 if env.subst('$BUILDDIR') == '#':
211 SConscript("SConscript")
213 SConscript("SConscript", variant_dir=env.subst('$BUILDDIR'), src_dir='#', duplicate=False)
214 SConscript("Examples/SConscript")
215 SConscript("HowTos/SConscript")
216 SConscript("doclib/SConscript")
217 if env['sparse_tests']:
218 verbose = 'test_changes' in COMMAND_LINE_TARGETS
219 SparseTestHack.build(env, verbose, verbose)
221 ###########################################################################
222 # Define build targets
224 #### install_all, default, all_tests, all
225 env.Install('${SCONSINSTALLDIR}', [ 'site_scons/__init__.py',
226 'site_scons/senfutil.py',
227 'site_scons/yaptu.py' ])
228 env.InstallDir('${SCONSINSTALLDIR}', [ 'site_scons/site_tools', 'site_scons/lib' ],
229 FILTER_SUFFIXES=[ '','.css','.pl','.py','.sh','.sty','.xml','.xsl','.yap' ])
230 env.Install('${INCLUDEINSTALLDIR}', 'boost_ext')
231 env.Install('${INCLUDEINSTALLDIR}/senf', 'senf/boost_intrusive')
233 env.Alias('install_all', env.FindInstalledFiles())
234 env.Alias('default', DEFAULT_TARGETS)
235 env.Alias('all_tests', env.FindAllBoostUnitTests())
236 env.Alias('test_changes', 'all_tests')
237 env.Alias('all', [ 'default', 'all_tests', 'examples', 'all_docs' ])
239 #### prepare and -c some
240 env.PhonyTarget('prepare', [], [])
241 env.PhonyTarget('some', [], [])
244 env.Alias('all_valgrinds')
245 if env.get('HAVE_VALGRIND'):
246 for test in env.FindAllBoostUnitTests():
247 stamp = env.Command(test[0].dir.File('.test-valgrind.stamp'),
248 [ test[0].dir.File('.test.bin'), 'tools/valgrind.sup' ],
249 [ """$VALGRIND --tool=memcheck
251 --suppressions=${SOURCES[1]}
253 ${SOURCES[0]} --result_code=no $BOOSTTESTARGS
254 """.replace("\n"," "),
256 alias = env.Command(test[0].dir.File('valgrind'), stamp, [ env.NopAction() ])
257 env.Alias('all_valgrinds', alias)
260 env.PhonyTarget('lcov', [], [
263 ' BUILDDIR="#/build/lcov"'
264 ' CCFLAGS+="-fprofile-arcs -ftest-coverage"'
269 ' --directory $TOPDIR/build/lcov/senf'
271 ' --output-file /tmp/senf_lcov.info'
272 ' --base-directory $TOPDIR',
274 ' --output-file lcov.info'
275 ' --remove /tmp/senf_lcov.info "*/include/*" "*/boost/*" "*.test.*"',
277 ' --output-directory doc/lcov'
278 ' --title all_tests lcov.info',
279 'rm /tmp/senf_lcov.info' ])
280 senfutil.CleanGlob(env, ['lcov','some','all'], [ '*.gcno', '*.gcda', '*.gcov' ])
281 env.Clean(['lcov', 'all'], [ 'lcov.info', env.Dir('doc/lcov'), env.Dir('build/lcov') ])
285 env.Clean('all', ('.prepare-stamp', env.Dir('dist'), env.Dir('build')))
287 senfutil.CleanGlob(env, 'all', '$CLEAN_PATTERNS')
288 senfutil.CleanGlob(env, ['some', 'all'], '$CLEAN_SOME_PATTERNS')
290 if env.GetOption('clean') and 'all' in BUILD_TARGETS:
291 env.Depends('all', ('lcov', 'all_valgrinds'))
292 # Disable writing to the deleted .sconsign file
293 import SCons.SConsign
294 SCons.SConsign.write = lambda : None
296 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp"):
297 Execute(Touch(".prepare-stamp"))
299 ### execute targets on remote hosts
300 for target in COMMAND_LINE_TARGETS:
302 realtarget, host = target.split('@',1)
303 cwd=env.GetLaunchDir()
304 home=os.environ['HOME']+'/'
305 if cwd.startswith(home) : cwd = cwd[len(home):]
306 args = [ '$SCONSARGS' ]
307 if env.GetLaunchDir() != os.getcwd():
309 env.PhonyTarget(target, [], [ "ssh $HOST scons $SCONSARGS -C $DIR $RTARGET" ],
310 HOST=host, RTARGET=realtarget, DIR=cwd, SCONSARGS=args)
312 env.PhonyTarget('clean', [], [
313 lambda **args: sys.stderr.write(
314 "=================================================================\n"
315 "'clean' is not a valid target, use the '-c' option instead:\n"
317 "=================================================================\n") ])