minor fixes for clang++
[senf.git] / site_scons / site_tools / CustomTests.py
1 import SCons.Environment, SCons.Util, SCons.Script, SCons.Conftest
2 import re, os.path
3
4 # Fix for SCons 0.97 compatibility
5 import SCons.SConf
6 try: SCons.SConf.SConfBase.Define
7 except AttributeError:
8     import string
9     def Define(self, name, value = None, comment = None):
10         lines = []
11         if comment:
12             comment_str = "/* %s */" % comment
13             lines.append(comment_str)
14         if value is not None:
15             define_str = "#define %s %s" % (name, value)
16         else:
17             define_str = "#define %s" % name
18         lines.append(define_str)
19         lines.append('')
20         self.config_h_text = self.config_h_text + string.join(lines, '\n')
21     SCons.SConf.SConfBase.Define = Define
22
23 class ConfTest(object):
24     """Configuration test decorator.
25
26 This class is used as a decorator to define SCons Configure
27 tests. There are three ways to use this facility:
28
29
30 DIRECT WITH EXTERNAL REGISTRY
31
32 In this scenario, you pass the test registry, a map, as argument to
33 the decorator. This usage is primarily interesting for tool writers:
34
35     from CustomTests import ConfTest
36
37     MY_TESTS = {}
38
39     @ConfTest(MY_TESTS)
40     def CheckMyFoo(context):
41         pass
42
43     def generate(env):
44         env.Append(CUSTOM_TESTS = MY_TESTS)
45
46 This will place CheckMyFoo into the MY_TESTS dictionary which you can
47 later add to the CUSTOM_TESTS environment variable.
48
49
50 USING A REGISTRY ALIAS
51
52 In this scenario, you define a local alias for the decorator which
53 serves as the registry. This usage is again primarily interesting for
54 tool and extension writers:
55
56     import CustomTests
57
58     MyConfTest = CustomTests.ConfTest()
59
60     @MyConfTest
61     def CheckMyFoo(context):
62         pass
63
64     def generate(env):
65         env.Append(CUSTOM_TESTS = MyConfTest.tests)
66
67 Logically this is like the previous method.
68
69
70 USING THE ENVIRONMENT MEMBER
71
72 This usage is interesting for SConstruct and SConscript writers:
73
74     env = Environment()
75     env.Tool('CustomTests')
76
77     @env.ConfTest()
78     def CheckMyFoo(context):
79         pass
80
81     conf = env.Configure()
82     conf.CheckMyFoo()
83     env = conf.Finish()
84
85 The new configuration test is automatically added to
86 env['CUSTOM_TESTS'] and is thus automatically available to all
87 configuration contexts created from the environment.
88 """
89
90     def __init__(self, registry=None):
91         if registry is None:
92             self.tests = {}
93         elif isinstance(registry, SCons.Environment.SubstitutionEnvironment):
94             self.tests =registry['CUSTOM_TESTS']
95         else:
96             self.tests = registry
97
98     def __call__(self, func):
99         self.tests[func.__name__] = func
100         return func
101
102 def Configure(self, *args, **kw):
103     try: kw['custom_tests'].update(self['CUSTOM_TESTS'])
104     except KeyError: kw['custom_tests'] = dict(self['CUSTOM_TESTS'])
105     return self._CustomTests_orig_Configure(*args, **kw)
106
107 def Fail(context, message, condition=True):
108     if condition:
109         SCons.Util.display("scons: *** %s" % message)
110         SCons.Script.Exit(1)
111
112 DefaultTest = ConfTest()
113
114 @DefaultTest
115 def CheckSymbolWithExpression(context, symbol, expression, header="", language="C"):
116     lang, suffix, msg = SCons.Conftest._lang2suffix(language)
117     if msg:
118         context.Message("Cannot check for %s: " % symbol)
119         context.Result(msg)
120         return False
121
122     text = ("#include <assert.h>\n"
123             "%s\n"
124             "int main() {\n"
125             "%s;\n"
126             "return 0;\n"
127             "}\n") % (header, expression)
128
129     context.Message("Checking for %s... " % symbol)
130     ret = context.TryLink(text, suffix)
131     context.Result(ret)
132     if ret:
133         key = symbol.upper()
134         key = re.sub('[^A-Z0-9_]', '_', key)
135         context.sconf.Define("HAVE_%s" % key, 1,
136                              "Define to 1 if you have `%s'" % symbol)
137
138     return ret
139
140 @DefaultTest
141 def CheckByteorder(context):
142     context.Message("Checking byteorder... ")
143     if context.env.has_key("BYTEORDER"):
144         ret = context.env["BYTEORDER"]
145     else:
146         ret = context.TryRun('#include <stdio.h>\n'
147                              'union byteorder_test { int i; char b; };\n'
148                              'int main() {\n'
149                              '    union byteorder_test t; t.i=1;\n'
150                              '    printf(t.b ? "little\\n" : "big\\n");\n'
151                              '    return 0;\n'
152                              '}\n',
153                              ".c")[-1].strip()
154     if not ret:
155         context.Result("failed")
156         return False
157     else:
158         context.Result(ret+"-endian")
159         context.sconf.Define("BYTEORDER_%s_ENDIAN" % ret.upper(), 1,
160                              "Define BYTEORDER_LITTLE_ENDIAN or BYTEORDER_BIG_ENDIAN")
161         return ret
162
163 @DefaultTest
164 def FindCHeader(context, name, dirs):
165     defn = name.upper()
166     defn = re.sub('[^A-Z0-9_]', '_', defn)
167     defn += "_PATH"
168
169     context.Message("Checking for %s... " % name)
170     for dir in dirs:
171         path = os.path.join(dir, name);
172         ret = context.TryCompile("#include <%s>" % path, ".c");
173         if ret:
174             context.Result(path)
175             context.sconf.Define(defn, "<%s>" % path,
176                                  "Define %s as <path/to/%s>" % (defn, name))
177             return ret
178     return False
179
180 def generate(env):
181     env.Append( CUSTOM_TESTS = DefaultTest.tests )
182     env._CustomTests_orig_Configure = env.Configure
183     env.AddMethod(Configure)
184     env.AddMethod(ConfTest)
185     env.AddMethod(Fail)
186
187 def exists(env):
188     return True