minor fixes for clang++
[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_GCC        = [ '-finline-limit=5000', '--param', 'inline-unit-growth=60' ],
105     INLINE_OPTS            = [ '${str(CXX).split("/")[-1] == "g++" and "$INLINE_OPTS_GCC" or None}' ],
106     CXXFLAGS_CLANG         = [ '-Wno-unneeded-internal-declaration' ], # needed for BOOST_PARAMETER_KEYWORD
107     CXXFLAGS               = [ '-Wall', '-Woverloaded-virtual', '-Wno-long-long', '$INLINE_OPTS',
108                                '-pipe', '$CXXFLAGS_', '-fno-strict-aliasing', 
109                                "${profile and '-pg' or None}",
110                                '${str(CXX).split("/")[-1] == "clang++" and "$CXXFLAGS_CLANG" or None}' ],
111     CXXFLAGS_final         = [ '-O3', '-fno-threadsafe-statics','-fno-stack-protector',
112                                "${profile and ' ' or '-ffunction-sections'}" ],
113     CXXFLAGS_normal        = [ '-O2', '-g' ],
114     CXXFLAGS_debug         = [ '-O0', '-g' ],
115
116     CPPDEFINES             = [ '$expandLogOption', '$CPPDEFINES_' ],
117     CPPDEFINES_final       = [ 'SENF_PPI_NOTRACE', 'NDEBUG', 
118                                'BOOST_NO_MT', 'BOOST_DISABLE_ASSERTS', 'BOOST_DISABLE_THREADS' ],
119     CPPDEFINES_normal      = [ 'SENF_DEBUG' ],
120     CPPDEFINES_debug       = [ '$CPPDEFINES_normal' ],
121
122     LINKFLAGS              = [ '-rdynamic', '$LINKFLAGS_', "${profile and '-pg' or None}" ],
123     LINKFLAGS_final        = [ "${profile and ' ' or '-Wl,--gc-sections'}" ],
124     LINKFLAGS_normal       = [ '-Wl,-S' ],
125     LINKFLAGS_debug        = [ '-g' ],
126 )
127 env.SetDefault(
128     PREFIX                 = '#/dist',
129     LIBINSTALLDIR          = '$PREFIX${syslayout and "/lib" or ""}',
130     BININSTALLDIR          = '$PREFIX${syslayout and "/bin" or ""}',
131     INCLUDEINSTALLDIR      = '$PREFIX${syslayout and "/include" or ""}',
132     CONFINSTALLDIR         = '${syslayout and "$LIBINSTALLDIR/senf" or "$PREFIX"}',
133     OBJINSTALLDIR          = '$CONFINSTALLDIR',
134     DOCINSTALLDIR          = '$PREFIX${syslayout and "/share/doc/senf" or "/manual"}',
135     SCONSINSTALLDIR        = '$CONFINSTALLDIR/site_scons',
136
137     BUILDDIR               = '${FLAVOR and "#/build/$FLAVOR" or "#"}',
138     LOCALLIBDIR            = '$BUILDDIR',
139
140     LIBSENF                = "senf",
141     LCOV                   = "lcov",
142     GENHTML                = "genhtml",
143     VALGRIND               = "valgrind",
144     SCONSBIN               = env.File("#/tools/scons"),
145     SCONSARGS              = ([ '-Q', '-j$CONCURRENCY_LEVEL' ] +
146                               [ '%s=%s' % (k,v) for k,v in ARGLIST ]),
147     SCONS                  = "@$SCONSBIN $SCONSARGS",
148     CONCURRENCY_LEVEL      = env.GetOption('num_jobs') or 1,
149     TOPDIR                 = env.Dir('#').abspath,
150     LIBADDSUFFIX           = '${FLAVOR and "_$FLAVOR" or ""}',
151     OBJADDSUFFIX           = '${LIBADDSUFFIX}',
152     FLAVOR                 = '',
153
154     PARSEFLAGS             = '',
155 )
156
157 # Set variables from command line
158 senfutil.parseArguments(
159     env,
160     BoolVariable('final', 'Build final (optimized) build', False),
161     BoolVariable('debug', 'Link in debug symbols', False),
162     BoolVariable('profile', 'compile and link with the profiling enabled option', False),
163     BoolVariable('syslayout', 'Install in to system layout directories (lib/, include/ etc)', False),
164     BoolVariable('sparse_tests', 'Link tests against object files and not the senf lib', False)
165 )
166
167 # Add UNIX env vars matching IMPORT_ENV patterns into the execution environment
168 senfutil.importProcessEnv(env)
169
170 # Handle 'test_changes'
171 if 'test_changes' in COMMAND_LINE_TARGETS and not env.has_key('only_tests'):
172     import SparseTestHack
173     env['only_tests'] = " ".join(x.abspath for x in SparseTestHack.findSCMChanges(env))
174
175 if env.has_key('only_tests') : env['sparse_tests'] = True
176
177 Export('env')
178
179 ###########################################################################
180 # Configure
181
182 SConscript('SConfigure')
183
184 # Only add this here, after all configure checks have run
185
186 env.Append(LIBS = [ '$LIBSENF$LIBADDSUFFIX',
187                     '$BOOSTREGEXLIB', '$BOOSTSIGNALSLIB',
188                     '$BOOSTFSLIB', '$BOOSTSYSTEMLIB', '$BOOSTDATETIMELIB' ])
189
190 ###########################################################################
191
192 # Create Doxyfile.local otherwise doxygen will barf on this non-existent file
193 # Create it even when cleaning, to silence the doxygen builder warnings
194 if not os.path.exists("doclib/Doxyfile.local"):
195     Execute(Touch("doclib/Doxyfile.local"))
196
197 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp") \
198    and not os.environ.get("SCONS") and COMMAND_LINE_TARGETS != [ 'prepare' ]:
199     env.Execute([ "$SCONS prepare" ])
200
201 # Load SConscripts
202
203 SConscriptChdir(0)
204 SConscript("debian/SConscript")
205 SConscriptChdir(1)
206 if os.path.exists('SConscript.local') : SConscript('SConscript.local')
207 if env['sparse_tests']:
208     import SparseTestHack
209     SparseTestHack.setup(env)
210 if env.subst('$BUILDDIR') == '#':
211     SConscript("SConscript")
212 else:
213     SConscript("SConscript", variant_dir=env.subst('$BUILDDIR'), src_dir='#', duplicate=False)
214 SConscript("Examples/SConscript")
215 SConscript("HowTos/SConscript")
216 SConscript("doclib/SConscript")
217 if env['sparse_tests']:
218     verbose = 'test_changes' in COMMAND_LINE_TARGETS
219     SparseTestHack.build(env, verbose, verbose)
220
221 ###########################################################################
222 # Define build targets
223
224 #### install_all, default, all_tests, all
225 env.Install('${SCONSINSTALLDIR}', [ 'site_scons/__init__.py',
226                                     'site_scons/senfutil.py',
227                                     'site_scons/yaptu.py' ])
228 env.InstallDir('${SCONSINSTALLDIR}', [ 'site_scons/site_tools', 'site_scons/lib' ],
229                FILTER_SUFFIXES=[ '','.css','.pl','.py','.sh','.sty','.xml','.xsl','.yap' ])
230 env.Install('${INCLUDEINSTALLDIR}', 'boost_ext')
231 env.Install('${INCLUDEINSTALLDIR}/senf', 'senf/boost_intrusive')
232
233 env.Alias('install_all', env.FindInstalledFiles())
234 env.Alias('default', DEFAULT_TARGETS)
235 env.Alias('all_tests', env.FindAllBoostUnitTests())
236 env.Alias('test_changes', 'all_tests')
237 env.Alias('all', [ 'default', 'all_tests', 'examples', 'all_docs' ])
238
239 #### prepare and -c some
240 env.PhonyTarget('prepare', [], [])
241 env.PhonyTarget('some', [], [])
242
243 #### valgrind
244 env.Alias('all_valgrinds')
245 if env.get('HAVE_VALGRIND'):
246     for test in env.FindAllBoostUnitTests():
247         stamp = env.Command(test[0].dir.File('.test-valgrind.stamp'),
248                             [ test[0].dir.File('.test.bin'), 'tools/valgrind.sup' ],
249                             [ """$VALGRIND --tool=memcheck
250                                           --error-exitcode=1
251                                           --suppressions=${SOURCES[1]}
252                                           $VALGRINDARGS
253                                               ${SOURCES[0]} --result_code=no $BOOSTTESTARGS
254                               """.replace("\n"," "),
255                               Touch("$TARGET") ])
256         alias = env.Command(test[0].dir.File('valgrind'), stamp, [ env.NopAction() ])
257         env.Alias('all_valgrinds', alias)
258
259 ### lcov
260 env.PhonyTarget('lcov', [], [
261         '$SCONS'
262         '    debug=1'
263         '    BUILDDIR="#/build/lcov"'
264         '    CCFLAGS+="-fprofile-arcs -ftest-coverage"'
265         '    LIBS+="gcov"'
266         '        all_tests',
267         '$LCOV'
268         '    --follow'
269         '    --directory $TOPDIR/build/lcov/senf'
270         '    --capture'
271         '    --output-file /tmp/senf_lcov.info'
272         '    --base-directory $TOPDIR',
273         '$LCOV'
274         '    --output-file lcov.info'
275         '    --remove /tmp/senf_lcov.info "*/include/*" "*/boost/*" "*.test.*"',
276         '$GENHTML'
277         '    --output-directory doc/lcov'
278         '    --title all_tests lcov.info',
279         'rm /tmp/senf_lcov.info' ])
280 senfutil.CleanGlob(env, ['lcov','some','all'], [ '*.gcno', '*.gcda', '*.gcov' ])
281 env.Clean(['lcov', 'all'], [ 'lcov.info', env.Dir('doc/lcov'), env.Dir('build/lcov') ])
282
283 #### clean
284
285 env.Clean('all', ('.prepare-stamp', env.Dir('dist'), env.Dir('build')))
286
287 senfutil.CleanGlob(env, 'all', '$CLEAN_PATTERNS')
288 senfutil.CleanGlob(env, ['some', 'all'], '$CLEAN_SOME_PATTERNS')
289
290 if env.GetOption('clean') and 'all' in BUILD_TARGETS:
291     env.Depends('all', ('lcov', 'all_valgrinds'))
292     # Disable writing to the deleted .sconsign file
293     import SCons.SConsign
294     SCons.SConsign.write = lambda : None
295
296 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp"):
297     Execute(Touch(".prepare-stamp"))
298
299 ### execute targets on remote hosts
300 for target in COMMAND_LINE_TARGETS:
301     if '@' in target:
302         realtarget, host = target.split('@',1)
303         cwd=env.GetLaunchDir()
304         home=os.environ['HOME']+'/'
305         if cwd.startswith(home) : cwd = cwd[len(home):]
306         args = [ '$SCONSARGS' ]
307         if env.GetLaunchDir() != os.getcwd():
308             args.append('-u')
309         env.PhonyTarget(target, [], [ "ssh $HOST scons $SCONSARGS -C $DIR $RTARGET" ],
310                         HOST=host, RTARGET=realtarget, DIR=cwd, SCONSARGS=args)
311
312 env.PhonyTarget('clean', [], [
313         lambda **args: sys.stderr.write(
314             "=================================================================\n"
315             "'clean' is not a valid target, use the '-c' option instead:\n"
316             "    $ scons -c all\n"
317             "=================================================================\n") ])