~ubuntu-branches/ubuntu/utopic/tdb/utopic-proposed

« back to all changes in this revision

Viewing changes to buildtools/wafadmin/Configure.py

  • Committer: Package Import Robot
  • Author(s): Andrew Bartlett
  • Date: 2013-02-12 20:43:55 UTC
  • mfrom: (1.4.6)
  • mto: (1.4.7) (3.3.7 experimental)
  • mto: This revision was merged to the branch mainline in revision 28.
  • Revision ID: package-import@ubuntu.com-20130212204355-6q6jvxshtoie7ex5
ImportĀ upstreamĀ versionĀ 1.2.11

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
# encoding: utf-8
 
3
# Thomas Nagy, 2005-2008 (ita)
 
4
 
 
5
"""
 
6
Configuration system
 
7
 
 
8
A configuration instance is created when "waf configure" is called, it is used to:
 
9
* create data dictionaries (Environment instances)
 
10
* store the list of modules to import
 
11
 
 
12
The old model (copied from Scons) was to store logic (mapping file extensions to functions)
 
13
along with the data. In Waf a way was found to separate that logic by adding an indirection
 
14
layer (storing the names in the Environment instances)
 
15
 
 
16
In the new model, the logic is more object-oriented, and the user scripts provide the
 
17
logic. The data files (Environments) must contain configuration data only (flags, ..).
 
18
 
 
19
Note: the c/c++ related code is in the module config_c
 
20
"""
 
21
 
 
22
import os, shlex, sys, time
 
23
try: import cPickle
 
24
except ImportError: import pickle as cPickle
 
25
import Environment, Utils, Options, Logs
 
26
from Logs import warn
 
27
from Constants import *
 
28
 
 
29
try:
 
30
        from urllib import request
 
31
except:
 
32
        from urllib import urlopen
 
33
else:
 
34
        urlopen = request.urlopen
 
35
 
 
36
conf_template = '''# project %(app)s configured on %(now)s by
 
37
# waf %(wafver)s (abi %(abi)s, python %(pyver)x on %(systype)s)
 
38
# using %(args)s
 
39
#
 
40
'''
 
41
 
 
42
class ConfigurationError(Utils.WscriptError):
 
43
        pass
 
44
 
 
45
autoconfig = False
 
46
"reconfigure the project automatically"
 
47
 
 
48
def find_file(filename, path_list):
 
49
        """find a file in a list of paths
 
50
        @param filename: name of the file to search for
 
51
        @param path_list: list of directories to search
 
52
        @return: the first occurrence filename or '' if filename could not be found
 
53
"""
 
54
        for directory in Utils.to_list(path_list):
 
55
                if os.path.exists(os.path.join(directory, filename)):
 
56
                        return directory
 
57
        return ''
 
58
 
 
59
def find_program_impl(env, filename, path_list=[], var=None, environ=None):
 
60
        """find a program in folders path_lst, and sets env[var]
 
61
        @param env: environment
 
62
        @param filename: name of the program to search for
 
63
        @param path_list: list of directories to search for filename
 
64
        @param var: environment value to be checked for in env or os.environ
 
65
        @return: either the value that is referenced with [var] in env or os.environ
 
66
         or the first occurrence filename or '' if filename could not be found
 
67
"""
 
68
 
 
69
        if not environ:
 
70
                environ = os.environ
 
71
 
 
72
        try: path_list = path_list.split()
 
73
        except AttributeError: pass
 
74
 
 
75
        if var:
 
76
                if env[var]: return env[var]
 
77
                if var in environ: env[var] = environ[var]
 
78
 
 
79
        if not path_list: path_list = environ.get('PATH', '').split(os.pathsep)
 
80
 
 
81
        ext = (Options.platform == 'win32') and '.exe,.com,.bat,.cmd' or ''
 
82
        for y in [filename+x for x in ext.split(',')]:
 
83
                for directory in path_list:
 
84
                        x = os.path.join(directory, y)
 
85
                        if os.path.isfile(x):
 
86
                                if var: env[var] = x
 
87
                                return x
 
88
        return ''
 
89
 
 
90
class ConfigurationContext(Utils.Context):
 
91
        tests = {}
 
92
        error_handlers = []
 
93
        def __init__(self, env=None, blddir='', srcdir=''):
 
94
                self.env = None
 
95
                self.envname = ''
 
96
 
 
97
                self.environ = dict(os.environ)
 
98
 
 
99
                self.line_just = 40
 
100
 
 
101
                self.blddir = blddir
 
102
                self.srcdir = srcdir
 
103
                self.all_envs = {}
 
104
 
 
105
                # curdir: necessary for recursion
 
106
                self.cwd = self.curdir = os.getcwd()
 
