Add tools to senfutil.py
[senf.git] / site_scons / senfutil.py
1 import os.path
2 from SCons.Script import *
3
4 # Fix for SCons 0.97 compatibility
5 try:
6     Variables
7 except NameError: 
8     Variables = Options
9     BoolVariable = BoolOption
10
11 def parseLogOption(value):
12     stream, area, level = ( x.strip() for x in value.strip().split('|') )
13     stream = ''.join('(%s)' % x for x in stream.split('::') )
14     if area : area = ''.join( '(%s)' % x for x in area.split('::') )
15     else    : area = '(_)'
16     return '((%s,%s,%s))' % (stream,area,level)
17
18 def expandLogOption(target, source, env, for_signature):
19     if env.get('LOGLEVELS'):
20         return [ 'SENF_LOG_CONF="' + ''.join( parseLogOption(x) for x in env.subst('$LOGLEVELS').split() )+'"']
21     else:
22         return []
23
24 class BuildTypeOptions:
25     def __init__(self, var):
26         self._var = var
27
28     def __call__(self, target, source, env, for_signature):
29         type = env['final'] and "final" or env['debug'] and "debug" or "normal"
30         return env[self._var + "_" + type]
31
32 def parseArguments(env, *defs):
33     vars = Variables(args=ARGUMENTS)
34     for d in defs : vars.Add(d)
35     vars.Update(env)
36     env.Help("""
37 Any construction environment variable may be set from the scons
38 command line (see SConstruct file and SCons documentation for a list
39 of variables) using
40
41    VARNAME=value    Assign new value  
42    VARNAME+=value   Append value at end
43
44 Special command line parameters:
45 """)
46     env.Help(vars.GenerateHelpText(env))
47     try                  : unknv = vars.UnknownVariables()
48     except AttributeError: unknv = vars.UnknownOptions()
49     for k,v in unknv.iteritems():
50         if k.endswith('+'):
51             env.Append(**{k[:-1]: v})
52         else:
53             env.Replace(**{k: v})
54
55
56 ###########################################################################
57 # This looks much more complicated than it is: We do three things here:
58 # a) switch between final or debug options
59 # b) parse the LOGLEVELS parameter into the correct SENF_LOG_CONF syntax
60 # c) check for a local SENF, set options accordingly and update that SENF if needed
61
62 def SetupForSENF(env, senf_paths = []):
63     senfutildir = os.path.dirname(__file__)
64     senf_paths.extend(('senf', '../senf', os.path.dirname(senfutildir), '/usr/local', '/usr'))
65     tooldir = os.path.join(senfutildir, 'site_tools')
66
67     env.Tool('Boost',       [ tooldir ])
68     env.Tool('PhonyTarget', [ tooldir ])
69
70     env.Append(
71         LIBS              = [ 'senf', 'rt', '$BOOSTREGEXLIB',
72                               '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB',
73                               '$BOOSTFSLIB' ],
74         BOOSTREGEXLIB     = 'boost_regex',
75         BOOSTIOSTREAMSLIB = 'boost_iostreams',
76         BOOSTSIGNALSLIB   = 'boost_signals',
77         BOOSTFSLIB        = 'boost_filesystem',
78         
79         CXXFLAGS          = [ '-Wno-long-long', '$CXXFLAGS_' ],
80         CXXFLAGS_         = BuildTypeOptions('CXXFLAGS'),
81         
82         CPPDEFINES        = [ '$expandLogOption', '$CPPDEFINES_' ],
83         expandLogOption   = expandLogOption,
84         CPPDEFINES_       = BuildTypeOptions('CPPDEFINES'),
85         
86         LINKFLAGS         = [ '-rdynamic', '$LINKFLAGS_' ],
87         LINKFLAGS_        = BuildTypeOptions('LINKFLAGS'),
88
89         LOGLEVELS         = [ '$LOGLEVELS_' ],
90         LOGLEVELS_        = BuildTypeOptions('LOGLEVELS'),
91         )
92
93     env.SetDefault( 
94         CXXFLAGS_final    = [],
95         CXXFLAGS_normal   = [],
96         CXXFLAGS_debug    = [],
97
98         CPPDEFINES_final  = [],
99         CPPDEFINES_normal = [],
100         CPPDEFINES_debug  = [],
101
102         LINKFLAGS_final   = [],
103         LINKFLAGS_normal  = [],
104         LINKFLAGS_debug   = [],
105
106         LOGLEVELS_final   = [],
107         LOGLEVELS_normal  = [],
108         LOGLEVELS_debug   = [],
109         )
110
111     # Interpret command line options
112     parseArguments(
113         env, 
114         BoolVariable('final', 'Build final (optimized) build', False),
115         BoolVariable('debug', 'Link in debug symbols', False),
116     )
117
118     # If we have a symbolic link (or directory) 'senf', we use it as our
119     # senf repository
120     for path in senf_paths:
121         if not path.startswith('/') : sconspath = '#/%s' % path
122         else                        : sconspath = path
123         if os.path.exists(os.path.join(path,"senf/config.hh")):
124             print "\nUsing SENF in '%s'\n" \
125                 % ('/..' in sconspath and os.path.abspath(path) or sconspath)
126             env.Append( LIBPATH = [ sconspath ],
127                         CPPPATH = [ sconspath ],
128                         BUNDLEDIR = sconspath )
129             try:
130                 env.MergeFlags(file(os.path.join(path,"senf.conf")).read())
131             except IOError:
132                 print "(SENF configuration file 'senf.conf' not found, assuming non-final SENF)"
133                 env.Append(CPPDEFINES = [ 'SENF_DEBUG' ])
134             break
135         elif os.path.exists(os.path.join(path,"include/senf/config.hh")):
136             print "\nUsing system SENF in '%s/'\n" % sconspath
137             env.Append(BUNDLEDIR = os.path.join(sconspath,"lib/senf"))
138             break
139     else:
140         print "\nSENF library not found .. trying build anyway !!\n"
141
142
143 def DefaultOptions(env):
144     env.Append(
145         CXXFLAGS         = [ '-Wall', '-Woverloaded-virtual' ],
146         CXXFLAGS_final   = [ '-O2' ],
147         CXXFLAGS_normal  = [ '-O0', '-g' ],
148         CXXFLAGS_debug   = [ '$CXXFLAGS_normal' ],
149
150         LINKFLAGS_normal = [ '-Wl,-S' ],
151         LINKFLAGS_debug  = [ '-g' ],
152     )
153
154 def Glob(env, exclude=[], subdirs=[]):
155     testSources = glob.glob("*.test.cc")
156     sources = [ x for x in glob.glob("*.cc") if x not in testSources and x not in exclude ]
157     for subdir in subdirs:
158         testSources += glob.glob(os.path.join(subdir,"*.test.cc"))
159         sources += [ x for x in glob.glob(os.path.join(subdir,"*.cc"))
160                      if x not in testSources and x not in exclude ]
161     return (sources, testSources)