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>
43 ENV = { 'PATH' : os.environ.get('PATH'),
44 'HOME' : os.environ.get('HOME'),
45 'SSH_AGENT_PID': os.environ.get('SSH_AGENT_PID'),
46 'SSH_AUTH_SOCK': os.environ.get('SSH_AUTH_SOCK') },
47 CLEAN_PATTERNS = [ '*~', '#*#', '*.pyc', 'semantic.cache', '.sconsign*' ],
49 BUILDDIR = '${FLAVOR and "#/build/$FLAVOR" or "#"}',
50 CPPPATH = [ '$BUILDDIR', '#' ],
51 LOCALLIBDIR = '$BUILDDIR',
52 LIBPATH = [ '$LOCALLIBDIR' ],
53 LIBS = [ '$LIBSENF$LIBADDSUFFIX', '$EXTRA_LIBS' ],
54 EXTRA_LIBS = [ 'rt', '$BOOSTREGEXLIB', '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB',
56 TEST_EXTRA_LIBS = [ ],
57 VALGRINDARGS = [ '--num-callers=50' ],
60 LIBINSTALLDIR = '$PREFIX${syslayout and "/lib" or ""}',
61 BININSTALLDIR = '$PREFIX${syslayout and "/bin" or ""}',
62 INCLUDEINSTALLDIR = '$PREFIX${syslayout and "/include" or ""}',
63 CONFINSTALLDIR = '${syslayout and "$LIBINSTALLDIR/senf" or "$PREFIX"}',
64 OBJINSTALLDIR = '$CONFINSTALLDIR',
65 DOCINSTALLDIR = '$PREFIX${syslayout and "/share/doc/senf" or "/manual"}',
66 SCONSINSTALLDIR = '$CONFINSTALLDIR/site_scons',
68 CPP_INCLUDE_EXTENSIONS = [ '.h', '.hh', '.ih', '.mpp', '.cci', '.ct', '.cti' ],
69 CPP_EXCLUDE_EXTENSIONS = [ '.test.hh' ],
71 # These options are insane. Only useful for inline debugging. Need at least 1G free RAM
72 INLINE_OPTS_DEBUG = [ '-finline-limit=20000', '-fvisibility-inlines-hidden',
73 '-fno-inline-functions', '-Winline'
74 '--param','large-function-growth=10000',
75 '--param', 'large-function-insns=10000',
76 '--param','inline-unit-growth=10000' ],
77 INLINE_OPTS_NORMAL = [ '-finline-limit=5000' ],
78 INLINE_OPTS = [ '$INLINE_OPTS_NORMAL' ],
79 CXXFLAGS = [ '-Wall', '-Woverloaded-virtual', '-Wno-long-long', '$INLINE_OPTS',
81 CXXFLAGS_ = senfutil.BuildTypeOptions('CXXFLAGS'),
82 CXXFLAGS_final = [ '-O3' ],
83 CXXFLAGS_normal = [ '-O0', '-g' ],
84 CXXFLAGS_debug = [ '$CXXFLAGS_normal' ],
86 CPPDEFINES = [ '$expandLogOption', '$CPPDEFINES_' ],
87 expandLogOption = senfutil.expandLogOption,
88 CPPDEFINES_ = senfutil.BuildTypeOptions('CPPDEFINES'),
89 CPPDEFINES_final = [ ],
90 CPPDEFINES_normal = [ 'SENF_DEBUG' ],
91 CPPDEFINES_debug = [ '$CPPDEFINES_normal' ],
93 LINKFLAGS = [ '-rdynamic', '$LINKFLAGS_' ],
94 LINKFLAGS_ = senfutil.BuildTypeOptions('LINKFLAGS'),
95 LINKFLAGS_final = [ ],
96 LINKFLAGS_normal = [ '-Wl,-S' ],
97 LINKFLAGS_debug = [ '-g' ],
104 SCONSBIN = env.File("#/tools/scons"),
105 SCONSARGS = [ '-Q', '-j$CONCURRENCY_LEVEL', 'debug=$debug', 'final=$final' ] + \
106 [ '%s=%s' % (k,v) for k,v in ARGUMENTS.iteritems() ],
107 SCONS = "@$SCONSBIN $SCONSARGS",
108 CONCURRENCY_LEVEL = env.GetOption('num_jobs') or 1,
109 TOPDIR = env.Dir('#').abspath,
110 LIBADDSUFFIX = '${FLAVOR and "_$FLAVOR" or ""}',
111 OBJADDSUFFIX = '${LIBADDSUFFIX}',
115 # Set variables from command line
116 senfutil.parseArguments(
118 BoolVariable('final', 'Build final (optimized) build', False),
119 BoolVariable('debug', 'Link in debug symbols', False),
120 BoolVariable('syslayout', 'Install in to system layout directories (lib/, include/ etc)', False),
121 BoolVariable('sparse_tests', 'Link tests against object files and not the senf lib', False)
124 if 'test_changes' in COMMAND_LINE_TARGETS and not env.has_key('only_tests'):
125 import SparseTestHack
126 env['only_tests'] = " ".join(x.abspath for x in SparseTestHack.findSCMChanges(env))
128 if env.has_key('only_tests') : env['sparse_tests'] = True
131 # Create Doxyfile.local otherwise doxygen will barf on this non-existent file
132 # Create it even when cleaning, to silence the doxygen builder warnings
133 if not os.path.exists("doclib/Doxyfile.local"):
134 Execute(Touch("doclib/Doxyfile.local"))
136 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp") \
137 and not os.environ.get("SCONS") and COMMAND_LINE_TARGETS != [ 'prepare' ]:
138 env.Execute([ "$SCONS prepare" ])
143 SConscript("debian/SConscript")
145 if os.path.exists('SConscript.local') : SConscript('SConscript.local')
146 if env['sparse_tests']:
147 import SparseTestHack
148 SparseTestHack.setup(env)
149 if env.subst('$BUILDDIR') == '#':
150 SConscript("SConscript")
152 SConscript("SConscript", variant_dir=env.subst('$BUILDDIR'), src_dir='#', duplicate=False)
153 SConscript("Examples/SConscript")
154 SConscript("HowTos/SConscript")
155 SConscript("doclib/SConscript")
156 if env['sparse_tests']:
157 verbose = 'test_changes' in COMMAND_LINE_TARGETS
158 SparseTestHack.build(env, verbose, verbose)
160 ###########################################################################
161 # Define build targets
163 #### install_all, default, all_tests, all
164 env.Install('${SCONSINSTALLDIR}', [ 'site_scons/__init__.py',
165 'site_scons/senfutil.py',
166 'site_scons/yaptu.py' ])
167 env.InstallDir('${SCONSINSTALLDIR}', [ 'site_scons/site_tools', 'site_scons/lib' ],
168 FILTER_SUFFIXES=[ '','.css','.pl','.py','.sh','.sty','.xml','.xsl','.yap' ])
169 env.Install('${INCLUDEINSTALLDIR}', 'boost')
171 env.Alias('install_all', env.FindInstalledFiles())
172 env.Alias('default', DEFAULT_TARGETS)
173 env.Alias('all_tests', env.FindAllBoostUnitTests())
174 env.Alias('test_changes', 'all_tests')
175 env.Alias('all', [ 'default', 'all_tests', 'examples', 'all_docs' ])
178 env.PhonyTarget('prepare', [], [])
181 for test in env.FindAllBoostUnitTests():
182 stamp = env.Command(test[0].dir.File('.test-valgrind.stamp'),
183 [ test[0].dir.File('.test.bin'), 'tools/valgrind.sup' ],
184 [ """valgrind --tool=memcheck
186 --suppressions=${SOURCES[1]}
188 ${SOURCES[0]} $BOOSTTESTARGS;
189 [ $$? -ne 99 ] || exit 1""".replace("\n"," "),
191 alias = env.Command(test[0].dir.File('valgrind'), stamp, [ env.NopAction() ])
192 env.Alias('all_valgrinds', alias)
195 env.PhonyTarget('lcov', [], [
196 '$SCONS debug=1 BUILDDIR="#/build/lcov" CCFLAGS+="-fprofile-arcs -ftest-coverage" LIBS+="gcov" all_tests',
197 '$LCOV --follow --directory $TOPDIR/build/lcov/senf --capture --output-file /tmp/senf_lcov.info --base-directory $TOPDIR',
198 '$LCOV --output-file lcov.info --remove /tmp/senf_lcov.info "*/include/*" "*/boost/*" "*.test.*" ',
199 '$GENHTML --output-directory doc/lcov --title all_tests lcov.info',
200 'rm /tmp/senf_lcov.info' ])
201 if env.GetOption('clean'):
202 env.Clean('lcov', [ os.path.join(path,f)
203 for path, subdirs, files in os.walk('.')
204 for pattern in ('*.gcno', '*.gcda', '*.gcov')
205 for f in fnmatch.filter(files,pattern) ] +
206 [ 'lcov.info', env.Dir('doc/lcov'), env.Dir('build/lcov') ])
209 env.Clean('all', ('.prepare-stamp', env.Dir('dist'), env.Dir('build')))
210 if env.GetOption('clean') : env.Depends('all', ('lcov', 'all_valgrinds'))
212 if env.GetOption('clean') and 'all' in BUILD_TARGETS:
213 env.Clean('all', [ os.path.join(path,f)
214 for path, subdirs, files in os.walk('.')
215 for pattern in env['CLEAN_PATTERNS']
216 for f in fnmatch.filter(files,pattern) ])
217 # Disable writing to the deleted .sconsign file
218 import SCons.SConsign
219 SCons.SConsign.write = lambda : None
221 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp"):
222 Execute(Touch(".prepare-stamp"))
224 ### execute targets on remote hosts
225 for target in COMMAND_LINE_TARGETS:
227 realtarget, host = target.split('@',1)
228 cwd=env.GetLaunchDir()
229 home=os.environ['HOME']+'/'
230 if cwd.startswith(home) : cwd = cwd[len(home):]
231 args = [ '$SCONSARGS' ]
232 if env.GetLaunchDir() != os.getcwd():
234 env.PhonyTarget(target, [], [ "ssh $HOST scons $SCONSARGS -C $DIR $RTARGET" ],
235 HOST=host, RTARGET=realtarget, DIR=cwd, SCONSARGS=args)