107
 
 
108
                self.tools = [] # tools loaded in the configuration, and that will be loaded when building
 
109
 
 
110
                self.setenv(DEFAULT)
 
111
 
 
112
                self.lastprog = ''
 
113
 
 
114
                self.hash = 0
 
115
                self.files = []
 
116
 
 
117
                self.tool_cache = []
 
118
 
 
119
                if self.blddir:
 
120
                        self.post_init()
 
121
 
 
122
        def post_init(self):
 
123
 
 
124
                self.cachedir = os.path.join(self.blddir, CACHE_DIR)
 
125
 
 
126
                path = os.path.join(self.blddir, WAF_CONFIG_LOG)
 
127
                try: os.unlink(path)
 
128
                except (OSError, IOError): pass
 
129
 
 
130
                try:
 
131
                        self.log = open(path, 'w')
 
132
                except (OSError, IOError):
 
133
                        self.fatal('could not open %r for writing' % path)
 
134
 
 
135
                app = Utils.g_module.APPNAME
 
136
                if app:
 
137
                        ver = getattr(Utils.g_module, 'VERSION', '')
 
138
                        if ver:
 
139
                                app = "%s (%s)" % (app, ver)
 
140
 
 
141
                now = time.ctime()
 
142
                pyver = sys.hexversion
 
143
                systype = sys.platform
 
144
                args = " ".join(sys.argv)
 
145
                wafver = WAFVERSION
 
146
                abi = ABI
 
147
                self.log.write(conf_template % vars())
 
148
 
 
149
        def __del__(self):
 
150
                """cleanup function: close config.log"""
 
151
 
 
152
                # may be ran by the gc, not always after initialization
 
153
                if hasattr(self, 'log') and self.log:
 
154
                        self.log.close()
 
155
 
 
156
        def fatal(self, msg):
 
157
                raise ConfigurationError(msg)
 
158
 
 
159
        def check_tool(self, input, tooldir=None, funs=None):
 
160
                "load a waf tool"
 
161
 
 
162
                tools = Utils.to_list(input)
 
163
                if tooldir: tooldir = Utils.to_list(tooldir)
 
164
                for tool in tools:
 
165
                        tool = tool.replace('++', 'xx')
 
166
                        if tool == 'java': tool = 'javaw'
 
167
                        if tool.lower() == 'unittest': tool = 'unittestw'
 
168
                        # avoid loading the same tool more than once with the same functions
 
169
                        # used by composite projects
 
170
 
 
171
                        mag = (tool, id(self.env), funs)
 
172
                        if mag in self.tool_cache:
 
173
                                continue
 
174
                        self.tool_cache.append(mag)
 
175
 
 
176
                        module = None
 
177
                        try:
 
178
                                module = Utils.load_tool(tool, tooldir)
 
179
                        except Exception, e:
 
180
                                ex = e
 
181
                                if Options.options.download:
 
182
                                        _3rdparty = os.path.normpath(Options.tooldir[0] + os.sep + '..' + os.sep + '3rdparty')
 
183
 
 
184
                                        # try to download the tool from the repository then
 
185
                                        # the default is set to false
 
186
                                        for x in Utils.to_list(Options.remote_repo):
 
187
                                                for sub in ['branches/waf-%s/wafadmin/3rdparty' % WAFVERSION, 'trunk/wafadmin/3rdparty']:
 
188
                                                        url = '/'.join((x, sub, tool + '.py'))
 
189
                                                        try:
 
190
                                                                web = urlopen(url)
 
191
                                                                if web.getcode() != 200:
 
192
                                                                        continue
 
193
                                                        except Exception, e:
 
194
                                                                # on python3 urlopen throws an exception
 
195
                                                                continue
 
196
                                                        else:
 
197
                                                                loc = None
 
198
                                                                try:
 
199
                                                                        loc = open(_3rdparty + os.sep + tool + '.py', 'wb')
 
200
                                                                        loc.write(web.read())
 
201
                                                                        web.close()
 
202
                                                                finally:
 
203
                                                                        if loc:
 
204
                                                                                loc.close()
 
205
                                                                Logs.warn('downloaded %s from %s' % (tool, url))
 
206
                                                                try:
 
207
                                                                        module = Utils.load_tool(tool, tooldir)
 
208
                                                                except:
 
209
                                                                        Logs.warn('module %s from %s is unusable' % (tool, url))
 
210
                                                                        try:
 
211
                                                                                os.unlink(_3rdparty + os.sep + tool + '.py')
 
212
                                                                        except:
 
213
                                                                                pass
 
214
                                                                        continue
 
215
                                                else:
 
216
                                                        break
 
217
 
 
218
                                        if not module:
 
219
                                                Logs.error('Could not load the tool %r or download a suitable replacement from the repository (sys.path %r)\n%s' % (tool, sys.path, e))
 
