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 all_docs Build documentation for all modules
26 install_all Install SENF into $$PREFIX
27 deb Build debian source and binary package
28 debsrc Build debian source package
29 debbin Build debian binary package
30 linklint Check links of doxygen documentation with 'linklint'
31 fixlinks Fix broken links in doxygen documentation
32 all_valgrinds Run all tests under valgrind/memcheck
33 lcov Generate test coverage output in doc/lcov and lcov.info
35 You may execute targets on a remote host (if the directory layout is the same)
38 scons <target>@[<user>@]<host>
42 ENV = { 'PATH' : os.environ.get('PATH'),
43 'HOME' : os.environ.get('HOME'),
44 'SSH_AGENT_PID': os.environ.get('SSH_AGENT_PID'),
45 'SSH_AUTH_SOCK': os.environ.get('SSH_AUTH_SOCK') },
46 CLEAN_PATTERNS = [ '*~', '#*#', '*.pyc', 'semantic.cache', '.sconsign*' ],
48 BUILDDIR = '${FLAVOR and "#/build/$FLAVOR" or "#"}',
49 CPPPATH = [ '$BUILDDIR', '#' ],
50 LOCALLIBDIR = '$BUILDDIR',
51 LIBPATH = [ '$LOCALLIBDIR' ],
52 LIBS = [ '$LIBSENF$LIBADDSUFFIX', '$EXTRA_LIBS' ],
53 EXTRA_LIBS = [ 'rt', '$BOOSTREGEXLIB', '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB',
55 TEST_EXTRA_LIBS = [ ],
56 VALGRINDARGS = [ '--num-callers=50' ],
59 LIBINSTALLDIR = '$PREFIX${syslayout and "/lib" or ""}',
60 BININSTALLDIR = '$PREFIX${syslayout and "/bin" or ""}',
61 INCLUDEINSTALLDIR = '$PREFIX${syslayout and "/include" or ""}',
62 CONFINSTALLDIR = '${syslayout and "$LIBINSTALLDIR/senf" or "$PREFIX"}',
63 OBJINSTALLDIR = '$CONFINSTALLDIR',
64 DOCINSTALLDIR = '$PREFIX${syslayout and "/share/doc/senf" or "/manual"}',
65 SCONSINSTALLDIR = '$CONFINSTALLDIR/site_scons',
67 CPP_INCLUDE_EXTENSIONS = [ '.h', '.hh', '.ih', '.mpp', '.cci', '.ct', '.cti' ],
68 CPP_EXCLUDE_EXTENSIONS = [ '.test.hh' ],
70 # These options are insane. Only useful for inline debugging. Need at least 1G free RAM
71 INLINE_OPTS_DEBUG = [ '-finline-limit=20000', '-fvisibility-inlines-hidden',
72 '-fno-inline-functions', '-Winline'
73 '--param','large-function-growth=10000',
74 '--param', 'large-function-insns=10000',
75 '--param','inline-unit-growth=10000' ],
76 INLINE_OPTS_NORMAL = [ '-finline-limit=5000' ],
77 INLINE_OPTS = [ '$INLINE_OPTS_NORMAL' ],
78 CXXFLAGS = [ '-Wall', '-Woverloaded-virtual', '-Wno-long-long', '$INLINE_OPTS',
80 CXXFLAGS_ = senfutil.BuildTypeOptions('CXXFLAGS'),
81 CXXFLAGS_final = [ '-O3' ],
82 CXXFLAGS_normal = [ '-O0', '-g' ],
83 CXXFLAGS_debug = [ '$CXXFLAGS_normal' ],
85 CPPDEFINES = [ '$expandLogOption', '$CPPDEFINES_' ],
86 expandLogOption = senfutil.expandLogOption,
87 CPPDEFINES_ = senfutil.BuildTypeOptions('CPPDEFINES'),
88 CPPDEFINES_final = [ ],
89 CPPDEFINES_normal = [ 'SENF_DEBUG' ],
90 CPPDEFINES_debug = [ '$CPPDEFINES_normal' ],
92 LINKFLAGS = [ '-rdynamic', '$LINKFLAGS_' ],
93 LINKFLAGS_ = senfutil.BuildTypeOptions('LINKFLAGS'),
94 LINKFLAGS_final = [ ],
95 LINKFLAGS_normal = [ '-Wl,-S' ],
96 LINKFLAGS_debug = [ '-g' ],
103 SCONSBIN = env.File("#/tools/scons"),
104 SCONSARGS = [ '-Q', '-j$CONCURRENCY_LEVEL', 'debug=$debug', 'final=$final' ],
105 SCONS = "@$SCONSBIN $SCONSARGS",
106 CONCURRENCY_LEVEL = env.GetOption('num_jobs') or 1,
107 TOPDIR = env.Dir('#').abspath,
108 LIBADDSUFFIX = '${FLAVOR and "_$FLAVOR" or ""}',
109 OBJADDSUFFIX = '${LIBADDSUFFIX}',
113 # Set variables from command line
114 senfutil.parseArguments(
116 BoolVariable('final', 'Build final (optimized) build', False),
117 BoolVariable('debug', 'Link in debug symbols', False),
118 BoolVariable('syslayout', 'Install in to system layout directories (lib/, include/ etc)', False),
119 BoolVariable('sparse_tests', 'Link tests against object files and not the senf lib', False)
122 if 'test_changes' in COMMAND_LINE_TARGETS and not env.has_key('only_tests'):
123 if os.popen("svnversion").read().strip() == "exported":
124 env['only_tests'] = " ".join(os.popen("git ls-files --modified").read().strip().split("\n"))
126 env['only_tests'] = " ".join(l[7:]
127 for l in os.popen("svn status").read().rstrip().split("\n")
130 if env.has_key('only_tests') : env['sparse_tests'] = True
133 # Create Doxyfile.local otherwise doxygen will barf on this non-existent file
134 # Create it even when cleaning, to silence the doxygen builder warnings
135 if not os.path.exists("doclib/Doxyfile.local"):
136 Execute(Touch("doclib/Doxyfile.local"))
138 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp") \
139 and not os.environ.get("SCONS") and COMMAND_LINE_TARGETS != [ 'prepare' ]:
140 env.Execute([ "$SCONS prepare" ])
145 SConscript("debian/SConscript")
147 if os.path.exists('SConscript.local') : SConscript('SConscript.local')
148 if env['sparse_tests']:
149 import SparseTestHack
150 SparseTestHack.setup(env)
151 if env.subst('$BUILDDIR') == '#':
152 SConscript("SConscript")
154 SConscript("SConscript", variant_dir=env.subst('$BUILDDIR'), src_dir='#', duplicate=False)
155 SConscript("Examples/SConscript")
156 SConscript("HowTos/SConscript")
157 SConscript("doclib/SConscript")
158 if env['sparse_tests']:
159 SparseTestHack.build(env, 'test_changes' in COMMAND_LINE_TARGETS)
161 ###########################################################################
162 # Define build targets
164 #### install_all, default, all_tests, all
165 env.Install('${SCONSINSTALLDIR}', [ 'site_scons/__init__.py',
166 'site_scons/senfutil.py',
167 'site_scons/yaptu.py' ])
168 env.InstallDir('${SCONSINSTALLDIR}', [ 'site_scons/site_tools', 'site_scons/lib' ],
169 FILTER_SUFFIXES=[ '','.css','.pl','.py','.sh','.sty','.xml','.xsl','.yap' ])
170 env.Install('${INCLUDEINSTALLDIR}', 'boost')
172 env.Alias('install_all', env.FindInstalledFiles())
173 env.Alias('default', DEFAULT_TARGETS)
174 env.Alias('all_tests', env.FindAllBoostUnitTests())
175 env.Alias('test_changes', 'all_tests')
176 env.Alias('all', [ 'default', 'all_tests', 'examples', 'all_docs' ])
179 env.PhonyTarget('prepare', [], [])
182 for test in env.FindAllBoostUnitTests():
183 stamp = env.Command(test[0].dir.File('.test-valgrind.stamp'),
184 [ test[0].dir.File('.test.bin'), 'tools/valgrind.sup' ],
185 [ """valgrind --tool=memcheck
187 --suppressions=${SOURCES[1]}
189 ${SOURCES[0]} $BOOSTTESTARGS;
190 [ $$? -ne 99 ] || exit 1""".replace("\n"," "),
192 alias = env.Command(test[0].dir.File('valgrind'), stamp, [ env.NopAction() ])
193 env.Alias('all_valgrinds', alias)
196 env.PhonyTarget('lcov', [], [
197 '$SCONS debug=1 BUILDDIR="#/build/lcov" CCFLAGS+="-fprofile-arcs -ftest-coverage" LIBS+="gcov" all_tests',
198 '$LCOV --follow --directory $TOPDIR/build/lcov/senf --capture --output-file /tmp/senf_lcov.info --base-directory $TOPDIR',
199 '$LCOV --output-file lcov.info --remove /tmp/senf_lcov.info "*/include/*" "*/boost/*" "*.test.*" ',
200 '$GENHTML --output-directory doc/lcov --title all_tests lcov.info',
201 'rm /tmp/senf_lcov.info' ])
202 if env.GetOption('clean'):
203 env.Clean('lcov', [ os.path.join(path,f)
204 for path, subdirs, files in os.walk('.')
205 for pattern in ('*.gcno', '*.gcda', '*.gcov')
206 for f in fnmatch.filter(files,pattern) ] +
207 [ 'lcov.info', env.Dir('doc/lcov'), env.Dir('build/lcov') ])
210 env.Clean('all', ('.prepare-stamp', env.Dir('dist'), env.Dir('build')))
211 if env.GetOption('clean') : env.Depends('all', ('lcov', 'all_valgrinds'))
213 if env.GetOption('clean') and 'all' in BUILD_TARGETS:
214 env.Clean('all', [ os.path.join(path,f)
215 for path, subdirs, files in os.walk('.')
216 for pattern in env['CLEAN_PATTERNS']
217 for f in fnmatch.filter(files,pattern) ])
218 # Disable writing to the deleted .sconsign file
219 import SCons.SConsign
220 SCons.SConsign.write = lambda : None
222 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp"):
223 Execute(Touch(".prepare-stamp"))
225 ### execute targets on remote hosts
226 for target in COMMAND_LINE_TARGETS:
228 realtarget, host = target.split('@',1)
229 cwd=env.GetLaunchDir()
230 home=os.environ['HOME']+'/'
231 if cwd.startswith(home) : cwd = cwd[len(home):]
232 args = [ '$SCONSARGS' ]
233 if env.GetLaunchDir() != os.getcwd():
235 env.PhonyTarget(target, [], [ "ssh $HOST scons $SCONSARGS -C $DIR $RTARGET" ],
236 HOST=host, RTARGET=realtarget, DIR=cwd, SCONSARGS=args)