Further top-dir cleanup and lcov target
[senf.git] / SConstruct
1 # -*- python -*-
2
3 import sys, glob, 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 env.Tool('Doxygen')
16 env.Tool('Dia2Png')
17 env.Tool('PkgDraw')
18 env.Tool('InstallSubdir')
19 env.Tool('CopyToDir')
20 env.Tool('Boost')
21 env.Tool('CombinedObject')
22 env.Tool('PhonyTarget')
23 env.Tool('InstallDir')
24
25 env.Help("""
26 Additional top-level build targets:
27
28 prepare      Create all target files not part of the repository
29 default      Build all default targets (like calling scons with no arguments)
30 examples     Build all examples
31 all_tests    Build and run unit tests for all modules
32 all_docs     Build documentation for all modules
33 all          Build everything
34 install_all  Install SENF into $$PREFIX
35 deb          Build debian source and binary package
36 debsrc       Build debian source package
37 debbin       Build debian binary package
38 linklint     Check links of doxygen documentation with 'linklint'
39 fixlinks     Fix broken links in doxygen documentation
40 valgrind     Run all tests under valgrind/memcheck
41 lcov         Generate test coverage output in doc/lcov and lcov.info
42 """)
43
44 env.Append(
45    ENV                    = { 'PATH' : os.environ.get('PATH'), 'HOME' : os.environ.get('HOME') },
46    CLEAN_PATTERNS         = [ '*~', '#*#', '*.pyc', 'semantic.cache', '.sconsign*',
47                               '*.gcno', '*.gcda', '*.gcov' ],
48
49    CPPPATH                = [ '#' ],
50    LOCALLIBDIR            = '#',
51    LIBPATH                = [ '$LOCALLIBDIR' ],
52    LIBS                   = [ '$LIBSENF$LIBADDSUFFIX', 'rt', '$BOOSTREGEXLIB', 
53                               '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB', '$BOOSTFSLIB' ], 
54    TEST_EXTRA_LIBS        = [  ],
55
56    PREFIX                 = '#/dist',
57    LIBINSTALLDIR          = '$PREFIX${syslayout and "/lib" or ""}',
58    BININSTALLDIR          = '$PREFIX${syslayout and "/bin" or ""}',
59    INCLUDEINSTALLDIR      = '$PREFIX${syslayout and "/include" or ""}',
60    CONFINSTALLDIR         = '${syslayout and "$LIBINSTALLDIR/senf" or "$PREFIX"}',
61    OBJINSTALLDIR          = '$CONFINSTALLDIR',
62    DOCINSTALLDIR          = '$PREFIX${syslayout and "/share/doc/senf" or "/manual"}',
63    SCONSINSTALLDIR        = '$CONFINSTALLDIR/site_scons',
64
65    CPP_INCLUDE_EXTENSIONS = [ '.h', '.hh', '.ih', '.mpp', '.cci', '.ct', '.cti' ],
66    CPP_EXCLUDE_EXTENSIONS = [ '.test.hh' ],
67
68    # These options are insane. Only useful for inline debugging. Need at least 1G free RAM
69    INLINE_OPTS_DEBUG      = [ '-finline-limit=20000', '-fvisibility-inlines-hidden', 
70                               '-fno-inline-functions', '-Winline' 
71                               '--param','large-function-growth=10000',
72                               '--param', 'large-function-insns=10000', 
73                               '--param','inline-unit-growth=10000' ],
74    INLINE_OPTS_NORMAL     = [ '-finline-limit=5000' ],
75    INLINE_OPTS            = [ '$INLINE_OPTS_NORMAL' ],
76    CXXFLAGS               = [ '-Wall', '-Woverloaded-virtual', '-Wno-long-long', '$INLINE_OPTS',
77                               '$CXXFLAGS_' ],
78    CXXFLAGS_              = senfutil.BuildTypeOptions('CXXFLAGS'),
79    CXXFLAGS_final         = [ '-O3' ],
80    CXXFLAGS_normal        = [ '-O0', '-g' ],
81    CXXFLAGS_debug         = [ '$CXXFLAGS_normal' ],
82
83    CPPDEFINES             = [ '$expandLogOption', '$CPPDEFINES_' ],
84    expandLogOption        = senfutil.expandLogOption,
85    CPPDEFINES_            = senfutil.BuildTypeOptions('CPPDEFINES'),
86    CPPDEFINES_final       = [ ],
87    CPPDEFINES_normal      = [ 'SENF_DEBUG' ],
88    CPPDEFINES_debug       = [ '$CPPDEFINES_normal' ],
89
90    LINKFLAGS              = [ '-rdynamic', '$LINKFLAGS_' ],
91    LINKFLAGS_             = senfutil.BuildTypeOptions('LINKFLAGS'),
92    LINKFLAGS_final        = [ ],
93    LINKFLAGS_normal       = [ '-Wl,-S' ],
94    LINKFLAGS_debug        = [ '-g' ],
95 )
96
97 env.SetDefault(
98     LIBSENF           = "senf",
99     LCOV              = "lcov",
100     GENHTML           = "genhtml",
101     SCONS             = "./tools/scons -j$CONCURRENCY_LEVEL",
102     CONCURRENCY_LEVEL = env.GetOption('num_jobs') or 1,
103 )
104
105 # Set variables from command line
106 senfutil.parseArguments(
107     env,
108     BoolVariable('final', 'Build final (optimized) build', False),
109     BoolVariable('debug', 'Link in debug symbols', False),
110     BoolVariable('syslayout', 'Install in to system layout directories (lib/, include/ etc)', False),
111 )
112
113 Export('env')
114
115 # Create Doxyfile.local otherwise doxygen will barf on this non-existent file
116 # Create it even when cleaning, to silence the doxygen builder warnings
117 if not os.path.exists("Doxyfile.local"):
118     Execute(Touch("Doxyfile.local"))
119
120 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp") \
121    and not os.environ.get("SCONS") and COMMAND_LINE_TARGETS != [ 'prepare' ]:
122     env.Execute([ "scons prepare" ])
123
124 # Load SConscripts
125
126 SConscriptChdir(0)
127 SConscript("debian/SConscript")
128 SConscriptChdir(1)
129 if os.path.exists('SConscript.local') : SConscript('SConscript.local')
130 SConscript("senf/SConscript")
131 SConscript("Examples/SConscript")
132 SConscript("HowTos/SConscript")
133 SConscript("doclib/SConscript")
134
135 ###########################################################################
136 # Define build targets
137
138 #### doc
139 env.Depends(SENFSCons.Doxygen(env), env.Value(env['ENV']['REVISION']))
140
141 #### libsenf.a
142 libsenf = env.Library("$LOCALLIBDIR/${LIBSENF}${LIBADDSUFFIX}", env['ALLOBJECTS'])
143 env.Default(libsenf)
144 env.Install('$LIBINSTALLDIR', libsenf)
145
146 def create(target, source, env): 
147     file(str(target[0]), 'w').write(source[0].get_contents()+"\n")
148 env['BUILDERS']['CreateFile'] = Builder(action = create)
149
150 conf = env.CreateFile("${LOCALLIBDIR}/${LIBSENF}${LIBADDSUFFIX}.conf", 
151                       env.Value(env.subst("$_CPPDEFFLAGS")))
152 env.Default(conf)
153 env.Install('$CONFINSTALLDIR', conf)
154
155 #### install_all, default, all_tests, all
156 env.Install('${SCONSINSTALLDIR}', [ 'site_scons/__init__.py',
157                                     'site_scons/senfutil.py',
158                                     'site_scons/yaptu.py' ])
159 env.InstallDir('${SCONSINSTALLDIR}', [ 'site_scons/site_tools', 'site_scons/lib' ],
160                FILTER_SUFFIXES=[ '','.css','.pl','.py','.sh','.sty','.xml','.xsl','.yap' ])
161 env.Install('${INCLUDEINSTALLDIR}', 'boost')
162
163 env.Alias('install_all', env.FindInstalledFiles())
164 env.Alias('default', DEFAULT_TARGETS)
165 env.Alias('all_tests', env.FindAllBoostUnitTests())
166 env.Alias('all', [ 'default', 'all_tests', 'examples', 'all_docs' ])
167
168 #### prepare
169 env.PhonyTarget('prepare', [], [])
170
171 #### valgrind
172 env.PhonyTarget('valgrind', [ 'all_tests' ], [ """
173     find -name .test.bin 
174         | while read test; do
175             echo;
176             echo "Running $$test";
177             echo;
178             valgrind --tool=memcheck --error-exitcode=99 --suppressions=tools/valgrind.sup 
179                 $$test $BOOSTTESTARGS;
180             [ $$? -ne 99 ] || exit 1;
181         done
182 """.replace("\n"," ") ])
183
184 ### lcov
185 env.Alias('lcov', env.AlwaysBuild(
186     env.Command( [ env.Dir('doc/lcov'), 'lcov.info' ], [], [
187         '$SCONS debug=1 CCFLAGS+="-fprofile-arcs -ftest-coverage" LIBS+="gcov" all_tests',
188         '$LCOV --directory . --capture --output-file /tmp/senf_lcov.info --base-directory .',
189         '$LCOV --output-file ${TARGETS[1]} --remove /tmp/senf_lcov.info \\*/include/\\*',
190         '$GENHTML --output-directory ${TARGETS[0]} --title all_tests ${TARGETS[1]}',
191         'rm /tmp/senf_lcov.info' ])))
192
193 #### clean
194 env.Clean('all', '.prepare-stamp')
195 env.Clean('all', libsenf)
196 env.Clean('all', env.Dir('linklint')) # env.Dir to disambiguate from linklint PhonyTarget
197 env.Clean('all', env.Dir('dist'))
198 env.Clean('all', 'lcov.info')
199
200 if env.GetOption('clean'):
201     env.Clean('all', [ os.path.join(path,f)
202                        for path, subdirs, files in os.walk('.')
203                        for pattern in env['CLEAN_PATTERNS']
204                        for f in fnmatch.filter(files,pattern) ])
205
206 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp"):
207     Execute(Touch(".prepare-stamp"))