220
                                                raise ex
 
221
                                else:
 
222
                                        Logs.error('Could not load the tool %r in %r (try the --download option?):\n%s' % (tool, sys.path, e))
 
223
                                        raise ex
 
224
 
 
225
                        if funs is not None:
 
226
                                self.eval_rules(funs)
 
227
                        else:
 
228
                                func = getattr(module, 'detect', None)
 
229
                                if func:
 
230
                                        if type(func) is type(find_file): func(self)
 
231
                                        else: self.eval_rules(func)
 
232
 
 
233
                        self.tools.append({'tool':tool, 'tooldir':tooldir, 'funs':funs})
 
234
 
 
235
        def sub_config(self, k):
 
236
                "executes the configure function of a wscript module"
 
237
                self.recurse(k, name='configure')
 
238
 
 
239
        def pre_recurse(self, name_or_mod, path, nexdir):
 
240
                return {'conf': self, 'ctx': self}
 
241
 
 
242
        def post_recurse(self, name_or_mod, path, nexdir):
 
243
                if not autoconfig:
 
244
                        return
 
245
                self.hash = hash((self.hash, getattr(name_or_mod, 'waf_hash_val', name_or_mod)))
 
246
                self.files.append(path)
 
247
 
 
248
        def store(self, file=''):
 
249
                "save the config results into the cache file"
 
250
                if not os.path.isdir(self.cachedir):
 
251
                        os.makedirs(self.cachedir)
 
252
 
 
253
                if not file:
 
254
                        file = open(os.path.join(self.cachedir, 'build.config.py'), 'w')
 
255
                file.write('version = 0x%x\n' % HEXVERSION)
 
256
                file.write('tools = %r\n' % self.tools)
 
257
                file.close()
 
258
 
 
259
                if not self.all_envs:
 
260
                        self.fatal('nothing to store in the configuration context!')
 
261
                for key in self.all_envs:
 
262
                        tmpenv = self.all_envs[key]
 
263
                        tmpenv.store(os.path.join(self.cachedir, key + CACHE_SUFFIX))
 
264
 
 
265
        def set_env_name(self, name, env):
 
266
                "add a new environment called name"
 
267
                self.all_envs[name] = env
 
268
                return env
 
269
 
 
270
        def retrieve(self, name, fromenv=None):
 
271
                "retrieve an environment called name"
 
272
                try:
 
273
                        env = self.all_envs[name]
 
274
                except KeyError:
 
275
                        env = Environment.Environment()
 
276
                        env['PREFIX'] = os.path.abspath(os.path.expanduser(Options.options.prefix))
 
277
                        self.all_envs[name] = env
 
278
                else:
 
279
                        if fromenv: warn("The environment %s may have been configured already" % name)
 
280
                return env
 
281
 
 
282
        def setenv(self, name):
 
283
                "enable the environment called name"
 
284
                self.env = self.retrieve(name)
 
285
                self.envname = name
 
286
 
 
287
        def add_os_flags(self, var, dest=None):
 
288
                # do not use 'get' to make certain the variable is not defined
 
289
                try: self.env.append_value(dest or var, Utils.to_list(self.environ[var]))
 
290
                except KeyError: pass
 
291
 
 
292
        def check_message_1(self, sr):
 
293
                self.line_just = max(self.line_just, len(sr))
 
294
                for x in ('\n', self.line_just * '-', '\n', sr, '\n'):
 
295
                        self.log.write(x)
 
296
                Utils.pprint('NORMAL', "%s :" % sr.ljust(self.line_just), sep='')
 
297
 
 
298
        def check_message_2(self, sr, color='GREEN'):
 
299
                self.log.write(sr)
 
300
                self.log.write('\n')
 
301
                Utils.pprint(color, sr)
 
302
 
 
303
        def check_message(self, th, msg, state, option=''):
 
304
                sr = 'Checking for %s %s' % (th, msg)
 
305
                self.check_message_1(sr)
 
306
                p = self.check_message_2
 
307
                if state: p('ok ' + str(option))
 
308
                else: p('not found', 'YELLOW')
 
309
 
 
310
        # FIXME remove in waf 1.6
 
311
        # the parameter 'option' is not used (kept for compatibility)
 
312
        def check_message_custom(self, th, msg, custom, option='', color='PINK'):
 
313
                sr = 'Checking for %s %s' % (th, msg)
 
314
                self.check_message_1(sr)
 
315
                self.check_message_2(custom, color)
 
316
 
 
317
        def msg(self, msg, result, color=None):
 
318
                """Prints a configuration message 'Checking for xxx: ok'"""
 
319
                self.start_msg('Checking for ' + msg)
 
320
 
 
321
                if not isinstance(color, str):
 
