Combine all boot build stuff in a single scons tool
[senf.git] / SConstruct
1 # -*- python -*-
2
3 import sys, glob, os.path, datetime, pwd, time, fnmatch, string
4 sys.path.append(Dir('#/senfscons').abspath)
5 sys.path.append(Dir('#/doclib').abspath)
6 import SENFSCons, senfutil
7
8 ###########################################################################
9 # Load utilities and setup libraries and configure build
10
11 env = Environment()
12
13 # Load all the local SCons tools
14 env.Tool('Doxygen', [ 'senfscons' ])
15 env.Tool('Dia2Png', [ 'senfscons' ])
16 env.Tool('PkgDraw', [ 'senfscons' ])
17 env.Tool('InstallSubdir', [ 'senfscons' ])
18 env.Tool('CopyToDir', [ 'senfscons' ])
19 env.Tool('Boost', [ 'senfscons' ])
20 env.Tool('CombinedObject', [ 'senfscons' ])
21 env.Tool('PhonyTarget', [ 'senfscons' ])
22
23 env.Help("""
24 Additional top-level build targets:
25
26 prepare      Create all target files not part of the repository
27 all_tests    Build and run unit tests for all modules
28 all_docs     Build documentation for all modules
29 all          Build everything
30 install_all  Install SENF into $PREFIX
31 deb          Build debian source and binary package
32 debsrc       Build debian source package
33 debbin       Build debian binary package
34 linklint     Check links of doxygen documentation with 'linklint'
35 fixlinks     Fix broken links in doxygen documentation
36 valgrind     Run all tests under valgrind/memcheck
37 """)
38
39 class BuildTypeOptions:
40     def __init__(self, var):
41         self._var = var
42
43     def __call__(self, target, source, env, for_signature):
44         type = env['final'] and "final" or env['debug'] and "debug" or "normal"
45         return env[self._var + "_" + type]
46
47 env.Replace(
48    PKGDRAW                = 'doclib/pkgdraw',
49 )
50
51 env.Append(
52    ENV                    = { 'PATH' : os.environ.get('PATH') },
53    CLEAN_PATTERNS         = [ '*~', '#*#', '*.pyc', 'semantic.cache', '.sconsign*', '.sconsign' ],
54
55    CPPPATH                = [ '#/include' ],
56    LOCALLIBDIR            = '#',
57    LIBPATH                = [ '$LOCALLIBDIR' ],
58    LIBS                   = [ '$LIBSENF$LIBADDSUFFIX', 'rt', '$BOOSTREGEXLIB', 
59                               '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB', '$BOOSTFSLIB' ], 
60    TEST_EXTRA_LIBS        = [  ],
61
62    PREFIX                 = '/usr/local',
63    LIBINSTALLDIR          = '$PREFIX/lib',
64    BININSTALLDIR          = '$PREFIX/bin',
65    INCLUDEINSTALLDIR      = '$PREFIX/include',
66    OBJINSTALLDIR          = '$LIBINSTALLDIR',
67    DOCINSTALLDIR          = '$PREFIX/doc',
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_              = 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_            = BuildTypeOptions('CPPDEFINES'),
89    CPPDEFINES_final       = [ ],
90    CPPDEFINES_normal      = [ 'SENF_DEBUG' ],
91    CPPDEFINES_debug       = [ '$CPPDEFINES_normal' ],
92
93    LINKFLAGS              = [ '-rdynamic', '$LINKFLAGS_' ],
94    LINKFLAGS_             = BuildTypeOptions('LINKFLAGS'),
95    LINKFLAGS_final        = [ ],
96    LINKFLAGS_normal       = [ '-Wl,-S' ],
97    LINKFLAGS_debug        = [ ],
98 )
99
100 env.SetDefault(
101     LIBSENF = "senf",
102     final   = 0,
103     debug   = 0,
104 )
105
106 # Set variables from command line
107 env.Replace(**ARGUMENTS)
108
109 Export('env')
110
111 # Create Doxyfile.local otherwise doxygen will barf on this non-existent file
112 # Create it even when cleaning, to silence the doxygen builder warnings
113 if not os.path.exists("Doxyfile.local"):
114     Execute(Touch("Doxyfile.local"))
115
116 # Create local_config.h
117 if not env.GetOption('clean') and not os.path.exists("local_config.hh"):
118     Execute(Touch("local_config.hh"))
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. Need to load some first (they change the global environment)
125 initSConscripts = [ 
126     "debian/SConscript",
127     "doclib/SConscript",
128 ]
129
130 SConscript(initSConscripts)
131
132 if os.path.exists('SConscript.local'):
133     SConscript('SConscript.local')
134
135 SConscript(list(set(glob.glob("*/SConscript")) - set(initSConscripts)))
136
137 ###########################################################################
138 # Define build targets
139
140 #### doc
141 env.Depends(SENFSCons.Doxygen(env), env.Value(env['ENV']['REVISION']))
142
143 #### libsenf.a
144 libsenf = env.Library(env.subst("$LIBSENF$LIBADDSUFFIX"), env['ALLOBJECTS'])
145 env.Default(libsenf)
146
147 env.InstallSubdir(target = '$INCLUDEINSTALLDIR', source = [ 'config.hh' ])
148 env.Install('$LIBINSTALLDIR', libsenf)
149
150 #### install_all, default, all_tests, all
151 env.Alias('install_all', env.FindInstalledFiles())
152 env.Alias('default', DEFAULT_TARGETS)
153 env.Alias('all_tests', env.FindAllBoostUnitTests())
154 env.Alias('all', [ 'default', 'all_tests', 'all_docs' ])
155
156 #### prepare
157 env.PhonyTarget('prepare', [], [])
158
159 #### valgrind
160 env.PhonyTarget('valgrind', [ 'all_tests' ], [ """
161     find -name .test.bin 
162         | while read test; do
163             echo;
164             echo "Running $$test";
165             echo;
166             valgrind --tool=memcheck --error-exitcode=99 --suppressions=valgrind.sup 
167                 $$test $BOOSTTESTARGS;
168             [ $$? -ne 99 ] || exit 1;
169         done
170 """.replace("\n"," ") ])
171
172 #### clean
173 env.Clean('all', '.prepare-stamp')
174 env.Clean('all', libsenf)
175 env.Clean('all', 'linklint')
176
177 if env.GetOption('clean'):
178     env.Clean('all', [ os.path.join(path,f)
179                        for path, subdirs, files in os.walk('.')
180                        for pattern in env['CLEAN_PATTERNS']
181                        for f in fnmatch.filter(files,pattern) ])
182
183 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp"):
184     Execute(Touch(".prepare-stamp"))