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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101 __revision__ = "src/engine/SCons/Builder.py 3842 2008/12/20 22:59:52 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
118
119 _null = _Null
120
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):
131
134
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
167 """A callable dictionary that will, in turn, call the value it
168 finds if it can."""
170 value = SCons.Util.Selector.__call__(self, env, source)
171 if callable(value):
172 value = value(env, source)
173 return value
174
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
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
199
200
201
202 misleading_keywords = {
203 'targets' : 'target',
204 'sources' : 'source',
205 }
206
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 """
228
270
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
278
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
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."""
318
319 - def __call__(self, target, source, env):
320 emitter = self.var
321
322
323
324
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
337 return cmp(self.var, other.var)
338
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
403
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
418 raise InternalError, "Do not test for the Node.builder attribute directly; use Node.has_builder() instead"
419
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
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
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 [],
456 tlist,
457 slist,
458 executor_kw)
459
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
481
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
512
513
514
515
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
528
529
530 for t in new_targets:
531 if t.builder is self:
532
533
534 t.builder_set(None)
535
536
537
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
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
564 _node_errors(self, env, tlist, slist)
565
566
567
568
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
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
588
589
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
617 if suff and not suff[0] in [ '.', '_', '$' ]:
618 return '.' + suff
619 return suff
620
622 prefix = self.prefix
623 if callable(prefix):
624 prefix = prefix(env, sources)
625 return env.subst(prefix)
626
628 if not callable(suffix):
629 suffix = self.adjust_suffix(suffix)
630 self.suffix = suffix
631
633 suffix = self.suffix
634 if callable(suffix):
635 suffix = suffix(env, sources)
636 return env.subst(suffix)
637
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
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
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
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
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
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
731
732
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
746
747 memoizer_counters.append(SCons.Memoize.CountDict('get_src_builders', _get_src_builders_key))
748
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
783
784 memoizer_counters.append(SCons.Memoize.CountDict('subst_src_suffixes', _subst_src_suffixes_key))
785
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
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
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
841
845