Packets: Better packet registry dump and implement bundledump utility
[senf.git] / site_scons / senfutil.py
1 import os.path, glob, site_tools.Yaptu
2 from SCons.Script import *
3
4 senfutildir = os.path.dirname(__file__)
5
6 # Fix for SCons 0.97 compatibility
7 try:
8     Variables
9 except NameError: 
10     Variables = Options
11     BoolVariable = BoolOption
12
13 def parseLogOption(value):
14     stream, area, level = ( x.strip() for x in value.strip().split('|') )
15     stream = ''.join('(%s)' % x for x in stream.split('::') )
16     if area : area = ''.join( '(%s)' % x for x in area.split('::') )
17     else    : area = '(_)'
18     return '((%s,%s,%s))' % (stream,area,level)
19
20 def expandLogOption(target, source, env, for_signature):
21     if env.get('LOGLEVELS'):
22         return [ 'SENF_LOG_CONF="' + ''.join( parseLogOption(x) for x in env.subst('$LOGLEVELS').split() )+'"']
23     else:
24         return []
25
26 class BuildTypeOptions:
27     def __init__(self, var):
28         self._var = var
29
30     def __call__(self, target, source, env, for_signature):
31         type = env['final'] and "final" or env['debug'] and "debug" or "normal"
32         return env[self._var + "_" + type]
33
34 def loadTools(env):
35     global senfutildir
36     tooldir = os.path.join(senfutildir, 'site_tools')
37     for tool in os.listdir(tooldir):
38         name, ext = os.path.splitext(tool)
39         if ext == '.py' and name != "__init__" : env.Tool(name, [ tooldir ])
40
41 def parseArguments(env, *defs):
42     vars = Variables(args=ARGUMENTS)
43     for d in defs : vars.Add(d)
44     vars.Update(env)
45     env.Help("""
46 Any construction environment variable may be set from the scons
47 command line (see SConstruct file and SCons documentation for a list
48 of variables) using
49
50    VARNAME=value    Assign new value  
51    VARNAME+=value   Append value at end
52
53 Special command line parameters:
54 """)
55     env.Help(vars.GenerateHelpText(env))
56     try                  : unknv = vars.UnknownVariables()
57     except AttributeError: unknv = vars.UnknownOptions()
58     for k,v in unknv.iteritems():
59         if k.endswith('+'):
60             env.Append(**{k[:-1]: v})
61         else:
62             env.Replace(**{k: v})
63
64
65 ###########################################################################
66 # This looks much more complicated than it is: We do three things here:
67 # a) switch between final or debug options
68 # b) parse the LOGLEVELS parameter into the correct SENF_LOG_CONF syntax
69 # c) check for a local SENF, set options accordingly and update that SENF if needed
70
71 def SetupForSENF(env, senf_path = []):
72     global senfutildir
73     senf_path.extend(('senf', os.path.dirname(senfutildir), '/usr/local', '/usr'))
74
75     loadTools(env)
76
77     env.Append(
78         LIBS              = [ 'senf', 'rt', '$BOOSTREGEXLIB',
79                               '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB',
80                               '$BOOSTFSLIB' ],
81         BOOSTREGEXLIB     = 'boost_regex',
82         BOOSTIOSTREAMSLIB = 'boost_iostreams',
83         BOOSTSIGNALSLIB   = 'boost_signals',
84         BOOSTFSLIB        = 'boost_filesystem',
85         
86         CXXFLAGS          = [ '-Wno-long-long', '$CXXFLAGS_' ],
87         CXXFLAGS_         = BuildTypeOptions('CXXFLAGS'),
88         
89         CPPDEFINES        = [ '$expandLogOption', '$CPPDEFINES_' ],
90         expandLogOption   = expandLogOption,
91         CPPDEFINES_       = BuildTypeOptions('CPPDEFINES'),
92         
93         LINKFLAGS         = [ '-rdynamic', '$LINKFLAGS_' ],
94         LINKFLAGS_        = BuildTypeOptions('LINKFLAGS'),
95
96         LOGLEVELS         = [ '$LOGLEVELS_' ],
97         LOGLEVELS_        = BuildTypeOptions('LOGLEVELS'),
98         )
99
100     env.SetDefault( 
101         CXXFLAGS_final    = [],
102         CXXFLAGS_normal   = [],
103         CXXFLAGS_debug    = [],
104
105         CPPDEFINES_final  = [],
106         CPPDEFINES_normal = [],
107         CPPDEFINES_debug  = [],
108
109         LINKFLAGS_final   = [],
110         LINKFLAGS_normal  = [],
111         LINKFLAGS_debug   = [],
112
113         LOGLEVELS_final   = [],
114         LOGLEVELS_normal  = [],
115         LOGLEVELS_debug   = [],
116
117         PROJECTNAME       = "Unnamed project",
118         DOCLINKS          = [],
119         PROJECTEMAIL      = "nobody@nowhere.org",
120         COPYRIGHT         = "nobody",
121         REVISION          = "unknown",
122         )
123
124     # Interpret command line options
125     parseArguments(
126         env, 
127         BoolVariable('final', 'Build final (optimized) build', False),
128         BoolVariable('debug', 'Link in debug symbols', False),
129     )
130
131     # If we have a symbolic link (or directory) 'senf', we use it as our
132     # senf repository
133     for path in senf_path:
134         if not path.startswith('/') : sconspath = '#/%s' % path
135         else                        : sconspath = path
136         if os.path.exists(os.path.join(path,"senf/config.hh")):
137             if not env.GetOption('no_progress'):
138                 print "\nUsing SENF in '%s'\n" \
139                     % ('/..' in sconspath and os.path.abspath(path) or sconspath)
140             env.Append( LIBPATH = [ sconspath ],
141                         CPPPATH = [ sconspath ],
142                         BUNDLEDIR = sconspath,
143                         SENFDIR = sconspath,
144                         SENFSYSLAYOUT = False)
145             try:
146                 env.MergeFlags(file(os.path.join(path,"senf.conf")).read())
147             except IOError:
148                 if not env.GetOption('no_progress'):
149                     print "(SENF configuration file 'senf.conf' not found, assuming non-final SENF)"
150                 env.Append(CPPDEFINES = [ 'SENF_DEBUG' ])
151             break
152         elif os.path.exists(os.path.join(path,"include/senf/config.hh")):
153             if not env.GetOption('no_progress'):
154                 print "\nUsing system SENF in '%s/'\n" % sconspath
155             env.Append(BUNDLEDIR = os.path.join(sconspath,"lib/senf"),
156                        SENFDIR = sconspath,
157                        SENFSYSLAYOUT = True)
158             break
159     else:
160         if not env.GetOption('no_progress'):
161             print "\nSENF library not found .. trying build anyway !!\n"
162
163     env.Alias('all', '#')
164
165
166 def DefaultOptions(env):
167     env.Append(
168         CXXFLAGS         = [ '-Wall', '-Woverloaded-virtual' ],
169         CXXFLAGS_final   = [ '-O2' ],
170         CXXFLAGS_normal  = [ '-O0', '-g' ],
171         CXXFLAGS_debug   = [ '$CXXFLAGS_normal' ],
172
173         LINKFLAGS_normal = [ '-Wl,-S' ],
174         LINKFLAGS_debug  = [ '-g' ],
175     )
176
177 def Glob(env, exclude=[], subdirs=[]):
178     testSources = env.Glob("*.test.cc", strings=True)
179     sources = [ x 
180                 for x in env.Glob("*.cc", strings=True) 
181                 if x not in testSources and x not in exclude ]
182     for subdir in subdirs:
183         testSources += env.Glob(os.path.join(subdir,"*.test.cc"), strings=True)
184         sources += [ x 
185                      for x in env.Glob(os.path.join(subdir,"*.cc"), strings=True)
186                      if x not in testSources and x not in exclude ]
187     sources.sort()
188     testSources.sort()
189     return (sources, testSources)
190
191 tagfiles = None
192
193 def Doxygen(env, doxyheader=None, doxyfooter=None, doxycss=None, mydoxyfile=False, senfdoc_path=[],
194             **kw):
195     # Additional interesting keyword arguments or environment variables:
196     #    PROJECTNAME, DOCLINKS, PROJECTEMAIL, COPYRIGHT, REVISION
197
198     global senfutildir
199     global tagfiles
200     libdir=os.path.join(senfutildir, 'lib')
201     
202     if tagfiles is None:
203         senfdocdir = None
204         senfdoc_path.extend(('senfdoc', '$SENFDIR', '$SENFDIR/manual',
205                              '$SENFDIR/share/doc/senf', '$SENFDIR/share/doc/libsenf-doc/html'))
206         for path in senfdoc_path:
207             path = env.Dir(path).get_path()
208             if os.path.exists(os.path.join(path, "doc/doclib.tag")):
209                 senfdocdir = path
210                 break
211         tagfiles = []
212         if senfdocdir is None:
213             if not env.GetOption('no_progress'):
214                 print "(SENF documentation not found)"
215         else:
216             for dir, dirs, files in os.walk(senfdocdir):
217                 tagfiles.extend([ os.path.join(dir,f) for f in files if f.endswith('.tag') ])
218                 if dir.endswith('/doc') : 
219                     try: dirs.remove('html')
220                     except ValueError: pass
221                 for d in dirs: 
222                     if d.startswith('.') : dirs.remove(d)
223     
224     if env.GetOption('clean'):
225         env.Clean('doc', env.Dir('doc'))
226         if not mydoxyfile:
227             env.Clean('doc', "Doxyfile")
228
229     if not mydoxyfile:
230         # Create Doxyfile NOW
231         site_tools.Yaptu.yaptuAction("Doxyfile", 
232                                      os.path.join(libdir, "Doxyfile.yap"),
233                                      env)
234
235     envvalues = [ env.Value('$PROJECTNAME'),
236                   env.Value('$DOCLINKS'),
237                   env.Value('$PROJECTEMAIL'),
238                   env.Value('$COPYRIGHT'),
239                   env.Value('$REVISION') ]
240
241     # The other files are created using dependencies
242     if doxyheader: 
243         doxyheader = env.CopyToDir(env.Dir("doc"), doxyheader)
244     else:
245         doxyheader = env.Yaptu("doc/doxyheader.html", os.path.join(libdir, "doxyheader.yap"), **kw)
246         env.Depends(doxyheader, envvalues)
247     if doxyfooter:
248         doxyfooter = env.CopyToDir(env.Dir("doc"), doxyfooter)
249     else:
250         doxyfooter = env.Yaptu("doc/doxyfooter.html", os.path.join(libdir, "doxyfooter.yap"), **kw)
251         env.Depends(doxyfooter, envvalues)
252     if doxycss:
253         doxycss = env.CopyToDir(env.Dir("doc"), doxycss)
254     else:
255         doxycss    = env.CopyToDir(env.Dir("doc"), os.path.join(libdir, "doxy.css"))
256
257     doc = env.Doxygen("Doxyfile",
258                       DOXYOPTS   = [ '--html', '--tagfiles', '"$TAGFILES"' ],
259                       DOXYENV    = { 'TOPDIR'     : env.Dir('#').abspath,
260                                      'LIBDIR'     : libdir,
261                                      'REVISION'   : '$REVISION',
262                                      'tagfiles'   : '$TAGFILES',
263                                      'output_dir' : 'doc',
264                                      'html_dir'   : 'html',
265                                      'html'       : 'YES' },
266                       TAGFILES   = tagfiles, 
267                       DOCLIBDIR  = libdir,
268                       DOXYGENCOM = "$DOCLIBDIR/doxygen.sh $DOXYOPTS $SOURCE")
269
270     env.Depends(doc, [ doxyheader, doxyfooter, doxycss ])
271
272     return doc