322
                        color = result and 'GREEN' or 'YELLOW'
 
323
 
 
324
                self.end_msg(result, color)
 
325
 
 
326
        def start_msg(self, msg):
 
327
                try:
 
328
                        if self.in_msg:
 
329
                                return
 
330
                except:
 
331
                        self.in_msg = 0
 
332
                self.in_msg += 1
 
333
 
 
334
                self.line_just = max(self.line_just, len(msg))
 
335
                for x in ('\n', self.line_just * '-', '\n', msg, '\n'):
 
336
                        self.log.write(x)
 
337
                Utils.pprint('NORMAL', "%s :" % msg.ljust(self.line_just), sep='')
 
338
 
 
339
        def end_msg(self, result, color):
 
340
                self.in_msg -= 1
 
341
                if self.in_msg:
 
342
                        return
 
343
 
 
344
                if not color:
 
345
                        color = 'GREEN'
 
346
                if result == True:
 
347
                        msg = 'ok'
 
348
                elif result == False:
 
349
                        msg = 'not found'
 
350
                        color = 'YELLOW'
 
351
                else:
 
352
                        msg = str(result)
 
353
 
 
354
                self.log.write(msg)
 
355
                self.log.write('\n')
 
356
                Utils.pprint(color, msg)
 
357
 
 
358
        def find_program(self, filename, path_list=[], var=None, mandatory=False):
 
359
                "wrapper that adds a configuration message"
 
360
 
 
361
                ret = None
 
362
                if var:
 
363
                        if self.env[var]:
 
364
                                ret = self.env[var]
 
365
                        elif var in os.environ:
 
366
                                ret = os.environ[var]
 
367
 
 
368
                if not isinstance(filename, list): filename = [filename]
 
369
                if not ret:
 
370
                        for x in filename:
 
371
                                ret = find_program_impl(self.env, x, path_list, var, environ=self.environ)
 
372
                                if ret: break
 
373
 
 
374
                self.check_message_1('Checking for program %s' % ' or '.join(filename))
 
375
                self.log.write('  find program=%r paths=%r var=%r\n  -> %r\n' % (filename, path_list, var, ret))
 
376
                if ret:
 
377
                        Utils.pprint('GREEN', str(ret))
 
378
                else:
 
379
                        Utils.pprint('YELLOW', 'not found')
 
380
                        if mandatory:
 
381
                                self.fatal('The program %r is required' % filename)
 
382
 
 
383
                if var:
 
384
                        self.env[var] = ret
 
385
                return ret
 
386
 
 
387
        def cmd_to_list(self, cmd):
 
388
                "commands may be written in pseudo shell like 'ccache g++'"
 
389
                if isinstance(cmd, str) and cmd.find(' '):
 
390
                        try:
 
391
                                os.stat(cmd)
 
392
                        except OSError:
 
393
                                return shlex.split(cmd)
 
394
                        else:
 
395
                                return [cmd]
 
396
                return cmd
 
397
 
 
398
        def __getattr__(self, name):
 
399
                r = self.__class__.__dict__.get(name, None)
 
400
                if r: return r
 
401
                if name and name.startswith('require_'):
 
402
 
 
403
                        for k in ['check_', 'find_']:
 
404
                                n = name.replace('require_', k)
 
405
                                ret = self.__class__.__dict__.get(n, None)
 
406
                                if ret:
 
407
                                        def run(*k, **kw):
 
408
                                                r = ret(self, *k, **kw)
 
409
                                                if not r:
 
410
                                                        self.fatal('requirement failure')
 
411
                                                return r
 
412
                                        return run
 
413
                self.fatal('No such method %r' % name)
 
414
 
 
415
        def eval_rules(self, rules):
 
416
                self.rules = Utils.to_list(rules)
 
417
                for x in self.rules:
 
418
                        f = getattr(self, x)
 
419
                        if not f: self.fatal("No such method '%s'." % x)
 
420
                        try:
 
421
                                f()
 
422
                        except Exception, e:
 
423
                                ret = self.err_handler(x, e)
 
424
                                if ret == BREAK:
 
425
                                        break
 
426
                                elif ret == CONTINUE:
 
427
                                        continue
 
428
                                else:
 
429
                                        self.fatal(e)
 
430
 
 
431
        def err_handler(self, fun, error):
 
432
                pass
 
433
 
 
434
def conf(f):
 
435
        "decorator: attach new configuration functions"
 
436
        setattr(ConfigurationContext, f.__name__, f)
 
437
        return f
 
438
 
 
439
def conftest(f):
 
440
        "decorator: attach new configuration tests (registered as strings)"
 
441
        ConfigurationContext.tests[f.__name__] = f
 
442
        return conf(f)
 
443
 
 
444