scons: added BOOST_VARIANT workaround for karmic
[senf.git] / SConstruct
1 # -*- python -*-
2
3 import sys, os.path, fnmatch
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 You may execute targets on a remote host (if the directory layout is the same)
37 by calling
38
39     scons <target>@[<user>@]<host>
40
41 Some more elaborate unit tests may be enabled by setting appropritate variables 
42 in the shell (unix) environment
43
44 SENF_TIMING_CRITICAL_TESTS
45                 Enables unit tests which depend on timing measurements. These
46                 unit tests should only be run on a single core and an otherwise
47                 idle system.
48
49 SENF_WLAN_TEST_INTERFACE
50                 WLAN interface to use for testing. The interface should not be
51                 actively in use.
52
53 SENF_ETH_TEST_INTERFACE
54                 Ethernet interface to use for testing. The interface should not
55                 be actively in use.
56
57 Some unit tests will only run when executed to 'root'.
58 """)
59
60 env.Append(
61    ENV                    = { 'PATH' : os.environ.get('PATH'), 
62                               'HOME' : os.environ.get('HOME'),
63                               'SSH_AGENT_PID': os.environ.get('SSH_AGENT_PID'),
64                               'SSH_AUTH_SOCK': os.environ.get('SSH_AUTH_SOCK') },
65    CLEAN_PATTERNS         = [ '*~', '#*#', '*.pyc', 'semantic.cache', '.sconsign*' ],
66
67    BUILDDIR               = '${FLAVOR and "#/build/$FLAVOR" or "#"}',
68    CPPPATH                = [ '$BUILDDIR', '#' ],
69    LOCALLIBDIR            = '$BUILDDIR',
70    LIBPATH                = [ '$LOCALLIBDIR' ],
71    LIBS                   = [ '$LIBSENF$LIBADDSUFFIX', '$EXTRA_LIBS' ],
72    EXTRA_LIBS             = [ 'rt', '$BOOSTREGEXLIB', '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB', 
73                               '$BOOSTFSLIB' ], 
74    TEST_EXTRA_LIBS        = [  ],
75    VALGRINDARGS           = [ '--num-callers=50' ],
76
77    PREFIX                 = '#/dist',
78    LIBINSTALLDIR          = '$PREFIX${syslayout and "/lib" or ""}',
79    BININSTALLDIR          = '$PREFIX${syslayout and "/bin" or ""}',
80    INCLUDEINSTALLDIR      = '$PREFIX${syslayout and "/include" or ""}',
81    CONFINSTALLDIR         = '${syslayout and "$LIBINSTALLDIR/senf" or "$PREFIX"}',
82    OBJINSTALLDIR          = '$CONFINSTALLDIR',
83    DOCINSTALLDIR          = '$PREFIX${syslayout and "/share/doc/senf" or "/manual"}',
84    SCONSINSTALLDIR        = '$CONFINSTALLDIR/site_scons',
85
86    CPP_INCLUDE_EXTENSIONS = [ '.h', '.hh', '.ih', '.mpp', '.cci', '.ct', '.cti' ],
87    CPP_EXCLUDE_EXTENSIONS = [ '.test.hh' ],
88
89    # These options are insane. Only useful for inline debugging. Need at least 1G free RAM
90    INLINE_OPTS_DEBUG      = [ '-finline-limit=20000', '-fvisibility-inlines-hidden', 
91                               '-fno-inline-functions', '-Winline' 
92                               '--param','large-function-growth=10000',
93                               '--param', 'large-function-insns=10000', 
94                               '--param','inline-unit-growth=10000' ],
95    INLINE_OPTS_NORMAL     = [ '-finline-limit=5000' ],
96    INLINE_OPTS            = [ '$INLINE_OPTS_NORMAL' ],
97    CXXFLAGS               = [ '-Wall', '-Woverloaded-virtual', '-Wno-long-long', '$INLINE_OPTS',
98                               '$CXXFLAGS_' ],
99    CXXFLAGS_              = senfutil.BuildTypeOptions('CXXFLAGS'),
100    CXXFLAGS_final         = [ '-O3' ],
101    CXXFLAGS_normal        = [ '-O0', '-g' ],
102    CXXFLAGS_debug         = [ '$CXXFLAGS_normal' ],
103
104    CPPDEFINES             = [ '$expandLogOption', '$CPPDEFINES_' ],
105    expandLogOption        = senfutil.expandLogOption,
106    CPPDEFINES_            = senfutil.BuildTypeOptions('CPPDEFINES'),
107    CPPDEFINES_final       = [ ],
108    CPPDEFINES_normal      = [ 'SENF_DEBUG' ],
109    CPPDEFINES_debug       = [ '$CPPDEFINES_normal' ],
110
111    LINKFLAGS              = [ '-rdynamic', '$LINKFLAGS_' ],
112    LINKFLAGS_             = senfutil.BuildTypeOptions('LINKFLAGS'),
113    LINKFLAGS_final        = [ ],
114    LINKFLAGS_normal       = [ '-Wl,-S' ],
115    LINKFLAGS_debug        = [ '-g' ],
116 )
117
118 # Add all UNIX env vars starting with 'SENF' to the execution environment
119 env.Append( ENV = dict(((k,v) for k,v in os.environ.iteritems() if k.startswith("SENF"))) )
120
121 env.SetDefault(
122     LIBSENF           = "senf",
123     LCOV              = "lcov",
124     GENHTML           = "genhtml",
125     SCONSBIN          = env.File("#/tools/scons"),
126     SCONSARGS         = [ '-Q', '-j$CONCURRENCY_LEVEL', 'debug=$debug', 'final=$final' ] + \
127         [ '%s=%s' % (k,v) for k,v in ARGUMENTS.iteritems() ],
128     SCONS             = "@$SCONSBIN $SCONSARGS",
129     CONCURRENCY_LEVEL = env.GetOption('num_jobs') or 1,
130     TOPDIR            = env.Dir('#').abspath,
131     LIBADDSUFFIX      = '${FLAVOR and "_$FLAVOR" or ""}',
132     OBJADDSUFFIX      = '${LIBADDSUFFIX}',
133     FLAVOR            = '',
134 )
135
136 # ugly hack for ubuntu karmic 
137 # ToDo: auto-configure alike support
138 if os.path.exists('/usr/lib/libboost_regex-mt.so'):
139     env.Append( BOOST_VARIANT = '-mt' )
140
141 # Set variables from command line
142 senfutil.parseArguments(
143     env,
144     BoolVariable('final', 'Build final (optimized) build', False),
145     BoolVariable('debug', 'Link in debug symbols', False),
146     BoolVariable('syslayout', 'Install in to system layout directories (lib/, include/ etc)', False),
147     BoolVariable('sparse_tests', 'Link tests against object files and not the senf lib', False)
148 )
149
150 if 'test_changes' in COMMAND_LINE_TARGETS and not env.has_key('only_tests'):
151     import SparseTestHack
152     env['only_tests'] = " ".join(x.abspath for x in SparseTestHack.findSCMChanges(env))
153
154 if env.has_key('only_tests') : env['sparse_tests'] = True
155 Export('env')
156
157 # Create Doxyfile.local otherwise doxygen will barf on this non-existent file
158 # Create it even when cleaning, to silence the doxygen builder warnings
159 if not os.path.exists("doclib/Doxyfile.local"):
160     Execute(Touch("doclib/Doxyfile.local"))
161
162 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp") \
163    and not os.environ.get("SCONS") and COMMAND_LINE_TARGETS != [ 'prepare' ]:
164     env.Execute([ "$SCONS prepare" ])
165
166 # Load SConscripts
167
168 SConscriptChdir(0)
169 SConscript("debian/SConscript")
170 SConscriptChdir(1)
171 if os.path.exists('SConscript.local') : SConscript('SConscript.local')
172 if env['sparse_tests']:
173     import SparseTestHack
174     SparseTestHack.setup(env)
175 if env.subst('$BUILDDIR') == '#':
176     SConscript("SConscript")
177 else:
178     SConscript("SConscript", variant_dir=env.subst('$BUILDDIR'), src_dir='#', duplicate=False)
179 SConscript("Examples/SConscript")
180 SConscript("HowTos/SConscript")
181 SConscript("doclib/SConscript")
182 if env['sparse_tests']:
183     verbose = 'test_changes' in COMMAND_LINE_TARGETS
184     SparseTestHack.build(env, verbose, verbose)
185
186 ###########################################################################
187 # Define build targets
188
189 #### install_all, default, all_tests, all
190 env.Install('${SCONSINSTALLDIR}', [ 'site_scons/__init__.py',
191                                     'site_scons/senfutil.py',
192                                     'site_scons/yaptu.py' ])
193 env.InstallDir('${SCONSINSTALLDIR}', [ 'site_scons/site_tools', 'site_scons/lib' ],
194                FILTER_SUFFIXES=[ '','.css','.pl','.py','.sh','.sty','.xml','.xsl','.yap' ])
195 env.Install('${INCLUDEINSTALLDIR}', 'boost')
196
197 env.Alias('install_all', env.FindInstalledFiles())
198 env.Alias('default', DEFAULT_TARGETS)
199 env.Alias('all_tests', env.FindAllBoostUnitTests())
200 env.Alias('test_changes', 'all_tests')
201 env.Alias('all', [ 'default', 'all_tests', 'examples', 'all_docs' ])
202
203 #### prepare
204 env.PhonyTarget('prepare', [], [])
205
206 #### valgrind
207 for test in env.FindAllBoostUnitTests():
208     stamp = env.Command(test[0].dir.File('.test-valgrind.stamp'), 
209                         [ test[0].dir.File('.test.bin'), 'tools/valgrind.sup' ],
210                         [ """valgrind --tool=memcheck 
211                                       --error-exitcode=99 
212                                       --suppressions=${SOURCES[1]}
213                                       $VALGRINDARGS
214                                           ${SOURCES[0]} $BOOSTTESTARGS;
215                              [ $$? -ne 99 ] || exit 1""".replace("\n"," "),
216                           Touch("$TARGET") ])
217     alias = env.Command(test[0].dir.File('valgrind'), stamp, [ env.NopAction() ])
218     env.Alias('all_valgrinds', alias)
219
220 ### lcov
221 env.PhonyTarget('lcov', [], [
222         '$SCONS debug=1 BUILDDIR="#/build/lcov" CCFLAGS+="-fprofile-arcs -ftest-coverage" LIBS+="gcov" all_tests',
223         '$LCOV --follow --directory $TOPDIR/build/lcov/senf --capture --output-file /tmp/senf_lcov.info --base-directory $TOPDIR',
224         '$LCOV --output-file lcov.info --remove /tmp/senf_lcov.info "*/include/*" "*/boost/*" "*.test.*" ',
225         '$GENHTML --output-directory doc/lcov --title all_tests lcov.info',
226         'rm /tmp/senf_lcov.info' ])
227 if env.GetOption('clean'): 
228     env.Clean('lcov', [ os.path.join(path,f)
229                         for path, subdirs, files in os.walk('.')
230                         for pattern in ('*.gcno', '*.gcda', '*.gcov')
231                         for f in fnmatch.filter(files,pattern) ] + 
232                       [ 'lcov.info', env.Dir('doc/lcov'), env.Dir('build/lcov') ])
233     
234 #### clean
235 env.Clean('all', ('.prepare-stamp', env.Dir('dist'), env.Dir('build')))
236 if env.GetOption('clean') : env.Depends('all', ('lcov', 'all_valgrinds'))
237
238 if env.GetOption('clean') and 'all' in BUILD_TARGETS:
239     env.Clean('all', [ os.path.join(path,f)
240                        for path, subdirs, files in os.walk('.')
241                        for pattern in env['CLEAN_PATTERNS']
242                        for f in fnmatch.filter(files,pattern) ])
243     # Disable writing to the deleted .sconsign file
244     import SCons.SConsign
245     SCons.SConsign.write = lambda : None
246
247 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp"):
248     Execute(Touch(".prepare-stamp"))
249
250 ### execute targets on remote hosts
251 for target in COMMAND_LINE_TARGETS:
252     if '@' in target:
253         realtarget, host = target.split('@',1)
254         cwd=env.GetLaunchDir()
255         home=os.environ['HOME']+'/'
256         if cwd.startswith(home) : cwd = cwd[len(home):]
257         args = [ '$SCONSARGS' ]
258         if env.GetLaunchDir() != os.getcwd():
259             args.append('-u')
260         env.PhonyTarget(target, [], [ "ssh $HOST scons $SCONSARGS -C $DIR $RTARGET" ],
261                         HOST=host, RTARGET=realtarget, DIR=cwd, SCONSARGS=args)