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