~ubuntu-branches/ubuntu/lucid/blender/lucid

« back to all changes in this revision

Viewing changes to scons/scons-local-1.1.0/SCons/Builder.py

  • Committer: Bazaar Package Importer
  • Author(s): Chris Coulson
  • Date: 2009-08-06 22:32:19 UTC
  • mfrom: (1.2.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20090806223219-8z4eej1u8levu4pz
Tags: 2.49a+dfsg-0ubuntu1
* Merge from debian unstable, remaining changes:
  - debian/control: Build-depend on python-2.6 rather than python-2.5.
  - debian/misc/*.desktop: Add Spanish translation to .desktop 
    files.
  - debian/pyversions: 2.6.
  - debian/rules: Clean *.o of source/blender/python/api2_2x/
* New upstream release (LP: #382153).
* Refreshed patches:
  - 01_sanitize_sys.patch
  - 02_tmp_in_HOME
  - 10_use_systemwide_ftgl
  - 70_portability_platform_detection
* Removed patches merged upstream:
  - 30_fix_python_syntax_warning
  - 90_ubuntu_ffmpeg_52_changes

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""SCons.Builder
 
2
 
 
3
Builder object subsystem.
 
4
 
 
5
A Builder object is a callable that encapsulates information about how
 
6
to execute actions to create a target Node (file) from source Nodes
 
7
(files), and how to create those dependencies for tracking.
 
8
 
 
9
The main entry point here is the Builder() factory method.  This provides
 
10
a procedural interface that creates the right underlying Builder object
 
11
based on the keyword arguments supplied and the types of the arguments.
 
12
 
 
13
The goal is for this external interface to be simple enough that the
 
14
vast majority of users can create new Builders as necessary to support
 
15
building new types of files in their configurations, without having to
 
16
dive any deeper into this subsystem.
 
17
 
 
18
The base class here is BuilderBase.  This is a concrete base class which
 
19
does, in fact, represent the Builder objects that we (or users) create.
 
20
 
 
21
There is also a proxy that looks like a Builder:
 
22
 
 
23
    CompositeBuilder
 
24
 
 
25
        This proxies for a Builder with an action that is actually a
 
26
        dictionary that knows how to map file suffixes to a specific
 
27
        action.  This is so that we can invoke different actions
 
28
        (compilers, compile options) for different flavors of source
 
29
        files.
 
30
 
 
31
Builders and their proxies have the following public interface methods
 
32
used by other modules:
 
33
 
 
34
    __call__()
 
35
        THE public interface.  Calling a Builder object (with the
 
36
        use of internal helper methods) sets up the target and source
 
37
        dependencies, appropriate mapping to a specific action, and the
 
38
        environment manipulation necessary for overridden construction
 
39
        variable.  This also takes care of warning about possible mistakes
 
40
        in keyword arguments.
 
41
 
 
42
    add_emitter()
 
43
        Adds an emitter for a specific file suffix, used by some Tool
 
44
        modules to specify that (for example) a yacc invocation on a .y
 
45
        can create a .h *and* a .c file.
 
46
 
 
47
    add_action()
 
48
        Adds an action for a specific file suffix, heavily used by
 
49
        Tool modules to add their specific action(s) for turning
 
50
        a source file into an object file to the global static
 
51
        and shared object file Builders.
 
52
 
 
53
There are the following methods for internal use within this module:
 
54
 
 
55
    _execute()
 
56
        The internal method that handles the heavily lifting when a
 
57
        Builder is called.  This is used so that the __call__() methods
 
58
        can set up warning about possible mistakes in keyword-argument
 
59
        overrides, and *then* execute all of the steps necessary so that
 
60
        the warnings only occur once.
 
61
 
 
62
    get_name()
 
63
        Returns the Builder's name within a specific Environment,
 
64
        primarily used to try to return helpful information in error
 
65
        messages.
 
66
 
 
67
    adjust_suffix()
 
68
    get_prefix()
 
69
    get_suffix()
 
70
    get_src_suffix()
 
71
    set_src_suffix()
 
72
        Miscellaneous stuff for handling the prefix and suffix
 
73
        manipulation we use in turning source file names into target
 
74
        file names.
 
75
 
 
76
"""
 
77
 
 
78
#
 
79
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation
 
80
#
 
81
# Permission is hereby granted, free of charge, to any person obtaining
 
82
# a copy of this software and associated documentation files (the
 
83
# "Software"), to deal in the Software without restriction, including
 
84
# without limitation the rights to use, copy, modify, merge, publish,
 
85
# distribute, sublicense, and/or sell copies of the Software, and to
 
86
# permit persons to whom the Software is furnished to do so, subject to
 
87
# the following conditions:
 
88
#
 
89
# The above copyright notice and this permission notice shall be included
 
90
# in all copies or substantial portions of the Software.
 
91
#
 
92
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
 
93
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 
94
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
95
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 
96
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 
97
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 
98
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
99
#
 
100
 
 
101
__revision__ = "src/engine/SCons/Builder.py 3603 2008/10/10 05:46:45 scons"
 
102
 
 
103
import UserDict
 
104
import UserList
 
105
 
 
106
import SCons.Action
 
107
from SCons.Debug import logInstanceCreation
 
108
from SCons.Errors import InternalError, UserError
 
109
import SCons.Executor
 
110
import SCons.Memoize
 
111
import SCons.Node
 
112
import SCons.Node.FS
 
113
import SCons.Util
 
114
import SCons.Warnings
 
115
 
 
116
class _Null:
 
117
    pass
 
118
 
 
119
_null = _Null
 
120
 
 
121
class DictCmdGenerator(SCons.Util.Selector):
 
122
    """This is a callable class that can be used as a
 
123
    command generator function.  It holds on to a dictionary
 
124
    mapping file suffixes to Actions.  It uses that dictionary
 
125
    to return the proper action based on the file suffix of
 
126
    the source file."""
 
127
 
 
128
    def __init__(self, dict=None, source_ext_match=1):
 
129
        SCons.Util.Selector.__init__(self, dict)
 
130
        self.source_ext_match = source_ext_match
 
131
 
 
132
    def src_suffixes(self):
 
133
        return self.keys()
 
134
 
 
135
    def add_action(self, suffix, action):
 
136
        """Add a suffix-action pair to the mapping.
 
137
        """
 
138
        self[suffix] = action
 
139
 
 
140
    def __call__(self, target, source, env, for_signature):
 
141
        if not source:
 
142
            return []
 
143
 
 
144
        if self.source_ext_match:
 
145
            ext = None
 
146
            for src in map(str, source):
 
147
                my_ext = SCons.Util.splitext(src)[1]
 
148
                if ext and my_ext != ext:
 
149
                    raise UserError("While building `%s' from `%s': Cannot build multiple sources with different extensions: %s, %s" % (repr(map(str, target)), src, ext, my_ext))
 
150
                ext = my_ext
 
151
        else:
 
152
            ext = SCons.Util.splitext(str(source[0]))[1]
 
153
 
 
154
        if not ext:
 
155
            raise UserError("While building `%s': Cannot deduce file extension from source files: %s" % (repr(map(str, target)), repr(map(str, source))))
 
156
 
 
157
        try:
 
158
            ret = SCons.Util.Selector.__call__(self, env, source)
 
159
        except KeyError, e:
 
160
            raise UserError("Ambiguous suffixes after environment substitution: %s == %s == %s" % (e[0], e[1], e[2]))
 
161
        if ret is None:
 
162
            raise UserError("While building `%s' from `%s': Don't know how to build from a source file with suffix `%s'.  Expected a suffix in this list: %s." % \
 
163
                            (repr(map(str, target)), repr(map(str, source)), ext, repr(self.keys())))
 
164
        return ret
 
165
 
 
166
class CallableSelector(SCons.Util.Selector):
 
167
    """A callable dictionary that will, in turn, call the value it
 
168
    finds if it can."""
 
169
    def __call__(self, env, source):
 
170
        value = SCons.Util.Selector.__call__(self, env, source)
 
171
        if callable(value):
 
172
            value = value(env, source)
 
173
        return value
 
174
 
 
175
class DictEmitter(SCons.Util.Selector):
 
176
    """A callable dictionary that maps file suffixes to emitters.
 
177
    When called, it finds the right emitter in its dictionary for the
 
178
    suffix of the first source file, and calls that emitter to get the
 
179
    right lists of targets and sources to return.  If there's no emitter
 
180
    for the suffix in its dictionary, the original target and source are
 
181
    returned.
 
182
    """
 
183
    def __call__(self, target, source, env):
 
184
        emitter = SCons.Util.Selector.__call__(self, env, source)
 
185
        if emitter:
 
186
            target, source = emitter(target, source, env)
 
187
        return (target, source)
 
188
 
 
189
class ListEmitter(UserList.UserList):
 
190
    """A callable list of emitters that calls each in sequence,
 
191
    returning the result.
 
192
    """
 
193
    def __call__(self, target, source, env):
 
194
        for e in self.data:
 
195
            target, source = e(target, source, env)
 
196
        return (target, source)
 
197
 
 
198
# These are a common errors when calling a Builder;
 
199
# they are similar to the 'target' and 'source' keyword args to builders,
 
200
# so we issue warnings when we see them.  The warnings can, of course,
 
201
# be disabled.
 
202
misleading_keywords = {
 
203
    'targets'   : 'target',
 
204
    'sources'   : 'source',
 
205
}
 
206
 
 
207
class OverrideWarner(UserDict.UserDict):
 
208
    """A class for warning about keyword arguments that we use as
 
209
    overrides in a Builder call.
 
210
 
 
211
    This class exists to handle the fact that a single Builder call
 
212
    can actually invoke multiple builders.  This class only emits the
 
213
    warnings once, no matter how many Builders are invoked.
 
214
    """
 
215
    def __init__(self, dict):
 
216
        UserDict.UserDict.__init__(self, dict)
 
217
        if __debug__: logInstanceCreation(self, 'Builder.OverrideWarner')
 
218
        self.already_warned = None
 
219
    def warn(self):
 
220
        if self.already_warned:
 
221
            return
 
222
        for k in self.keys():
 
223
            if misleading_keywords.has_key(k):
 
224
                alt = misleading_keywords[k]
 
225
                msg = "Did you mean to use `%s' instead of `%s'?" % (alt, k)
 
226
                SCons.Warnings.warn(SCons.Warnings.MisleadingKeywordsWarning, msg)
 
227
        self.already_warned = 1
 
228
 
 
229
def Builder(**kw):
 
230
    """A factory for builder objects."""
 
231
    composite = None
 
232
    if kw.has_key('generator'):
 
233
        if kw.has_key('action'):
 
234
            raise UserError, "You must not specify both an action and a generator."
 
235
        kw['action'] = SCons.Action.CommandGeneratorAction(kw['generator'])
 
236
        del kw['generator']
 
237
    elif kw.has_key('action'):
 
238
        source_ext_match = kw.get('source_ext_match', 1)
 
239
        if kw.has_key('source_ext_match'):
 
240
            del kw['source_ext_match']
 
241
        if SCons.Util.is_Dict(kw['action']):
 
242
            composite = DictCmdGenerator(kw['action'], source_ext_match)
 
243
            kw['action'] = SCons.Action.CommandGeneratorAction(composite)
 
244
            kw['src_suffix'] = composite.src_suffixes()
 
245
        else:
 
246
            kw['action'] = SCons.Action.Action(kw['action'])
 
247
 
 
248
    if kw.has_key('emitter'):
 
249
        emitter = kw['emitter']
 
250
        if SCons.Util.is_String(emitter):
 
251
            # This allows users to pass in an Environment
 
252
            # variable reference (like "$FOO") as an emitter.
 
253
            # We will look in that Environment variable for
 
254
            # a callable to use as the actual emitter.
 
255
            var = SCons.Util.get_environment_var(emitter)
 
256
            if not var:
 
257
                raise UserError, "Supplied emitter '%s' does not appear to refer to an Environment variable" % emitter
 
258
            kw['emitter'] = EmitterProxy(var)
 
259
        elif SCons.Util.is_Dict(emitter):
 
260
            kw['emitter'] = DictEmitter(emitter)
 
261
        elif SCons.Util.is_List(emitter):
 
262
            kw['emitter'] = ListEmitter(emitter)
 
263
 
 
264
    result = apply(BuilderBase, (), kw)
 
265
 
 
266
    if not composite is None:
 
267
        result = CompositeBuilder(result, composite)
 
268
 
 
269
    return result
 
270
 
 
271
def _node_errors(builder, env, tlist, slist):
 
272
    """Validate that the lists of target and source nodes are
 
273
    legal for this builder and environment.  Raise errors or
 
274
    issue warnings as appropriate.
 
275
    """
 
276
 
 
277
    # First, figure out if there are any errors in the way the targets
 
278
    # were specified.
 
279
    for t in tlist:
 
280
        if t.side_effect:
 
281
            raise UserError, "Multiple ways to build the same target were specified for: %s" % t
 
282
        if t.has_explicit_builder():
 
283
            if not t.env is None and not t.env is env:
 
284
                action = t.builder.action
 
285
                t_contents = action.get_contents(tlist, slist, t.env)
 
286
                contents = action.get_contents(tlist, slist, env)
 
287
 
 
288
                if t_contents == contents:
 
289
                    msg = "Two different environments were specified for target %s,\n\tbut they appear to have the same action: %s" % (t, action.genstring(tlist, slist, t.env))
 
290
                    SCons.Warnings.warn(SCons.Warnings.DuplicateEnvironmentWarning, msg)
 
291
                else:
 
292
                    msg = "Two environments with different actions were specified for the same target: %s" % t
 
293
                    raise UserError, msg
 
294
            if builder.multi:
 
295
                if t.builder != builder:
 
296
                    msg = "Two different builders (%s and %s) were specified for the same target: %s" % (t.builder.get_name(env), builder.get_name(env), t)
 
297
                    raise UserError, msg
 
298
                if t.get_executor().targets != tlist:
 
299
                    msg = "Two different target lists have a target in common: %s  (from %s and from %s)" % (t, map(str, t.get_executor().targets), map(str, tlist))
 
300
                    raise UserError, msg
 
301
            elif t.sources != slist:
 
302
                msg = "Multiple ways to build the same target were specified for: %s  (from %s and from %s)" % (t, map(str, t.sources), map(str, slist))
 
303
                raise UserError, msg
 
304
 
 
305
    if builder.single_source:
 
306
        if len(slist) > 1:
 
307
            raise UserError, "More than one source given for single-source builder: targets=%s sources=%s" % (map(str,tlist), map(str,slist))
 
308
 
 
309
class EmitterProxy:
 
310
    """This is a callable class that can act as a
 
311
    Builder emitter.  It holds on to a string that
 
312
    is a key into an Environment dictionary, and will
 
313
    look there at actual build time to see if it holds
 
314
    a callable.  If so, we will call that as the actual
 
315
    emitter."""
 
316
    def __init__(self, var):
 
317
        self.var = SCons.Util.to_String(var)
 
318
 
 
319
    def __call__(self, target, source, env):
 
320
        emitter = self.var
 
321
 
 
322
        # Recursively substitute the variable.
 
323
        # We can't use env.subst() because it deals only
 
324
        # in strings.  Maybe we should change that?
 
325
        while SCons.Util.is_String(emitter) and env.has_key(emitter):
 
326
            emitter = env[emitter]
 
327
        if callable(emitter):
 
328
            target, source = emitter(target, source, env)
 
329
        elif SCons.Util.is_List(emitter):
 
330
            for e in emitter:
 
331
                target, source = e(target, source, env)
 
332
 
 
333
        return (target, source)
 
334
 
 
335
 
 
336
    def __cmp__(self, other):
 
337
        return cmp(self.var, other.var)
 
338
 
 
339
class BuilderBase:
 
340
    """Base class for Builders, objects that create output
 
341
    nodes (files) from input nodes (files).
 
342
    """
 
343
 
 
344
    if SCons.Memoize.use_memoizer:
 
345
        __metaclass__ = SCons.Memoize.Memoized_Metaclass
 
346
 
 
347
    memoizer_counters = []
 
348
 
 
349
    def __init__(self,  action = None,
 
350
                        prefix = '',
 
351
                        suffix = '',
 
352
                        src_suffix = '',
 
353
                        target_factory = None,
 
354
                        source_factory = None,
 
355
                        target_scanner = None,
 
356
                        source_scanner = None,
 
357
                        emitter = None,
 
358
                        multi = 0,
 
359
                        env = None,
 
360
                        single_source = 0,
 
361
                        name = None,
 
362
                        chdir = _null,
 
363
                        is_explicit = 1,
 
364
                        src_builder = None,
 
365
                        ensure_suffix = False,
 
366
                        **overrides):
 
367
        if __debug__: logInstanceCreation(self, 'Builder.BuilderBase')
 
368
        self._memo = {}
 
369
        self.action = action
 
370
        self.multi = multi
 
371
        if SCons.Util.is_Dict(prefix):
 
372
            prefix = CallableSelector(prefix)
 
373
        self.prefix = prefix
 
374
        if SCons.Util.is_Dict(suffix):
 
375
            suffix = CallableSelector(suffix)
 
376
        self.env = env
 
377
        self.single_source = single_source
 
378
        if overrides.has_key('overrides'):
 
379
            SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning,
 
380
                "The \"overrides\" keyword to Builder() creation has been deprecated;\n" +\
 
381
                "\tspecify the items as keyword arguments to the Builder() call instead.")
 
382
            overrides.update(overrides['overrides'])
 
383
            del overrides['overrides']
 
384
        if overrides.has_key('scanner'):
 
385
            SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning,
 
386
                                "The \"scanner\" keyword to Builder() creation has been deprecated;\n"
 
387
                                "\tuse: source_scanner or target_scanner as appropriate.")
 
388
            del overrides['scanner']
 
389
        self.overrides = overrides
 
390
 
 
391
        self.set_suffix(suffix)
 
392
        self.set_src_suffix(src_suffix)
 
393
        self.ensure_suffix = ensure_suffix
 
394
 
 
395
        self.target_factory = target_factory
 
396
        self.source_factory = source_factory
 
397
        self.target_scanner = target_scanner
 
398
        self.source_scanner = source_scanner
 
399
 
 
400
        self.emitter = emitter
 
401
 
 
402
        # Optional Builder name should only be used for Builders
 
403
        # that don't get attached to construction environments.
 
404
        if name:
 
405
            self.name = name
 
406
        self.executor_kw = {}
 
407
        if not chdir is _null:
 
408
            self.executor_kw['chdir'] = chdir
 
409
        self.is_explicit = is_explicit
 
410
 
 
411
        if src_builder is None:
 
412
            src_builder = []
 
413
        elif not SCons.Util.is_List(src_builder):
 
414
            src_builder = [ src_builder ]
 
415
        self.src_builder = src_builder
 
416
 
 
417
    def __nonzero__(self):
 
418
        raise InternalError, "Do not test for the Node.builder attribute directly; use Node.has_builder() instead"
 
419
 
 
420
    def get_name(self, env):
 
421
        """Attempts to get the name of the Builder.
 
422
 
 
423
        Look at the BUILDERS variable of env, expecting it to be a
 
424
        dictionary containing this Builder, and return the key of the
 
425
        dictionary.  If there's no key, then return a directly-configured
 
426
        name (if there is one) or the name of the class (by default)."""
 
427
 
 
428
        try:
 
429
            index = env['BUILDERS'].values().index(self)
 
430
            return env['BUILDERS'].keys()[index]
 
431
        except (AttributeError, KeyError, TypeError, ValueError):
 
432
            try:
 
433
                return self.name
 
434
            except AttributeError:
 
435
                return str(self.__class__)
 
436
 
 
437
    def __cmp__(self, other):
 
438
        return cmp(self.__dict__, other.__dict__)
 
439
 
 
440
    def splitext(self, path, env=None):
 
441
        if not env:
 
442
            env = self.env
 
443
        if env:
 
444
            matchsuf = filter(lambda S,path=path: path[-len(S):] == S,
 
445
                              self.src_suffixes(env))
 
446
            if matchsuf:
 
447
                suf = max(map(None, map(len, matchsuf), matchsuf))[1]
 
448
                return [path[:-len(suf)], path[-len(suf):]]
 
449
        return SCons.Util.splitext(path)
 
450
 
 
451
    def get_single_executor(self, env, tlist, slist, executor_kw):
 
452
        if not self.action:
 
453
            raise UserError, "Builder %s must have an action to build %s."%(self.get_name(env or self.env), map(str,tlist))
 
454
        return self.action.get_executor(env or self.env,
 
455
                                        [],  # env already has overrides
 
456
                                        tlist,
 
457
                                        slist,
 
458
                                        executor_kw)
 
459
 
 
460
    def get_multi_executor(self, env, tlist, slist, executor_kw):
 
461
        try:
 
462
            executor = tlist[0].get_executor(create = 0)
 
463
        except (AttributeError, IndexError):
 
464
            return self.get_single_executor(env, tlist, slist, executor_kw)
 
465
        else:
 
466
            executor.add_sources(slist)
 
467
            return executor
 
468
 
 
469
    def _adjustixes(self, files, pre, suf, ensure_suffix=False):
 
470
        if not files:
 
471
            return []
 
472
        result = []
 
473
        if not SCons.Util.is_List(files):
 
474
            files = [files]
 
475
 
 
476
        for f in files:
 
477
            if SCons.Util.is_String(f):
 
478
                f = SCons.Util.adjustixes(f, pre, suf, ensure_suffix)
 
479
            result.append(f)
 
480
        return result
 
481
 
 
482
    def _create_nodes(self, env, target = None, source = None):
 
483
        """Create and return lists of target and source nodes.
 
484
        """
 
485
        src_suf = self.get_src_suffix(env)
 
486
 
 
487
        target_factory = env.get_factory(self.target_factory)
 
488
        source_factory = env.get_factory(self.source_factory)
 
489
 
 
490
        source = self._adjustixes(source, None, src_suf)
 
491
        slist = env.arg2nodes(source, source_factory)
 
492
 
 
493
        pre = self.get_prefix(env, slist)
 
494
        suf = self.get_suffix(env, slist)
 
495
 
 
496
        if target is None:
 
497
            try:
 
498
                t_from_s = slist[0].target_from_source
 
499
            except AttributeError:
 
500
                raise UserError("Do not know how to create a target from source `%s'" % slist[0])
 
501
            except IndexError:
 
502
                tlist = []
 
503
            else:
 
504
                splitext = lambda S,self=self,env=env: self.splitext(S,env)
 
505
                tlist = [ t_from_s(pre, suf, splitext) ]
 
506
        else:
 
507
            target = self._adjustixes(target, pre, suf, self.ensure_suffix)
 
508
            tlist = env.arg2nodes(target, target_factory, target=target, source=source)
 
509
 
 
510
        if self.emitter:
 
511
            # The emitter is going to do str(node), but because we're
 
512
            # being called *from* a builder invocation, the new targets
 
513
            # don't yet have a builder set on them and will look like
 
514
            # source files.  Fool the emitter's str() calls by setting
 
515
            # up a temporary builder on the new targets.
 
516
            new_targets = []
 
517
            for t in tlist:
 
518
                if not t.is_derived():
 
519
                    t.builder_set(self)
 
520
                    new_targets.append(t)
 
521
 
 
522
            orig_tlist = tlist[:]
 
523
            orig_slist = slist[:]
 
524
 
 
525
            target, source = self.emitter(target=tlist, source=slist, env=env)
 
526
 
 
527
            # Now delete the temporary builders that we attached to any
 
528
            # new targets, so that _node_errors() doesn't do weird stuff
 
529
            # to them because it thinks they already have builders.
 
530
            for t in new_targets:
 
531
                if t.builder is self:
 
532
                    # Only delete the temporary builder if the emitter
 
533
                    # didn't change it on us.
 
534
                    t.builder_set(None)
 
535
 
 
536
            # Have to call arg2nodes yet again, since it is legal for
 
537
            # emitters to spit out strings as well as Node instances.
 
538
            tlist = env.arg2nodes(target, target_factory,
 
539
                                  target=orig_tlist, source=orig_slist)
 
540
            slist = env.arg2nodes(source, source_factory,
 
541
                                  target=orig_tlist, source=orig_slist)
 
542
 
 
543
        return tlist, slist
 
544
 
 
545
    def _execute(self, env, target, source, overwarn={}, executor_kw={}):
 
546
        # We now assume that target and source are lists or None.
 
547
        if self.src_builder:
 
548
            source = self.src_builder_sources(env, source, overwarn)
 
549
 
 
550
        if self.single_source and len(source) > 1 and target is None:
 
551
            result = []
 
552
            if target is None: target = [None]*len(source)
 
553
            for tgt, src in zip(target, source):
 
554
                if not tgt is None: tgt = [tgt]
 
555
                if not src is None: src = [src]
 
556
                result.extend(self._execute(env, tgt, src, overwarn))
 
557
            return SCons.Node.NodeList(result)
 
558
 
 
559
        overwarn.warn()
 
560
 
 
561
        tlist, slist = self._create_nodes(env, target, source)
 
562
 
 
563
        # Check for errors with the specified target/source lists.
 
564
        _node_errors(self, env, tlist, slist)
 
565
 
 
566
        # The targets are fine, so find or make the appropriate Executor to
 
567
        # build this particular list of targets from this particular list of
 
568
        # sources.
 
569
        if self.multi:
 
570
            get_executor = self.get_multi_executor
 
571
        else:
 
572
            get_executor = self.get_single_executor
 
573
        executor = get_executor(env, tlist, slist, executor_kw)
 
574
 
 
575
        # Now set up the relevant information in the target Nodes themselves.
 
576
        for t in tlist:
 
577
            t.cwd = env.fs.getcwd()
 
578
            t.builder_set(self)
 
579
            t.env_set(env)
 
580
            t.add_source(slist)
 
581
            t.set_executor(executor)
 
582
            t.set_explicit(self.is_explicit)
 
583
 
 
584
        return SCons.Node.NodeList(tlist)
 
585
 
 
586
    def __call__(self, env, target=None, source=None, chdir=_null, **kw):
 
587
        # We now assume that target and source are lists or None.
 
588
        # The caller (typically Environment.BuilderWrapper) is
 
589
        # responsible for converting any scalar values to lists.
 
590
        if chdir is _null:
 
591
            ekw = self.executor_kw
 
592
        else:
 
593
            ekw = self.executor_kw.copy()
 
594
            ekw['chdir'] = chdir
 
595
        if kw:
 
596
            if kw.has_key('srcdir'):
 
597
                def prependDirIfRelative(f, srcdir=kw['srcdir']):
 
598
                    import os.path
 
599
                    if SCons.Util.is_String(f) and not os.path.isabs(f):
 
600
                        f = os.path.join(srcdir, f)
 
601
                    return f
 
602
                if not SCons.Util.is_List(source):
 
603
                    source = [source]
 
604
                source = map(prependDirIfRelative, source)
 
605
                del kw['srcdir']
 
606
            if self.overrides:
 
607
                env_kw = self.overrides.copy()
 
608
                env_kw.update(kw)
 
609
            else:
 
610
                env_kw = kw
 
611
        else:
 
612
            env_kw = self.overrides
 
613
        env = env.Override(env_kw)
 
614
        return self._execute(env, target, source, OverrideWarner(kw), ekw)
 
615
 
 
616
    def adjust_suffix(self, suff):
 
617
        if suff and not suff[0] in [ '.', '_', '$' ]:
 
618
            return '.' + suff
 
619
        return suff
 
620
 
 
621
    def get_prefix(self, env, sources=[]):
 
622
        prefix = self.prefix
 
623
        if callable(prefix):
 
624
            prefix = prefix(env, sources)
 
625
        return env.subst(prefix)
 
626
 
 
627
    def set_suffix(self, suffix):
 
628
        if not callable(suffix):
 
629
            suffix = self.adjust_suffix(suffix)
 
630
        self.suffix = suffix
 
631
 
 
632
    def get_suffix(self, env, sources=[]):
 
633
        suffix = self.suffix
 
634
        if callable(suffix):
 
635
            suffix = suffix(env, sources)
 
636
        return env.subst(suffix)
 
637
 
 
638
    def set_src_suffix(self, src_suffix):
 
639
        if not src_suffix:
 
640
            src_suffix = []
 
641
        elif not SCons.Util.is_List(src_suffix):
 
642
            src_suffix = [ src_suffix ]
 
643
        adjust = lambda suf, s=self: \
 
644
                        callable(suf) and suf or s.adjust_suffix(suf)
 
645
        self.src_suffix = map(adjust, src_suffix)
 
646
 
 
647
    def get_src_suffix(self, env):
 
648
        """Get the first src_suffix in the list of src_suffixes."""
 
649
        ret = self.src_suffixes(env)
 
650
        if not ret:
 
651
            return ''
 
652
        return ret[0]
 
653
 
 
654
    def add_emitter(self, suffix, emitter):
 
655
        """Add a suffix-emitter mapping to this Builder.
 
656
 
 
657
        This assumes that emitter has been initialized with an
 
658
        appropriate dictionary type, and will throw a TypeError if
 
659
        not, so the caller is responsible for knowing that this is an
 
660
        appropriate method to call for the Builder in question.
 
661
        """
 
662
        self.emitter[suffix] = emitter
 
663
 
 
664
    def add_src_builder(self, builder):
 
665
        """
 
666
        Add a new Builder to the list of src_builders.
 
667
 
 
668
        This requires wiping out cached values so that the computed
 
669
        lists of source suffixes get re-calculated.
 
670
        """
 
671
        self._memo = {}
 
672
        self.src_builder.append(builder)
 
673
 
 
674
    def _get_sdict(self, env):
 
675
        """
 
676
        Returns a dictionary mapping all of the source suffixes of all
 
677
        src_builders of this Builder to the underlying Builder that
 
678
        should be called first.
 
679
 
 
680
        This dictionary is used for each target specified, so we save a
 
681
        lot of extra computation by memoizing it for each construction
 
682
        environment.
 
683
 
 
684
        Note that this is re-computed each time, not cached, because there
 
685
        might be changes to one of our source Builders (or one of their
 
686
        source Builders, and so on, and so on...) that we can't "see."
 
687
 
 
688
        The underlying methods we call cache their computed values,
 
689
        though, so we hope repeatedly aggregating them into a dictionary
 
690
        like this won't be too big a hit.  We may need to look for a
 
691
        better way to do this if performance data show this has turned
 
692
        into a significant bottleneck.
 
693
        """
 
694
        sdict = {}
 
695
        for bld in self.get_src_builders(env):
 
696
            for suf in bld.src_suffixes(env):
 
697
                sdict[suf] = bld
 
698
        return sdict
 
699
 
 
700
    def src_builder_sources(self, env, source, overwarn={}):
 
701
        sdict = self._get_sdict(env)
 
702
 
 
703
        src_suffixes = self.src_suffixes(env)
 
704
 
 
705
        lengths = list(set(map(len, src_suffixes)))
 
706
 
 
707
        def match_src_suffix(name, src_suffixes=src_suffixes, lengths=lengths):
 
708
            node_suffixes = map(lambda l, n=name: n[-l:], lengths)
 
709
            for suf in src_suffixes:
 
710
                if suf in node_suffixes:
 
711
                    return suf
 
712
            return None
 
713
 
 
714
        result = []
 
715
        for s in SCons.Util.flatten(source):
 
716
            if SCons.Util.is_String(s):
 
717
                match_suffix = match_src_suffix(env.subst(s))
 
718
                if not match_suffix and not '.' in s:
 
719
                    src_suf = self.get_src_suffix(env)
 
720
                    s = self._adjustixes(s, None, src_suf)[0]
 
721
            else:
 
722
                match_suffix = match_src_suffix(s.name)
 
723
            if match_suffix:
 
724
                try:
 
725
                    bld = sdict[match_suffix]
 
726
                except KeyError:
 
727
                    result.append(s)
 
728
                else:
 
729
                    tlist = bld._execute(env, None, [s], overwarn)
 
730
                    # If the subsidiary Builder returned more than one
 
731
                    # target, then filter out any sources that this
 
732
                    # Builder isn't capable of building.
 
733
                    if len(tlist) > 1:
 
734
                        mss = lambda t, m=match_src_suffix: m(t.name)
 
735
                        tlist = filter(mss, tlist)
 
736
                    result.extend(tlist)
 
737
            else:
 
738
                result.append(s)
 
739
 
 
740
        source_factory = env.get_factory(self.source_factory)
 
741
 
 
742
        return env.arg2nodes(result, source_factory)
 
743
 
 
744
    def _get_src_builders_key(self, env):
 
745
        return id(env)
 
746
 
 
747
    memoizer_counters.append(SCons.Memoize.CountDict('get_src_builders', _get_src_builders_key))
 
748
 
 
749
    def get_src_builders(self, env):
 
750
        """
 
751
        Returns the list of source Builders for this Builder.
 
752
 
 
753
        This exists mainly to look up Builders referenced as
 
754
        strings in the 'BUILDER' variable of the construction
 
755
        environment and cache the result.
 
756
        """
 
757
        memo_key = id(env)
 
758
        try:
 
759
            memo_dict = self._memo['get_src_builders']
 
760
        except KeyError:
 
761
            memo_dict = {}
 
762
            self._memo['get_src_builders'] = memo_dict
 
763
        else:
 
764
            try:
 
765
                return memo_dict[memo_key]
 
766
            except KeyError:
 
767
                pass
 
768
 
 
769
        builders = []
 
770
        for bld in self.src_builder:
 
771
            if SCons.Util.is_String(bld):
 
772
                try:
 
773
                    bld = env['BUILDERS'][bld]
 
774
                except KeyError:
 
775
                    continue
 
776
            builders.append(bld)
 
777
 
 
778
        memo_dict[memo_key] = builders
 
779
        return builders
 
780
 
 
781
    def _subst_src_suffixes_key(self, env):
 
782
        return id(env)
 
783
 
 
784
    memoizer_counters.append(SCons.Memoize.CountDict('subst_src_suffixes', _subst_src_suffixes_key))
 
785
 
 
786
    def subst_src_suffixes(self, env):
 
787
        """
 
788
        The suffix list may contain construction variable expansions,
 
789
        so we have to evaluate the individual strings.  To avoid doing
 
790
        this over and over, we memoize the results for each construction
 
791
        environment.
 
792
        """
 
793
        memo_key = id(env)
 
794
        try:
 
795
            memo_dict = self._memo['subst_src_suffixes']
 
796
        except KeyError:
 
797
            memo_dict = {}
 
798
            self._memo['subst_src_suffixes'] = memo_dict
 
799
        else:
 
800
            try:
 
801
                return memo_dict[memo_key]
 
802
            except KeyError:
 
803
                pass
 
804
        suffixes = map(lambda x, s=self, e=env: e.subst(x), self.src_suffix)
 
805
        memo_dict[memo_key] = suffixes
 
806
        return suffixes
 
807
 
 
808
    def src_suffixes(self, env):
 
809
        """
 
810
        Returns the list of source suffixes for all src_builders of this
 
811
        Builder.
 
812
 
 
813
        This is essentially a recursive descent of the src_builder "tree."
 
814
        (This value isn't cached because there may be changes in a
 
815
        src_builder many levels deep that we can't see.)
 
816
        """
 
817
        sdict = {}
 
818
        suffixes = self.subst_src_suffixes(env)
 
819
        for s in suffixes:
 
820
            sdict[s] = 1
 
821
        for builder in self.get_src_builders(env):
 
822
            for s in builder.src_suffixes(env):
 
823
                if not sdict.has_key(s):
 
824
                    sdict[s] = 1
 
825
                    suffixes.append(s)
 
826
        return suffixes
 
827
 
 
828
class CompositeBuilder(SCons.Util.Proxy):
 
829
    """A Builder Proxy whose main purpose is to always have
 
830
    a DictCmdGenerator as its action, and to provide access
 
831
    to the DictCmdGenerator's add_action() method.
 
832
    """
 
833
 
 
834
    def __init__(self, builder, cmdgen):
 
835
        if __debug__: logInstanceCreation(self, 'Builder.CompositeBuilder')
 
836
        SCons.Util.Proxy.__init__(self, builder)
 
837
 
 
838
        # cmdgen should always be an instance of DictCmdGenerator.
 
839
        self.cmdgen = cmdgen
 
840
        self.builder = builder
 
841
 
 
842
    def add_action(self, suffix, action):
 
843
        self.cmdgen.add_action(suffix, action)
 
844
        self.set_src_suffix(self.cmdgen.src_suffixes())