Packets/GenericTLV: added some documentation
[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
42 env.Append(
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*' ],
48
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', 
55                               '$BOOSTFSLIB' ], 
56    TEST_EXTRA_LIBS        = [  ],
57    VALGRINDARGS           = [ '--num-callers=50' ],
58
59    PREFIX                 = '#/dist',
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',
67
68    CPP_INCLUDE_EXTENSIONS = [ '.h', '.hh', '.ih', '.mpp', '.cci', '.ct', '.cti' ],
69    CPP_EXCLUDE_EXTENSIONS = [ '.test.hh' ],
70
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',
80                               '$CXXFLAGS_' ],
81    CXXFLAGS_              = senfutil.BuildTypeOptions('CXXFLAGS'),
82    CXXFLAGS_final         = [ '-O3' ],
83    CXXFLAGS_normal        = [ '-O0', '-g' ],
84    CXXFLAGS_debug         = [ '$CXXFLAGS_normal' ],
85
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' ],
92
93    LINKFLAGS              = [ '-rdynamic', '$LINKFLAGS_' ],
94    LINKFLAGS_             = senfutil.BuildTypeOptions('LINKFLAGS'),
95    LINKFLAGS_final        = [ ],
96    LINKFLAGS_normal       = [ '-Wl,-S' ],
97    LINKFLAGS_debug        = [ '-g' ],
98 )
99
100 env.SetDefault(
101     LIBSENF           = "senf",
102     LCOV              = "lcov",
103     GENHTML           = "genhtml",
104     SCONSBIN          = env.File("#/tools/scons"),
105     SCONSARGS         = [ '-Q', '-j$CONCURRENCY_LEVEL', 'debug=$debug', 'final=$final' ] + \
106         [ '%s=%s' % (k,v) for k,v in ARGUMENTS.iteritems() ],
107     SCONS             = "@$SCONSBIN $SCONSARGS",
108     CONCURRENCY_LEVEL = env.GetOption('num_jobs') or 1,
109     TOPDIR            = env.Dir('#').abspath,
110     LIBADDSUFFIX      = '${FLAVOR and "_$FLAVOR" or ""}',
111     OBJADDSUFFIX      = '${LIBADDSUFFIX}',
112     FLAVOR            = '',
113 )
114
115 # Set variables from command line
116 senfutil.parseArguments(
117     env,
118     BoolVariable('final', 'Build final (optimized) build', False),
119     BoolVariable('debug', 'Link in debug symbols', False),
120     BoolVariable('syslayout', 'Install in to system layout directories (lib/, include/ etc)', False),
121     BoolVariable('sparse_tests', 'Link tests against object files and not the senf lib', False)
122 )
123
124 if 'test_changes' in COMMAND_LINE_TARGETS and not env.has_key('only_tests'):
125     import SparseTestHack
126     env['only_tests'] = " ".join(x.abspath for x in SparseTestHack.findSCMChanges(env))
127
128 if env.has_key('only_tests') : env['sparse_tests'] = True
129 Export('env')
130
131 # Create Doxyfile.local otherwise doxygen will barf on this non-existent file
132 # Create it even when cleaning, to silence the doxygen builder warnings
133 if not os.path.exists("doclib/Doxyfile.local"):
134     Execute(Touch("doclib/Doxyfile.local"))
135
136 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp") \
137    and not os.environ.get("SCONS") and COMMAND_LINE_TARGETS != [ 'prepare' ]:
138     env.Execute([ "$SCONS prepare" ])
139
140 # Load SConscripts
141
142 SConscriptChdir(0)
143 SConscript("debian/SConscript")
144 SConscriptChdir(1)
145 if os.path.exists('SConscript.local') : SConscript('SConscript.local')
146 if env['sparse_tests']:
147     import SparseTestHack
148     SparseTestHack.setup(env)
149 if env.subst('$BUILDDIR') == '#':
150     SConscript("SConscript")
151 else:
152     SConscript("SConscript", variant_dir=env.subst('$BUILDDIR'), src_dir='#', duplicate=False)
153 SConscript("Examples/SConscript")
154 SConscript("HowTos/SConscript")
155 SConscript("doclib/SConscript")
156 if env['sparse_tests']:
157     verbose = 'test_changes' in COMMAND_LINE_TARGETS
158     SparseTestHack.build(env, verbose, verbose)
159
160 ###########################################################################
161 # Define build targets
162
163 #### install_all, default, all_tests, all
164 env.Install('${SCONSINSTALLDIR}', [ 'site_scons/__init__.py',
165                                     'site_scons/senfutil.py',
166                                     'site_scons/yaptu.py' ])
167 env.InstallDir('${SCONSINSTALLDIR}', [ 'site_scons/site_tools', 'site_scons/lib' ],
168                FILTER_SUFFIXES=[ '','.css','.pl','.py','.sh','.sty','.xml','.xsl','.yap' ])
169 env.Install('${INCLUDEINSTALLDIR}', 'boost')
170
171 env.Alias('install_all', env.FindInstalledFiles())
172 env.Alias('default', DEFAULT_TARGETS)
173 env.Alias('all_tests', env.FindAllBoostUnitTests())
174 env.Alias('test_changes', 'all_tests')
175 env.Alias('all', [ 'default', 'all_tests', 'examples', 'all_docs' ])
176
177 #### prepare
178 env.PhonyTarget('prepare', [], [])
179
180 #### valgrind
181 for test in env.FindAllBoostUnitTests():
182     stamp = env.Command(test[0].dir.File('.test-valgrind.stamp'), 
183                         [ test[0].dir.File('.test.bin'), 'tools/valgrind.sup' ],
184                         [ """valgrind --tool=memcheck 
185                                       --error-exitcode=99 
186                                       --suppressions=${SOURCES[1]}
187                                       $VALGRINDARGS
188                                           ${SOURCES[0]} $BOOSTTESTARGS;
189                              [ $$? -ne 99 ] || exit 1""".replace("\n"," "),
190                           Touch("$TARGET") ])
191     alias = env.Command(test[0].dir.File('valgrind'), stamp, [ env.NopAction() ])
192     env.Alias('all_valgrinds', alias)
193
194 ### lcov
195 env.PhonyTarget('lcov', [], [
196         '$SCONS debug=1 BUILDDIR="#/build/lcov" CCFLAGS+="-fprofile-arcs -ftest-coverage" LIBS+="gcov" all_tests',
197         '$LCOV --follow --directory $TOPDIR/build/lcov/senf --capture --output-file /tmp/senf_lcov.info --base-directory $TOPDIR',
198         '$LCOV --output-file lcov.info --remove /tmp/senf_lcov.info "*/include/*" "*/boost/*" "*.test.*" ',
199         '$GENHTML --output-directory doc/lcov --title all_tests lcov.info',
200         'rm /tmp/senf_lcov.info' ])
201 if env.GetOption('clean'): 
202     env.Clean('lcov', [ os.path.join(path,f)
203                         for path, subdirs, files in os.walk('.')
204                         for pattern in ('*.gcno', '*.gcda', '*.gcov')
205                         for f in fnmatch.filter(files,pattern) ] + 
206                       [ 'lcov.info', env.Dir('doc/lcov'), env.Dir('build/lcov') ])
207     
208 #### clean
209 env.Clean('all', ('.prepare-stamp', env.Dir('dist'), env.Dir('build')))
210 if env.GetOption('clean') : env.Depends('all', ('lcov', 'all_valgrinds'))
211
212 if env.GetOption('clean') and 'all' in BUILD_TARGETS:
213     env.Clean('all', [ os.path.join(path,f)
214                        for path, subdirs, files in os.walk('.')
215                        for pattern in env['CLEAN_PATTERNS']
216                        for f in fnmatch.filter(files,pattern) ])
217     # Disable writing to the deleted .sconsign file
218     import SCons.SConsign
219     SCons.SConsign.write = lambda : None
220
221 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp"):
222     Execute(Touch(".prepare-stamp"))
223
224 ### execute targets on remote hosts
225 for target in COMMAND_LINE_TARGETS:
226     if '@' in target:
227         realtarget, host = target.split('@',1)
228         cwd=env.GetLaunchDir()
229         home=os.environ['HOME']+'/'
230         if cwd.startswith(home) : cwd = cwd[len(home):]
231         args = [ '$SCONSARGS' ]
232         if env.GetLaunchDir() != os.getcwd():
233             args.append('-u')
234         env.PhonyTarget(target, [], [ "ssh $HOST scons $SCONSARGS -C $DIR $RTARGET" ],
235                         HOST=host, RTARGET=realtarget, DIR=cwd, SCONSARGS=args)