3 import sys, os.path, fnmatch
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 You may execute targets on a remote host (if the directory layout is the same)
39 scons <target>@[<user>@]<host>
41 Some more elaborate unit tests may be enabled by setting appropritate variables
42 in the shell (unix) environment
44 SENF_TIMING_CRITICAL_TESTS
45 Enables unit tests which depend on timing measurements. These
46 unit tests should only be run on a single core and an otherwise
49 SENF_WLAN_TEST_INTERFACE
50 WLAN interface to use for testing. The interface should not be
53 SENF_ETH_TEST_INTERFACE
54 Ethernet interface to use for testing. The interface should not
57 Some unit tests will only run when executed to 'root'.
61 expandLogOption = senfutil.expandLogOption,
62 CXXFLAGS_ = env.BuildTypeOptions('CXXFLAGS'),
63 CPPDEFINES_ = env.BuildTypeOptions('CPPDEFINES'),
64 LINKFLAGS_ = env.BuildTypeOptions('LINKFLAGS'),
67 IMPORT_ENV = [ 'PATH', 'HOME', 'SSH_*', 'SENF*', 'CCACHE_*', 'DISTCC_*' ],
69 CLEAN_PATTERNS = [ '*~', '#*#', '*.pyc', 'semantic.cache', '.sconsign*',
72 CPPPATH = [ '#', '$BUILDDIR',
73 '${NEED_BOOST_EXT and "#/boost_ext" or None}' ],
74 LOCALLIBDIR = '$BUILDDIR',
75 LIBPATH = [ '$LOCALLIBDIR' ],
76 LIBS = [ '$EXTRA_LIBS' ],
77 EXTRA_LIBS = [ 'rt' ],
78 TEST_EXTRA_LIBS = [ ],
79 VALGRINDARGS = [ '--num-callers=50' ],
81 CPP_INCLUDE_EXTENSIONS = [ '.h', '.hh', '.ih', '.mpp', '.cci', '.ct', '.cti' ],
82 CPP_EXCLUDE_EXTENSIONS = [ '.test.hh' ],
84 # INLINE_OPTS_DEBUG are insane. Only useful for inline debugging. Need at least 1G free RAM
85 INLINE_OPTS_DEBUG = [ '-finline-limit=20000', '-fvisibility-inlines-hidden',
86 '-fno-inline-functions', '-Winline'
87 '--param','large-function-growth=10000',
88 '--param', 'large-function-insns=10000',
89 '--param','inline-unit-growth=10000' ],
90 INLINE_OPTS_NORMAL = [ '-finline-limit=5000' ],
91 INLINE_OPTS = [ '$INLINE_OPTS_NORMAL' ],
92 CXXFLAGS = [ '-Wall', '-Woverloaded-virtual', '-Wno-long-long', '$INLINE_OPTS',
93 '-pipe', '$CXXFLAGS_', '-fno-strict-aliasing' ],
94 CXXFLAGS_final = [ '-O3' ],
95 CXXFLAGS_normal = [ '-O2', '-g' ],
96 CXXFLAGS_debug = [ '-O0', '-g' ],
98 CPPDEFINES = [ '$expandLogOption', '$CPPDEFINES_' ],
99 CPPDEFINES_final = [ 'SENF_PPI_NOTRACE', 'BOOST_NO_MT' ],
100 CPPDEFINES_normal = [ 'SENF_DEBUG' ],
101 CPPDEFINES_debug = [ '$CPPDEFINES_normal' ],
103 LINKFLAGS = [ '-rdynamic', '$LINKFLAGS_' ],
104 LINKFLAGS_final = [ ],
105 LINKFLAGS_normal = [ '-Wl,-S' ],
106 LINKFLAGS_debug = [ '-g' ],
110 LIBINSTALLDIR = '$PREFIX${syslayout and "/lib" or ""}',
111 BININSTALLDIR = '$PREFIX${syslayout and "/bin" or ""}',
112 INCLUDEINSTALLDIR = '$PREFIX${syslayout and "/include" or ""}',
113 CONFINSTALLDIR = '${syslayout and "$LIBINSTALLDIR/senf" or "$PREFIX"}',
114 OBJINSTALLDIR = '$CONFINSTALLDIR',
115 DOCINSTALLDIR = '$PREFIX${syslayout and "/share/doc/senf" or "/manual"}',
116 SCONSINSTALLDIR = '$CONFINSTALLDIR/site_scons',
118 BUILDDIR = '${FLAVOR and "#/build/$FLAVOR" or "#"}',
123 VALGRIND = "valgrind",
124 SCONSBIN = env.File("#/tools/scons"),
125 SCONSARGS = ([ '-Q', '-j$CONCURRENCY_LEVEL' ] +
126 [ '%s=%s' % (k,v) for k,v in ARGUMENTS.iteritems() ]),
127 SCONS = "@$SCONSBIN $SCONSARGS",
128 CONCURRENCY_LEVEL = env.GetOption('num_jobs') or 1,
129 TOPDIR = env.Dir('#').abspath,
130 LIBADDSUFFIX = '${FLAVOR and "_$FLAVOR" or ""}',
131 OBJADDSUFFIX = '${LIBADDSUFFIX}',
135 # Set variables from command line
136 senfutil.parseArguments(
138 BoolVariable('final', 'Build final (optimized) build', False),
139 BoolVariable('debug', 'Link in debug symbols', False),
140 BoolVariable('syslayout', 'Install in to system layout directories (lib/, include/ etc)', False),
141 BoolVariable('sparse_tests', 'Link tests against object files and not the senf lib', False)
144 # Add UNIX env vars matching IMPORT_ENV patterns into the execution environment
145 senfutil.importProcessEnv(env)
147 # Handle 'test_changes'
148 if 'test_changes' in COMMAND_LINE_TARGETS and not env.has_key('only_tests'):
149 import SparseTestHack
150 env['only_tests'] = " ".join(x.abspath for x in SparseTestHack.findSCMChanges(env))
152 if env.has_key('only_tests') : env['sparse_tests'] = True
156 ###########################################################################
159 SConscript('SConfigure')
161 # Only add this here, after all configure checks have run
163 env.Append(LIBS = '$LIBSENF$LIBADDSUFFIX',
164 EXTRA_LIBS = [ '$BOOSTREGEXLIB', '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB',
167 ###########################################################################
169 # Create Doxyfile.local otherwise doxygen will barf on this non-existent file
170 # Create it even when cleaning, to silence the doxygen builder warnings
171 if not os.path.exists("doclib/Doxyfile.local"):
172 Execute(Touch("doclib/Doxyfile.local"))
174 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp") \
175 and not os.environ.get("SCONS") and COMMAND_LINE_TARGETS != [ 'prepare' ]:
176 env.Execute([ "$SCONS prepare" ])
181 SConscript("debian/SConscript")
183 if os.path.exists('SConscript.local') : SConscript('SConscript.local')
184 if env['sparse_tests']:
185 import SparseTestHack
186 SparseTestHack.setup(env)
187 if env.subst('$BUILDDIR') == '#':
188 SConscript("SConscript")
190 SConscript("SConscript", variant_dir=env.subst('$BUILDDIR'), src_dir='#', duplicate=False)
191 SConscript("Examples/SConscript")
192 SConscript("HowTos/SConscript")
193 SConscript("doclib/SConscript")
194 if env['sparse_tests']:
195 verbose = 'test_changes' in COMMAND_LINE_TARGETS
196 SparseTestHack.build(env, verbose, verbose)
198 ###########################################################################
199 # Define build targets
201 #### install_all, default, all_tests, all
202 env.Install('${SCONSINSTALLDIR}', [ 'site_scons/__init__.py',
203 'site_scons/senfutil.py',
204 'site_scons/senfconf.py',
205 'site_scons/yaptu.py' ])
206 env.InstallDir('${SCONSINSTALLDIR}', [ 'site_scons/site_tools', 'site_scons/lib' ],
207 FILTER_SUFFIXES=[ '','.css','.pl','.py','.sh','.sty','.xml','.xsl','.yap' ])
208 env.Install('${INCLUDEINSTALLDIR}', 'boost_ext')
209 env.Install('${INCLUDEINSTALLDIR}/senf', 'senf/boost_intrusive')
211 env.Alias('install_all', env.FindInstalledFiles())
212 env.Alias('default', DEFAULT_TARGETS)
213 env.Alias('all_tests', env.FindAllBoostUnitTests())
214 env.Alias('test_changes', 'all_tests')
215 env.Alias('all', [ 'default', 'all_tests', 'examples', 'all_docs' ])
218 env.PhonyTarget('prepare', [], [])
221 env.Alias('all_valgrinds')
222 if env['HAVE_VALGRIND']:
223 for test in env.FindAllBoostUnitTests():
224 stamp = env.Command(test[0].dir.File('.test-valgrind.stamp'),
225 [ test[0].dir.File('.test.bin'), 'tools/valgrind.sup' ],
226 [ """$VALGRIND --tool=memcheck
228 --suppressions=${SOURCES[1]}
230 ${SOURCES[0]} --result_code=no $BOOSTTESTARGS
231 """.replace("\n"," "),
233 alias = env.Command(test[0].dir.File('valgrind'), stamp, [ env.NopAction() ])
234 env.Alias('all_valgrinds', alias)
237 env.PhonyTarget('lcov', [], [
238 '$SCONS debug=1 BUILDDIR="#/build/lcov" CCFLAGS+="-fprofile-arcs -ftest-coverage" LIBS+="gcov" all_tests',
239 '$LCOV --follow --directory $TOPDIR/build/lcov/senf --capture --output-file /tmp/senf_lcov.info --base-directory $TOPDIR',
240 '$LCOV --output-file lcov.info --remove /tmp/senf_lcov.info "*/include/*" "*/boost/*" "*.test.*" ',
241 '$GENHTML --output-directory doc/lcov --title all_tests lcov.info',
242 'rm /tmp/senf_lcov.info' ])
243 if env.GetOption('clean'):
244 env.Clean('lcov', [ os.path.join(path,f)
245 for path, subdirs, files in os.walk('.')
246 for pattern in ('*.gcno', '*.gcda', '*.gcov')
247 for f in fnmatch.filter(files,pattern) ] +
248 [ 'lcov.info', env.Dir('doc/lcov'), env.Dir('build/lcov') ])
251 env.Clean('all', ('.prepare-stamp', env.Dir('dist'), env.Dir('build')))
252 if env.GetOption('clean') : env.Depends('all', ('lcov', 'all_valgrinds'))
254 if env.GetOption('clean') and 'all' in BUILD_TARGETS:
255 env.Clean('all', [ os.path.join(path,f)
256 for path, subdirs, files in os.walk('.')
257 for pattern in env['CLEAN_PATTERNS']
258 for f in fnmatch.filter(files,pattern) ])
259 # Disable writing to the deleted .sconsign file
260 import SCons.SConsign
261 SCons.SConsign.write = lambda : None
263 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp"):
264 Execute(Touch(".prepare-stamp"))
266 ### execute targets on remote hosts
267 for target in COMMAND_LINE_TARGETS:
269 realtarget, host = target.split('@',1)
270 cwd=env.GetLaunchDir()
271 home=os.environ['HOME']+'/'
272 if cwd.startswith(home) : cwd = cwd[len(home):]
273 args = [ '$SCONSARGS' ]
274 if env.GetLaunchDir() != os.getcwd():
276 env.PhonyTarget(target, [], [ "ssh $HOST scons $SCONSARGS -C $DIR $RTARGET" ],
277 HOST=host, RTARGET=realtarget, DIR=cwd, SCONSARGS=args)