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 SCONS = "@$SCONSBIN $SCONSARGS",
107 CONCURRENCY_LEVEL = env.GetOption('num_jobs') or 1,
108 TOPDIR = env.Dir('#').abspath,
109 LIBADDSUFFIX = '${FLAVOR and "_$FLAVOR" or ""}',
110 OBJADDSUFFIX = '${LIBADDSUFFIX}',
114 # Set variables from command line
115 senfutil.parseArguments(
117 BoolVariable('final', 'Build final (optimized) build', False),
118 BoolVariable('debug', 'Link in debug symbols', False),
119 BoolVariable('syslayout', 'Install in to system layout directories (lib/, include/ etc)', False),
120 BoolVariable('sparse_tests', 'Link tests against object files and not the senf lib', False)
123 if 'test_changes' in COMMAND_LINE_TARGETS and not env.has_key('only_tests'):
124 import SparseTestHack
125 env['only_tests'] = " ".join(x.abspath for x in SparseTestHack.findSCMChanges(env))
127 if env.has_key('only_tests') : env['sparse_tests'] = True
130 # Create Doxyfile.local otherwise doxygen will barf on this non-existent file
131 # Create it even when cleaning, to silence the doxygen builder warnings
132 if not os.path.exists("doclib/Doxyfile.local"):
133 Execute(Touch("doclib/Doxyfile.local"))
135 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp") \
136 and not os.environ.get("SCONS") and COMMAND_LINE_TARGETS != [ 'prepare' ]:
137 env.Execute([ "$SCONS prepare" ])
142 SConscript("debian/SConscript")
144 if os.path.exists('SConscript.local') : SConscript('SConscript.local')
145 if env['sparse_tests']:
146 import SparseTestHack
147 SparseTestHack.setup(env)
148 if env.subst('$BUILDDIR') == '#':
149 SConscript("SConscript")
151 SConscript("SConscript", variant_dir=env.subst('$BUILDDIR'), src_dir='#', duplicate=False)
152 SConscript("Examples/SConscript")
153 SConscript("HowTos/SConscript")
154 SConscript("doclib/SConscript")
155 if env['sparse_tests']:
156 verbose = 'test_changes' in COMMAND_LINE_TARGETS
157 SparseTestHack.build(env, verbose, verbose)
159 ###########################################################################
160 # Define build targets
162 #### install_all, default, all_tests, all
163 env.Install('${SCONSINSTALLDIR}', [ 'site_scons/__init__.py',
164 'site_scons/senfutil.py',
165 'site_scons/yaptu.py' ])
166 env.InstallDir('${SCONSINSTALLDIR}', [ 'site_scons/site_tools', 'site_scons/lib' ],
167 FILTER_SUFFIXES=[ '','.css','.pl','.py','.sh','.sty','.xml','.xsl','.yap' ])
168 env.Install('${INCLUDEINSTALLDIR}', 'boost')
170 env.Alias('install_all', env.FindInstalledFiles())
171 env.Alias('default', DEFAULT_TARGETS)
172 env.Alias('all_tests', env.FindAllBoostUnitTests())
173 env.Alias('test_changes', 'all_tests')
174 env.Alias('all', [ 'default', 'all_tests', 'examples', 'all_docs' ])
177 env.PhonyTarget('prepare', [], [])
180 for test in env.FindAllBoostUnitTests():
181 stamp = env.Command(test[0].dir.File('.test-valgrind.stamp'),
182 [ test[0].dir.File('.test.bin'), 'tools/valgrind.sup' ],
183 [ """valgrind --tool=memcheck
185 --suppressions=${SOURCES[1]}
187 ${SOURCES[0]} $BOOSTTESTARGS;
188 [ $$? -ne 99 ] || exit 1""".replace("\n"," "),
190 alias = env.Command(test[0].dir.File('valgrind'), stamp, [ env.NopAction() ])
191 env.Alias('all_valgrinds', alias)
194 env.PhonyTarget('lcov', [], [
195 '$SCONS debug=1 BUILDDIR="#/build/lcov" CCFLAGS+="-fprofile-arcs -ftest-coverage" LIBS+="gcov" all_tests',
196 '$LCOV --follow --directory $TOPDIR/build/lcov/senf --capture --output-file /tmp/senf_lcov.info --base-directory $TOPDIR',
197 '$LCOV --output-file lcov.info --remove /tmp/senf_lcov.info "*/include/*" "*/boost/*" "*.test.*" ',
198 '$GENHTML --output-directory doc/lcov --title all_tests lcov.info',
199 'rm /tmp/senf_lcov.info' ])
200 if env.GetOption('clean'):
201 env.Clean('lcov', [ os.path.join(path,f)
202 for path, subdirs, files in os.walk('.')
203 for pattern in ('*.gcno', '*.gcda', '*.gcov')
204 for f in fnmatch.filter(files,pattern) ] +
205 [ 'lcov.info', env.Dir('doc/lcov'), env.Dir('build/lcov') ])
208 env.Clean('all', ('.prepare-stamp', env.Dir('dist'), env.Dir('build')))
209 if env.GetOption('clean') : env.Depends('all', ('lcov', 'all_valgrinds'))
211 if env.GetOption('clean') and 'all' in BUILD_TARGETS:
212 env.Clean('all', [ os.path.join(path,f)
213 for path, subdirs, files in os.walk('.')
214 for pattern in env['CLEAN_PATTERNS']
215 for f in fnmatch.filter(files,pattern) ])
216 # Disable writing to the deleted .sconsign file
217 import SCons.SConsign
218 SCons.SConsign.write = lambda : None
220 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp"):
221 Execute(Touch(".prepare-stamp"))
223 ### execute targets on remote hosts
224 for target in COMMAND_LINE_TARGETS:
226 realtarget, host = target.split('@',1)
227 cwd=env.GetLaunchDir()
228 home=os.environ['HOME']+'/'
229 if cwd.startswith(home) : cwd = cwd[len(home):]
230 args = [ '$SCONSARGS' ]
231 if env.GetLaunchDir() != os.getcwd():
233 env.PhonyTarget(target, [], [ "ssh $HOST scons $SCONSARGS -C $DIR $RTARGET" ],
234 HOST=host, RTARGET=realtarget, DIR=cwd, SCONSARGS=args)