scons: added BOOST_VARIANT workaround for karmic
[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         
82         CXXFLAGS          = [ '-Wno-long-long', '$CXXFLAGS_' ],
83         CXXFLAGS_         = BuildTypeOptions('CXXFLAGS'),
84         
85         CPPDEFINES        = [ '$expandLogOption', '$CPPDEFINES_' ],
86         expandLogOption   = expandLogOption,
87         CPPDEFINES_       = BuildTypeOptions('CPPDEFINES'),
88         
89         LINKFLAGS         = [ '-rdynamic', '$LINKFLAGS_' ],
90         LINKFLAGS_        = BuildTypeOptions('LINKFLAGS'),
91
92         LOGLEVELS         = [ '$LOGLEVELS_' ],
93         LOGLEVELS_        = BuildTypeOptions('LOGLEVELS'),
94         )
95
96     env.SetDefault( 
97         CXXFLAGS_final    = [],
98         CXXFLAGS_normal   = [],
99         CXXFLAGS_debug    = [],
100
101         CPPDEFINES_final  = [],
102         CPPDEFINES_normal = [],
103         CPPDEFINES_debug  = [],
104
105         LINKFLAGS_final   = [],
106         LINKFLAGS_normal  = [],
107         LINKFLAGS_debug   = [],
108
109         LOGLEVELS_final   = [],
110         LOGLEVELS_normal  = [],
111         LOGLEVELS_debug   = [],
112
113         PROJECTNAME       = "Unnamed project",
114         DOCLINKS          = [],
115         PROJECTEMAIL      = "nobody@nowhere.org",
116         COPYRIGHT         = "nobody",
117         REVISION          = "unknown",
118         )
119
120     # Interpret command line options
121     parseArguments(
122         env, 
123         BoolVariable('final', 'Build final (optimized) build', False),
124         BoolVariable('debug', 'Link in debug symbols', False),
125     )
126
127     # If we have a symbolic link (or directory) 'senf', we use it as our
128     # senf repository
129     for path in senf_path:
130         if not path.startswith('/') : sconspath = '#/%s' % path
131         else                        : sconspath = path
132         if os.path.exists(os.path.join(path,"senf/config.hh")):
133             if not env.GetOption('no_progress'):
134                 print "\nUsing SENF in '%s'\n" \
135                     % ('/..' in sconspath and os.path.abspath(path) or sconspath)
136             env.Append( LIBPATH = [ sconspath ],
137                         CPPPATH = [ sconspath ],
138                         BUNDLEDIR = sconspath,
139                         SENFDIR = sconspath,
140                         SENFSYSLAYOUT = False)
141             try:
142                 env.MergeFlags(file(os.path.join(path,"senf.conf")).read())
143             except IOError:
144                 if not env.GetOption('no_progress'):
145                     print "(SENF configuration file 'senf.conf' not found, assuming non-final SENF)"
146                 env.Append(CPPDEFINES = [ 'SENF_DEBUG' ])
147             break
148         elif os.path.exists(os.path.join(path,"include/senf/config.hh")):
149             if not env.GetOption('no_progress'):
150                 print "\nUsing system SENF in '%s/'\n" % sconspath
151             env.Append(BUNDLEDIR = os.path.join(sconspath,"lib/senf"),
152                        SENFDIR = sconspath,
153                        SENFSYSLAYOUT = True)
154             break
155     else:
156         if not env.GetOption('no_progress'):
157             print "\nSENF library not found .. trying build anyway !!\n"
158
159     env.Alias('all', '#')
160
161
162 def DefaultOptions(env):
163     env.Append(
164         CXXFLAGS         = [ '-Wall', '-Woverloaded-virtual' ],
165         CXXFLAGS_final   = [ '-O2' ],
166         CXXFLAGS_normal  = [ '-O0', '-g' ],
167         CXXFLAGS_debug   = [ '$CXXFLAGS_normal' ],
168
169         LINKFLAGS_normal = [ '-Wl,-S' ],
170         LINKFLAGS_debug  = [ '-g' ],
171     )
172     # ugly hack for ubuntu karmic 
173     # ToDo: auto-configure alike support
174     if os.path.exists('/usr/lib/libboost_regex-mt.so'):
175         env.Append( BOOST_VARIANT = '-mt' )
176
177
178 def Glob(env, exclude=[], subdirs=[]):
179     testSources = env.Glob("*.test.cc", strings=True)
180     sources = [ x 
181                 for x in env.Glob("*.cc", strings=True) 
182                 if x not in testSources and x not in exclude ]
183     for subdir in subdirs:
184         testSources += env.Glob(os.path.join(subdir,"*.test.cc"), strings=True)
185         sources += [ x 
186                      for x in env.Glob(os.path.join(subdir,"*.cc"), strings=True)
187                      if x not in testSources and x not in exclude ]
188     sources.sort()
189     testSources.sort()
190     return (sources, testSources)
191
192 tagfiles = None
193
194 def Doxygen(env, doxyheader=None, doxyfooter=None, doxycss=None, mydoxyfile=False, senfdoc_path=[],
195             **kw):
196     # Additional interesting keyword arguments or environment variables:
197     #    PROJECTNAME, DOCLINKS, PROJECTEMAIL, COPYRIGHT, REVISION
198
199     global senfutildir
200     global tagfiles
201     libdir=os.path.join(senfutildir, 'lib')
202     
203     if tagfiles is None:
204         senfdocdir = None
205         senfdoc_path.extend(('senfdoc', '$SENFDIR', '$SENFDIR/manual',
206                              '$SENFDIR/share/doc/senf', '$SENFDIR/share/doc/libsenf-doc/html'))
207         for path in senfdoc_path:
208             path = env.Dir(path).get_path()
209             if os.path.exists(os.path.join(path, "doc/doclib.tag")):
210                 senfdocdir = path
211                 break
212         tagfiles = []
213         if senfdocdir is None:
214             if not env.GetOption('no_progress'):
215                 print "(SENF documentation not found)"
216         else:
217             for dir, dirs, files in os.walk(senfdocdir):
218                 tagfiles.extend([ os.path.join(dir,f) for f in files if f.endswith('.tag') ])
219                 if dir.endswith('/doc') : 
220                     try: dirs.remove('html')
221                     except ValueError: pass
222                 for d in dirs: 
223                     if d.startswith('.') : dirs.remove(d)
224     
225     if env.GetOption('clean'):
226         env.Clean('doc', env.Dir('doc'))
227         if not mydoxyfile:
228             env.Clean('doc', "Doxyfile")
229
230     if not mydoxyfile:
231         # Create Doxyfile NOW
232         site_tools.Yaptu.yaptuAction("Doxyfile", 
233                                      os.path.join(libdir, "Doxyfile.yap"),
234                                      env)
235
236     envvalues = [ env.Value('$PROJECTNAME'),
237                   env.Value('$DOCLINKS'),
238                   env.Value('$PROJECTEMAIL'),
239                   env.Value('$COPYRIGHT'),
240                   env.Value('$REVISION') ]
241
242     # The other files are created using dependencies
243     if doxyheader: 
244         doxyheader = env.CopyToDir(env.Dir("doc"), doxyheader)
245     else:
246         doxyheader = env.Yaptu("doc/doxyheader.html", os.path.join(libdir, "doxyheader.yap"), **kw)
247         env.Depends(doxyheader, envvalues)
248     if doxyfooter:
249         doxyfooter = env.CopyToDir(env.Dir("doc"), doxyfooter)
250     else:
251         doxyfooter = env.Yaptu("doc/doxyfooter.html", os.path.join(libdir, "doxyfooter.yap"), **kw)
252         env.Depends(doxyfooter, envvalues)
253     if doxycss:
254         doxycss = env.CopyToDir(env.Dir("doc"), doxycss)
255     else:
256         doxycss    = env.CopyToDir(env.Dir("doc"), os.path.join(libdir, "doxy.css"))
257
258     doc = env.Doxygen("Doxyfile",
259                       DOXYOPTS   = [ '--html', '--tagfiles', '"$TAGFILES"' ],
260                       DOXYENV    = { 'TOPDIR'     : env.Dir('#').abspath,
261                                      'LIBDIR'     : libdir,
262                                      'REVISION'   : '$REVISION',
263                                      'tagfiles'   : '$TAGFILES',
264                                      'output_dir' : 'doc',
265                                      'html_dir'   : 'html',
266                                      'html'       : 'YES',
267                                      'DOXYGEN'    : '$DOXYGEN' },
268                       TAGFILES   = tagfiles, 
269                       DOCLIBDIR  = libdir,
270                       DOXYGENCOM = "$DOCLIBDIR/doxygen.sh $DOXYOPTS $SOURCE")
271
272     env.Depends(doc, [ doxyheader, doxyfooter, doxycss ])
273
274     return doc