fixes for Ubuntu Oneiric (g++ 4.6.1, boost 1.46.1)
[senf.git] / SConstruct
1 # -*- python -*-
2
3 import sys, os.path
4 import SENFSCons, senfutil
5
6 ###########################################################################
7 # Load utilities and setup libraries and configure build
8
9 env = Environment()
10
11 env.Decider('MD5-timestamp')
12 env.EnsureSConsVersion(1,2)
13
14 # Load all the local SCons tools
15 senfutil.loadTools(env)
16
17 env.Help("""
18 Additional top-level build targets:
19
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
26 all             Build everything
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
35
36 The following additional targets may be called within subdirectories, either
37 using '$ scons -u <target>'  or '$ scons <directory>/<target>:
38
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
42
43 When cleaning up using '$ scons -c <target>', some targets are handled specially:
44
45 all             Remove everything generated by the build including temporary and
46                 backup files
47
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.
50
51 You may execute targets on a remote host via ssh (if the directory layout is the
52 same) by calling
53
54     $ scons <target>@[<user>@]<host>
55
56 Some more elaborate unit tests may be enabled by setting appropritate variables
57 in the shell (unix) environment
58
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
62                 idle system.
63
64 SENF_WLAN_TEST_INTERFACE
65                 WLAN interface to use for testing. The interface should not be
66                 actively in use.
67
68 SENF_ETH_TEST_INTERFACE
69                 Ethernet interface to use for testing. The interface should not
70                 be actively in use.
71
72 Some unit tests will only run when executed to 'root'.
73 """)
74
75 env.Replace(
76     expandLogOption        = senfutil.expandLogOption,
77     CXXFLAGS_              = env.BuildTypeOptions('CXXFLAGS'),
78     CPPDEFINES_            = env.BuildTypeOptions('CPPDEFINES'),
79     LINKFLAGS_             = env.BuildTypeOptions('LINKFLAGS'),
80 )
81 env.Append(
82     IMPORT_ENV             = [ 'PATH', 'HOME', 'SSH_*', 'SENF*', 'CCACHE_*', 'DISTCC_*' ],
83
84     CLEAN_SOME_PATTERNS    = [ '*~', '#*#', '*.pyc', 'semantic.cache' ],
85     CLEAN_PATTERNS         = [ '.sconsign*', '.sconf_temp' ],
86
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' ],
94
95     CPP_INCLUDE_EXTENSIONS = [ '.h', '.hh', '.ih', '.mpp', '.cci', '.ct', '.cti' ],
96     CPP_EXCLUDE_EXTENSIONS = [ '.test.hh' ],
97
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_NORMAL     = [ '-finline-limit=5000', '--param', 'inline-unit-growth=60' ],
105     INLINE_OPTS            = [ '$INLINE_OPTS_NORMAL' ],
106     CXXFLAGS               = [ '-Wall', '-Woverloaded-virtual', '-Wno-long-long', '$INLINE_OPTS',
107                                '-pipe', '$CXXFLAGS_', '-fno-strict-aliasing', 
108                                "${profile and '-pg' or None}" ],
109     CXXFLAGS_final         = [ '-O3' ],
110     CXXFLAGS_normal        = [ '-O2', '-g' ],
111     CXXFLAGS_debug         = [ '-O0', '-g' ],
112
113     CPPDEFINES             = [ '$expandLogOption', '$CPPDEFINES_' ],
114     CPPDEFINES_final       = [ 'SENF_PPI_NOTRACE', 'BOOST_NO_MT', 'NDEBUG', 'BOOST_DISABLE_ASSERTS' ],
115     CPPDEFINES_normal      = [ 'SENF_DEBUG' ],
116     CPPDEFINES_debug       = [ '$CPPDEFINES_normal' ],
117
118     LINKFLAGS              = [ '-rdynamic', '$LINKFLAGS_', "${profile and '-pg' or None}" ],
119     LINKFLAGS_final        = [ ],
120     LINKFLAGS_normal       = [ '-Wl,-S' ],
121     LINKFLAGS_debug        = [ '-g' ],
122 )
123 env.SetDefault(
124     PREFIX                 = '#/dist',
125     LIBINSTALLDIR          = '$PREFIX${syslayout and "/lib" or ""}',
126     BININSTALLDIR          = '$PREFIX${syslayout and "/bin" or ""}',
127     INCLUDEINSTALLDIR      = '$PREFIX${syslayout and "/include" or ""}',
128     CONFINSTALLDIR         = '${syslayout and "$LIBINSTALLDIR/senf" or "$PREFIX"}',
129     OBJINSTALLDIR          = '$CONFINSTALLDIR',
130     DOCINSTALLDIR          = '$PREFIX${syslayout and "/share/doc/senf" or "/manual"}',
131     SCONSINSTALLDIR        = '$CONFINSTALLDIR/site_scons',
132
133     BUILDDIR               = '${FLAVOR and "#/build/$FLAVOR" or "#"}',
134     LOCALLIBDIR            = '$BUILDDIR',
135
136     LIBSENF                = "senf",
137     LCOV                   = "lcov",
138     GENHTML                = "genhtml",
139     VALGRIND               = "valgrind",
140     SCONSBIN               = env.File("#/tools/scons"),
141     SCONSARGS              = ([ '-Q', '-j$CONCURRENCY_LEVEL' ] +
142                               [ '%s=%s' % (k,v) for k,v in ARGLIST ]),
143     SCONS                  = "@$SCONSBIN $SCONSARGS",
144     CONCURRENCY_LEVEL      = env.GetOption('num_jobs') or 1,
145     TOPDIR                 = env.Dir('#').abspath,
146     LIBADDSUFFIX           = '${FLAVOR and "_$FLAVOR" or ""}',
147     OBJADDSUFFIX           = '${LIBADDSUFFIX}',
148     FLAVOR                 = '',
149
150     PARSEFLAGS             = '',
151 )
152
153 # Set variables from command line
154 senfutil.parseArguments(
155     env,
156     BoolVariable('final', 'Build final (optimized) build', False),
157     BoolVariable('debug', 'Link in debug symbols', False),
158     BoolVariable('profile', 'compile and link with the profiling enabled option', False),
159     BoolVariable('syslayout', 'Install in to system layout directories (lib/, include/ etc)', False),
160     BoolVariable('sparse_tests', 'Link tests against object files and not the senf lib', False)
161 )
162
163 # Add UNIX env vars matching IMPORT_ENV patterns into the execution environment
164 senfutil.importProcessEnv(env)
165
166 # Handle 'test_changes'
167 if 'test_changes' in COMMAND_LINE_TARGETS and not env.has_key('only_tests'):
168     import SparseTestHack
169     env['only_tests'] = " ".join(x.abspath for x in SparseTestHack.findSCMChanges(env))
170
171 if env.has_key('only_tests') : env['sparse_tests'] = True
172
173 Export('env')
174
175 ###########################################################################
176 # Configure
177
178 SConscript('SConfigure')
179
180 # Only add this here, after all configure checks have run
181
182 env.Append(LIBS = [ '$LIBSENF$LIBADDSUFFIX',
183                     '$BOOSTREGEXLIB', '$BOOSTSIGNALSLIB',
184                     '$BOOSTFSLIB', '$BOOSTSYSTEMLIB' ])
185
186 ###########################################################################
187
188 # Create Doxyfile.local otherwise doxygen will barf on this non-existent file
189 # Create it even when cleaning, to silence the doxygen builder warnings
190 if not os.path.exists("doclib/Doxyfile.local"):
191     Execute(Touch("doclib/Doxyfile.local"))
192
193 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp") \
194    and not os.environ.get("SCONS") and COMMAND_LINE_TARGETS != [ 'prepare' ]:
195     env.Execute([ "$SCONS prepare" ])
196
197 # Load SConscripts
198
199 SConscriptChdir(0)
200 SConscript("debian/SConscript")
201 SConscriptChdir(1)
202 if os.path.exists('SConscript.local') : SConscript('SConscript.local')
203 if env['sparse_tests']:
204     import SparseTestHack
205     SparseTestHack.setup(env)
206 if env.subst('$BUILDDIR') == '#':
207     SConscript("SConscript")
208 else:
209     SConscript("SConscript", variant_dir=env.subst('$BUILDDIR'), src_dir='#', duplicate=False)
210 SConscript("Examples/SConscript")
211 SConscript("HowTos/SConscript")
212 SConscript("doclib/SConscript")
213 if env['sparse_tests']:
214     verbose = 'test_changes' in COMMAND_LINE_TARGETS
215     SparseTestHack.build(env, verbose, verbose)
216
217 ###########################################################################
218 # Define build targets
219
220 #### install_all, default, all_tests, all
221 env.Install('${SCONSINSTALLDIR}', [ 'site_scons/__init__.py',
222                                     'site_scons/senfutil.py',
223                                     'site_scons/yaptu.py' ])
224 env.InstallDir('${SCONSINSTALLDIR}', [ 'site_scons/site_tools', 'site_scons/lib' ],
225                FILTER_SUFFIXES=[ '','.css','.pl','.py','.sh','.sty','.xml','.xsl','.yap' ])
226 env.Install('${INCLUDEINSTALLDIR}', 'boost_ext')
227 env.Install('${INCLUDEINSTALLDIR}/senf', 'senf/boost_intrusive')
228
229 env.Alias('install_all', env.FindInstalledFiles())
230 env.Alias('default', DEFAULT_TARGETS)
231 env.Alias('all_tests', env.FindAllBoostUnitTests())
232 env.Alias('test_changes', 'all_tests')
233 env.Alias('all', [ 'default', 'all_tests', 'examples', 'all_docs' ])
234
235 #### prepare and -c some
236 env.PhonyTarget('prepare', [], [])
237 env.PhonyTarget('some', [], [])
238
239 #### valgrind
240 env.Alias('all_valgrinds')
241 if env.get('HAVE_VALGRIND'):
242     for test in env.FindAllBoostUnitTests():
243         stamp = env.Command(test[0].dir.File('.test-valgrind.stamp'),
244                             [ test[0].dir.File('.test.bin'), 'tools/valgrind.sup' ],
245                             [ """$VALGRIND --tool=memcheck
246                                           --error-exitcode=1
247                                           --suppressions=${SOURCES[1]}
248                                           $VALGRINDARGS
249                                               ${SOURCES[0]} --result_code=no $BOOSTTESTARGS
250                               """.replace("\n"," "),
251                               Touch("$TARGET") ])
252         alias = env.Command(test[0].dir.File('valgrind'), stamp, [ env.NopAction() ])
253         env.Alias('all_valgrinds', alias)
254
255 ### lcov
256 env.PhonyTarget('lcov', [], [
257         '$SCONS'
258         '    debug=1'
259         '    BUILDDIR="#/build/lcov"'
260         '    CCFLAGS+="-fprofile-arcs -ftest-coverage"'
261         '    LIBS+="gcov"'
262         '        all_tests',
263         '$LCOV'
264         '    --follow'
265         '    --directory $TOPDIR/build/lcov/senf'
266         '    --capture'
267         '    --output-file /tmp/senf_lcov.info'
268         '    --base-directory $TOPDIR',
269         '$LCOV'
270         '    --output-file lcov.info'
271         '    --remove /tmp/senf_lcov.info "*/include/*" "*/boost/*" "*.test.*"',
272         '$GENHTML'
273         '    --output-directory doc/lcov'
274         '    --title all_tests lcov.info',
275         'rm /tmp/senf_lcov.info' ])
276 senfutil.CleanGlob(env, ['lcov','some','all'], [ '*.gcno', '*.gcda', '*.gcov' ])
277 env.Clean(['lcov', 'all'], [ 'lcov.info', env.Dir('doc/lcov'), env.Dir('build/lcov') ])
278
279 #### clean
280
281 env.Clean('all', ('.prepare-stamp', env.Dir('dist'), env.Dir('build')))
282
283 senfutil.CleanGlob(env, 'all', '$CLEAN_PATTERNS')
284 senfutil.CleanGlob(env, ['some', 'all'], '$CLEAN_SOME_PATTERNS')
285
286 if env.GetOption('clean') and 'all' in BUILD_TARGETS:
287     env.Depends('all', ('lcov', 'all_valgrinds'))
288     # Disable writing to the deleted .sconsign file
289     import SCons.SConsign
290     SCons.SConsign.write = lambda : None
291
292 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp"):
293     Execute(Touch(".prepare-stamp"))
294
295 ### execute targets on remote hosts
296 for target in COMMAND_LINE_TARGETS:
297     if '@' in target:
298         realtarget, host = target.split('@',1)
299         cwd=env.GetLaunchDir()
300         home=os.environ['HOME']+'/'
301         if cwd.startswith(home) : cwd = cwd[len(home):]
302         args = [ '$SCONSARGS' ]
303         if env.GetLaunchDir() != os.getcwd():
304             args.append('-u')
305         env.PhonyTarget(target, [], [ "ssh $HOST scons $SCONSARGS -C $DIR $RTARGET" ],
306                         HOST=host, RTARGET=realtarget, DIR=cwd, SCONSARGS=args)
307
308 env.PhonyTarget('clean', [], [
309         lambda **args: sys.stderr.write(
310             "=================================================================\n"
311             "'clean' is not a valid target, use the '-c' option instead:\n"
312             "    $ scons -c all\n"
313             "=================================================================\n") ])