Packets/80221Bundle: swap out MIHMessageRegistry in own header file; documentation...
[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
151 # Set variables from command line
152 senfutil.parseArguments(
153     env,
154     BoolVariable('final', 'Build final (optimized) build', False),
155     BoolVariable('debug', 'Link in debug symbols', False),
156     BoolVariable('profile', 'compile and link with the profiling enabled option', False),
157     BoolVariable('syslayout', 'Install in to system layout directories (lib/, include/ etc)', False),
158     BoolVariable('sparse_tests', 'Link tests against object files and not the senf lib', False)
159 )
160
161 # Add UNIX env vars matching IMPORT_ENV patterns into the execution environment
162 senfutil.importProcessEnv(env)
163
164 # Handle 'test_changes'
165 if 'test_changes' in COMMAND_LINE_TARGETS and not env.has_key('only_tests'):
166     import SparseTestHack
167     env['only_tests'] = " ".join(x.abspath for x in SparseTestHack.findSCMChanges(env))
168
169 if env.has_key('only_tests') : env['sparse_tests'] = True
170
171 Export('env')
172
173 ###########################################################################
174 # Configure
175
176 SConscript('SConfigure')
177
178 # Only add this here, after all configure checks have run
179
180 env.Append(LIBS = '$LIBSENF$LIBADDSUFFIX',
181            EXTRA_LIBS = [ '$BOOSTREGEXLIB', '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB',
182                           '$BOOSTFSLIB' ])
183
184 ###########################################################################
185
186 # Create Doxyfile.local otherwise doxygen will barf on this non-existent file
187 # Create it even when cleaning, to silence the doxygen builder warnings
188 if not os.path.exists("doclib/Doxyfile.local"):
189     Execute(Touch("doclib/Doxyfile.local"))
190
191 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp") \
192    and not os.environ.get("SCONS") and COMMAND_LINE_TARGETS != [ 'prepare' ]:
193     env.Execute([ "$SCONS prepare" ])
194
195 # Load SConscripts
196
197 SConscriptChdir(0)
198 SConscript("debian/SConscript")
199 SConscriptChdir(1)
200 if os.path.exists('SConscript.local') : SConscript('SConscript.local')
201 if env['sparse_tests']:
202     import SparseTestHack
203     SparseTestHack.setup(env)
204 if env.subst('$BUILDDIR') == '#':
205     SConscript("SConscript")
206 else:
207     SConscript("SConscript", variant_dir=env.subst('$BUILDDIR'), src_dir='#', duplicate=False)
208 SConscript("Examples/SConscript")
209 SConscript("HowTos/SConscript")
210 SConscript("doclib/SConscript")
211 if env['sparse_tests']:
212     verbose = 'test_changes' in COMMAND_LINE_TARGETS
213     SparseTestHack.build(env, verbose, verbose)
214
215 ###########################################################################
216 # Define build targets
217
218 #### install_all, default, all_tests, all
219 env.Install('${SCONSINSTALLDIR}', [ 'site_scons/__init__.py',
220                                     'site_scons/senfutil.py',
221                                     'site_scons/yaptu.py' ])
222 env.InstallDir('${SCONSINSTALLDIR}', [ 'site_scons/site_tools', 'site_scons/lib' ],
223                FILTER_SUFFIXES=[ '','.css','.pl','.py','.sh','.sty','.xml','.xsl','.yap' ])
224 env.Install('${INCLUDEINSTALLDIR}', 'boost_ext')
225 env.Install('${INCLUDEINSTALLDIR}/senf', 'senf/boost_intrusive')
226
227 env.Alias('install_all', env.FindInstalledFiles())
228 env.Alias('default', DEFAULT_TARGETS)
229 env.Alias('all_tests', env.FindAllBoostUnitTests())
230 env.Alias('test_changes', 'all_tests')
231 env.Alias('all', [ 'default', 'all_tests', 'examples', 'all_docs' ])
232
233 #### prepare and -c some
234 env.PhonyTarget('prepare', [], [])
235 env.PhonyTarget('some', [], [])
236
237 #### valgrind
238 env.Alias('all_valgrinds')
239 if env.get('HAVE_VALGRIND'):
240     for test in env.FindAllBoostUnitTests():
241         stamp = env.Command(test[0].dir.File('.test-valgrind.stamp'),
242                             [ test[0].dir.File('.test.bin'), 'tools/valgrind.sup' ],
243                             [ """$VALGRIND --tool=memcheck
244                                           --error-exitcode=1
245                                           --suppressions=${SOURCES[1]}
246                                           $VALGRINDARGS
247                                               ${SOURCES[0]} --result_code=no $BOOSTTESTARGS
248                               """.replace("\n"," "),
249                               Touch("$TARGET") ])
250         alias = env.Command(test[0].dir.File('valgrind'), stamp, [ env.NopAction() ])
251         env.Alias('all_valgrinds', alias)
252
253 ### lcov
254 env.PhonyTarget('lcov', [], [
255         '$SCONS'
256         '    debug=1'
257         '    BUILDDIR="#/build/lcov"'
258         '    CCFLAGS+="-fprofile-arcs -ftest-coverage"'
259         '    LIBS+="gcov"'
260         '        all_tests',
261         '$LCOV'
262         '    --follow'
263         '    --directory $TOPDIR/build/lcov/senf'
264         '    --capture'
265         '    --output-file /tmp/senf_lcov.info'
266         '    --base-directory $TOPDIR',
267         '$LCOV'
268         '    --output-file lcov.info'
269         '    --remove /tmp/senf_lcov.info "*/include/*" "*/boost/*" "*.test.*"',
270         '$GENHTML'
271         '    --output-directory doc/lcov'
272         '    --title all_tests lcov.info',
273         'rm /tmp/senf_lcov.info' ])
274 senfutil.CleanGlob(env, ['lcov','some','all'], [ '*.gcno', '*.gcda', '*.gcov' ])
275 env.Clean(['lcov', 'all'], [ 'lcov.info', env.Dir('doc/lcov'), env.Dir('build/lcov') ])
276
277 #### clean
278
279 env.Clean('all', ('.prepare-stamp', env.Dir('dist'), env.Dir('build')))
280
281 senfutil.CleanGlob(env, 'all', '$CLEAN_PATTERNS')
282 senfutil.CleanGlob(env, ['some', 'all'], '$CLEAN_SOME_PATTERNS')
283
284 if env.GetOption('clean') and 'all' in BUILD_TARGETS:
285     env.Depends('all', ('lcov', 'all_valgrinds'))
286     # Disable writing to the deleted .sconsign file
287     import SCons.SConsign
288     SCons.SConsign.write = lambda : None
289
290 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp"):
291     Execute(Touch(".prepare-stamp"))
292
293 ### execute targets on remote hosts
294 for target in COMMAND_LINE_TARGETS:
295     if '@' in target:
296         realtarget, host = target.split('@',1)
297         cwd=env.GetLaunchDir()
298         home=os.environ['HOME']+'/'
299         if cwd.startswith(home) : cwd = cwd[len(home):]
300         args = [ '$SCONSARGS' ]
301         if env.GetLaunchDir() != os.getcwd():
302             args.append('-u')
303         env.PhonyTarget(target, [], [ "ssh $HOST scons $SCONSARGS -C $DIR $RTARGET" ],
304                         HOST=host, RTARGET=realtarget, DIR=cwd, SCONSARGS=args)
305
306 env.PhonyTarget('clean', [], [
307         lambda **args: sys.stderr.write(
308             "=================================================================\n"
309             "'clean' is not a valid target, use the '-c' option instead:\n"
310             "    $ scons -c all\n"
311             "=================================================================\n") ])