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 __revision__ = "src/engine/SCons/Builder.py pchdll:3325:cd517fae59a4 2015/06/18 06:53:27 bdbaddog"
101
102 import collections
103
104 import SCons.Action
105 import SCons.Debug
106 from SCons.Debug import logInstanceCreation
107 from SCons.Errors import InternalError, UserError
108 import SCons.Executor
109 import SCons.Memoize
110 import SCons.Util
111 import SCons.Warnings
112
115
116 _null = _Null
117
118 -def match_splitext(path, suffixes = []):
119 if suffixes:
120 matchsuf = [S for S in suffixes if path[-len(S):] == S]
121 if matchsuf:
122 suf = max([(len(_f),_f) for _f in matchsuf])[1]
123 return [path[:-len(suf)], path[-len(suf):]]
124 return SCons.Util.splitext(path)
125
127 """This is a callable class that can be used as a
128 command generator function. It holds on to a dictionary
129 mapping file suffixes to Actions. It uses that dictionary
130 to return the proper action based on the file suffix of
131 the source file."""
132
133 - def __init__(self, dict=None, source_ext_match=1):
136
138 return list(self.keys())
139
141 """Add a suffix-action pair to the mapping.
142 """
143 self[suffix] = action
144
145 - def __call__(self, target, source, env, for_signature):
146 if not source:
147 return []
148
149 if self.source_ext_match:
150 suffixes = self.src_suffixes()
151 ext = None
152 for src in map(str, source):
153 my_ext = match_splitext(src, suffixes)[1]
154 if ext and my_ext != ext:
155 raise UserError("While building `%s' from `%s': Cannot build multiple sources with different extensions: %s, %s"
156 % (repr(list(map(str, target))), src, ext, my_ext))
157 ext = my_ext
158 else:
159 ext = match_splitext(str(source[0]), self.src_suffixes())[1]
160
161 if not ext:
162
163 raise UserError("While building `%s': "
164 "Cannot deduce file extension from source files: %s"
165 % (repr(list(map(str, target))), repr(list(map(str, source)))))
166
167 try:
168 ret = SCons.Util.Selector.__call__(self, env, source, ext)
169 except KeyError, e:
170 raise UserError("Ambiguous suffixes after environment substitution: %s == %s == %s" % (e.args[0], e.args[1], e.args[2]))
171 if ret is None:
172 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." % \
173 (repr(list(map(str, target))), repr(list(map(str, source))), ext, repr(list(self.keys()))))
174 return ret
175
177 """A callable dictionary that will, in turn, call the value it
178 finds if it can."""
180 value = SCons.Util.Selector.__call__(self, env, source)
181 if callable(value):
182 value = value(env, source)
183 return value
184
186 """A callable dictionary that maps file suffixes to emitters.
187 When called, it finds the right emitter in its dictionary for the
188 suffix of the first source file, and calls that emitter to get the
189 right lists of targets and sources to return. If there's no emitter
190 for the suffix in its dictionary, the original target and source are
191 returned.
192 """
193 - def __call__(self, target, source, env):
194 emitter = SCons.Util.Selector.__call__(self, env, source)
195 if emitter:
196 target, source = emitter(target, source, env)
197 return (target, source)
198
200 """A callable list of emitters that calls each in sequence,
201 returning the result.
202 """
203 - def __call__(self, target, source, env):
204 for e in self.data:
205 target, source = e(target, source, env)
206 return (target, source)
207
208
209
210
211
212 misleading_keywords = {
213 'targets' : 'target',
214 'sources' : 'source',
215 }
216
218 """A class for warning about keyword arguments that we use as
219 overrides in a Builder call.
220
221 This class exists to handle the fact that a single Builder call
222 can actually invoke multiple builders. This class only emits the
223 warnings once, no matter how many Builders are invoked.
224 """
238
240 """A factory for builder objects."""
241 composite = None
242 if 'generator' in kw:
243 if 'action' in kw:
244 raise UserError("You must not specify both an action and a generator.")
245 kw['action'] = SCons.Action.CommandGeneratorAction(kw['generator'], {})
246 del kw['generator']
247 elif 'action' in kw:
248 source_ext_match = kw.get('source_ext_match', 1)
249 if 'source_ext_match' in kw:
250 del kw['source_ext_match']
251 if SCons.Util.is_Dict(kw['action']):
252 composite = DictCmdGenerator(kw['action'], source_ext_match)
253 kw['action'] = SCons.Action.CommandGeneratorAction(composite, {})
254 kw['src_suffix'] = composite.src_suffixes()
255 else:
256 kw['action'] = SCons.Action.Action(kw['action'])
257
258 if 'emitter' in kw:
259 emitter = kw['emitter']
260 if SCons.Util.is_String(emitter):
261
262
263
264
265 var = SCons.Util.get_environment_var(emitter)
266 if not var:
267 raise UserError("Supplied emitter '%s' does not appear to refer to an Environment variable" % emitter)
268 kw['emitter'] = EmitterProxy(var)
269 elif SCons.Util.is_Dict(emitter):
270 kw['emitter'] = DictEmitter(emitter)
271 elif SCons.Util.is_List(emitter):
272 kw['emitter'] = ListEmitter(emitter)
273
274 result = BuilderBase(**kw)
275
276 if not composite is None:
277 result = CompositeBuilder(result, composite)
278
279 return result
280
282 """Validate that the lists of target and source nodes are
283 legal for this builder and environment. Raise errors or
284 issue warnings as appropriate.
285 """
286
287
288
289 for t in tlist:
290 if t.side_effect:
291 raise UserError("Multiple ways to build the same target were specified for: %s" % t)
292 if t.has_explicit_builder():
293 if not t.env is None and not t.env is env:
294 action = t.builder.action
295 t_contents = action.get_contents(tlist, slist, t.env)
296 contents = action.get_contents(tlist, slist, env)
297
298 if t_contents == contents:
299 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))
300 SCons.Warnings.warn(SCons.Warnings.DuplicateEnvironmentWarning, msg)
301 else:
302 msg = "Two environments with different actions were specified for the same target: %s" % t
303 raise UserError(msg)
304 if builder.multi:
305 if t.builder != builder:
306 msg = "Two different builders (%s and %s) were specified for the same target: %s" % (t.builder.get_name(env), builder.get_name(env), t)
307 raise UserError(msg)
308
309 if t.get_executor().get_all_targets() != tlist:
310 msg = "Two different target lists have a target in common: %s (from %s and from %s)" % (t, list(map(str, t.get_executor().get_all_targets())), list(map(str, tlist)))
311 raise UserError(msg)
312 elif t.sources != slist:
313 msg = "Multiple ways to build the same target were specified for: %s (from %s and from %s)" % (t, list(map(str, t.sources)), list(map(str, slist)))
314 raise UserError(msg)
315
316 if builder.single_source:
317 if len(slist) > 1:
318 raise UserError("More than one source given for single-source builder: targets=%s sources=%s" % (list(map(str,tlist)), list(map(str,slist))))
319
321 """This is a callable class that can act as a
322 Builder emitter. It holds on to a string that
323 is a key into an Environment dictionary, and will
324 look there at actual build time to see if it holds
325 a callable. If so, we will call that as the actual
326 emitter."""
329
330 - def __call__(self, target, source, env):
331 emitter = self.var
332
333
334
335
336 while SCons.Util.is_String(emitter) and emitter in env:
337 emitter = env[emitter]
338 if callable(emitter):
339 target, source = emitter(target, source, env)
340 elif SCons.Util.is_List(emitter):
341 for e in emitter:
342 target, source = e(target, source, env)
343
344 return (target, source)
345
346
348 return cmp(self.var, other.var)
349
351 """Base class for Builders, objects that create output
352 nodes (files) from input nodes (files).
353 """
354
355 if SCons.Memoize.use_memoizer:
356 __metaclass__ = SCons.Memoize.Memoized_Metaclass
357
358 memoizer_counters = []
359
360 - def __init__(self, action = None,
361 prefix = '',
362 suffix = '',
363 src_suffix = '',
364 target_factory = None,
365 source_factory = None,
366 target_scanner = None,
367 source_scanner = None,
368 emitter = None,
369 multi = 0,
370 env = None,
371 single_source = 0,
372 name = None,
373 chdir = _null,
374 is_explicit = 1,
375 src_builder = None,
376 ensure_suffix = False,
377 **overrides):
427
429 raise InternalError("Do not test for the Node.builder attribute directly; use Node.has_builder() instead")
430
432 """Attempts to get the name of the Builder.
433
434 Look at the BUILDERS variable of env, expecting it to be a
435 dictionary containing this Builder, and return the key of the
436 dictionary. If there's no key, then return a directly-configured
437 name (if there is one) or the name of the class (by default)."""
438
439 try:
440 index = list(env['BUILDERS'].values()).index(self)
441 return list(env['BUILDERS'].keys())[index]
442 except (AttributeError, KeyError, TypeError, ValueError):
443 try:
444 return self.name
445 except AttributeError:
446 return str(self.__class__)
447
449 return cmp(self.__dict__, other.__dict__)
450
451 - def splitext(self, path, env=None):
452 if not env:
453 env = self.env
454 if env:
455 suffixes = self.src_suffixes(env)
456 else:
457 suffixes = []
458 return match_splitext(path, suffixes)
459
460 - def _adjustixes(self, files, pre, suf, ensure_suffix=False):
461 if not files:
462 return []
463 result = []
464 if not SCons.Util.is_List(files):
465 files = [files]
466
467 for f in files:
468 if SCons.Util.is_String(f):
469 f = SCons.Util.adjustixes(f, pre, suf, ensure_suffix)
470 result.append(f)
471 return result
472
474 """Create and return lists of target and source nodes.
475 """
476 src_suf = self.get_src_suffix(env)
477
478 target_factory = env.get_factory(self.target_factory)
479 source_factory = env.get_factory(self.source_factory)
480
481 source = self._adjustixes(source, None, src_suf)
482 slist = env.arg2nodes(source, source_factory)
483
484 pre = self.get_prefix(env, slist)
485 suf = self.get_suffix(env, slist)
486
487 if target is None:
488 try:
489 t_from_s = slist[0].target_from_source
490 except AttributeError:
491 raise UserError("Do not know how to create a target from source `%s'" % slist[0])
492 except IndexError:
493 tlist = []
494 else:
495 splitext = lambda S: self.splitext(S,env)
496 tlist = [ t_from_s(pre, suf, splitext) ]
497 else:
498 target = self._adjustixes(target, pre, suf, self.ensure_suffix)
499 tlist = env.arg2nodes(target, target_factory, target=target, source=source)
500
501 if self.emitter:
502
503
504
505
506
507 new_targets = []
508 for t in tlist:
509 if not t.is_derived():
510 t.builder_set(self)
511 new_targets.append(t)
512
513 orig_tlist = tlist[:]
514 orig_slist = slist[:]
515
516 target, source = self.emitter(target=tlist, source=slist, env=env)
517
518
519
520
521 for t in new_targets:
522 if t.builder is self:
523
524
525 t.builder_set(None)
526
527
528
529 tlist = env.arg2nodes(target, target_factory,
530 target=orig_tlist, source=orig_slist)
531 slist = env.arg2nodes(source, source_factory,
532 target=orig_tlist, source=orig_slist)
533
534 return tlist, slist
535
536 - def _execute(self, env, target, source, overwarn={}, executor_kw={}):
537
538 if self.src_builder:
539 source = self.src_builder_sources(env, source, overwarn)
540
541 if self.single_source and len(source) > 1 and target is None:
542 result = []
543 if target is None: target = [None]*len(source)
544 for tgt, src in zip(target, source):
545 if not tgt is None: tgt = [tgt]
546 if not src is None: src = [src]
547 result.extend(self._execute(env, tgt, src, overwarn))
548 return SCons.Node.NodeList(result)
549
550 overwarn.warn()
551
552 tlist, slist = self._create_nodes(env, target, source)
553
554
555 _node_errors(self, env, tlist, slist)
556
557
558
559
560
561 executor = None
562 key = None
563
564 if self.multi:
565 try:
566 executor = tlist[0].get_executor(create = 0)
567 except (AttributeError, IndexError):
568 pass
569 else:
570 executor.add_sources(slist)
571
572 if executor is None:
573 if not self.action:
574 fmt = "Builder %s must have an action to build %s."
575 raise UserError(fmt % (self.get_name(env or self.env),
576 list(map(str,tlist))))
577 key = self.action.batch_key(env or self.env, tlist, slist)
578 if key:
579 try:
580 executor = SCons.Executor.GetBatchExecutor(key)
581 except KeyError:
582 pass
583 else:
584 executor.add_batch(tlist, slist)
585
586 if executor is None:
587 executor = SCons.Executor.Executor(self.action, env, [],
588 tlist, slist, executor_kw)
589 if key:
590 SCons.Executor.AddBatchExecutor(key, executor)
591
592
593 for t in tlist:
594 t.cwd = env.fs.getcwd()
595 t.builder_set(self)
596 t.env_set(env)
597 t.add_source(slist)
598 t.set_executor(executor)
599 t.set_explicit(self.is_explicit)
600
601 return SCons.Node.NodeList(tlist)
602
603 - def __call__(self, env, target=None, source=None, chdir=_null, **kw):
604
605
606
607 if chdir is _null:
608 ekw = self.executor_kw
609 else:
610 ekw = self.executor_kw.copy()
611 ekw['chdir'] = chdir
612 if kw:
613 if 'srcdir' in kw:
614 def prependDirIfRelative(f, srcdir=kw['srcdir']):
615 import os.path
616 if SCons.Util.is_String(f) and not os.path.isabs(f):
617 f = os.path.join(srcdir, f)
618 return f
619 if not SCons.Util.is_List(source):
620 source = [source]
621 source = list(map(prependDirIfRelative, source))
622 del kw['srcdir']
623 if self.overrides:
624 env_kw = self.overrides.copy()
625 env_kw.update(kw)
626 else:
627 env_kw = kw
628 else:
629 env_kw = self.overrides
630 env = env.Override(env_kw)
631 return self._execute(env, target, source, OverrideWarner(kw), ekw)
632
634 if suff and not suff[0] in [ '.', '_', '$' ]:
635 return '.' + suff
636 return suff
637
639 prefix = self.prefix
640 if callable(prefix):
641 prefix = prefix(env, sources)
642 return env.subst(prefix)
643
645 if not callable(suffix):
646 suffix = self.adjust_suffix(suffix)
647 self.suffix = suffix
648
650 suffix = self.suffix
651 if callable(suffix):
652 suffix = suffix(env, sources)
653 return env.subst(suffix)
654
656 if not src_suffix:
657 src_suffix = []
658 elif not SCons.Util.is_List(src_suffix):
659 src_suffix = [ src_suffix ]
660 self.src_suffix = [callable(suf) and suf or self.adjust_suffix(suf) for suf in src_suffix]
661
663 """Get the first src_suffix in the list of src_suffixes."""
664 ret = self.src_suffixes(env)
665 if not ret:
666 return ''
667 return ret[0]
668
670 """Add a suffix-emitter mapping to this Builder.
671
672 This assumes that emitter has been initialized with an
673 appropriate dictionary type, and will throw a TypeError if
674 not, so the caller is responsible for knowing that this is an
675 appropriate method to call for the Builder in question.
676 """
677 self.emitter[suffix] = emitter
678
680 """
681 Add a new Builder to the list of src_builders.
682
683 This requires wiping out cached values so that the computed
684 lists of source suffixes get re-calculated.
685 """
686 self._memo = {}
687 self.src_builder.append(builder)
688
690 """
691 Returns a dictionary mapping all of the source suffixes of all
692 src_builders of this Builder to the underlying Builder that
693 should be called first.
694
695 This dictionary is used for each target specified, so we save a
696 lot of extra computation by memoizing it for each construction
697 environment.
698
699 Note that this is re-computed each time, not cached, because there
700 might be changes to one of our source Builders (or one of their
701 source Builders, and so on, and so on...) that we can't "see."
702
703 The underlying methods we call cache their computed values,
704 though, so we hope repeatedly aggregating them into a dictionary
705 like this won't be too big a hit. We may need to look for a
706 better way to do this if performance data show this has turned
707 into a significant bottleneck.
708 """
709 sdict = {}
710 for bld in self.get_src_builders(env):
711 for suf in bld.src_suffixes(env):
712 sdict[suf] = bld
713 return sdict
714
728
729 result = []
730 for s in SCons.Util.flatten(source):
731 if SCons.Util.is_String(s):
732 match_suffix = match_src_suffix(env.subst(s))
733 if not match_suffix and not '.' in s:
734 src_suf = self.get_src_suffix(env)
735 s = self._adjustixes(s, None, src_suf)[0]
736 else:
737 match_suffix = match_src_suffix(s.name)
738 if match_suffix:
739 try:
740 bld = sdict[match_suffix]
741 except KeyError:
742 result.append(s)
743 else:
744 tlist = bld._execute(env, None, [s], overwarn)
745
746
747
748 if len(tlist) > 1:
749 tlist = [t for t in tlist if match_src_suffix(t.name)]
750 result.extend(tlist)
751 else:
752 result.append(s)
753
754 source_factory = env.get_factory(self.source_factory)
755
756 return env.arg2nodes(result, source_factory)
757
760
761 memoizer_counters.append(SCons.Memoize.CountDict('get_src_builders', _get_src_builders_key))
762
764 """
765 Returns the list of source Builders for this Builder.
766
767 This exists mainly to look up Builders referenced as
768 strings in the 'BUILDER' variable of the construction
769 environment and cache the result.
770 """
771 memo_key = id(env)
772 try:
773 memo_dict = self._memo['get_src_builders']
774 except KeyError:
775 memo_dict = {}
776 self._memo['get_src_builders'] = memo_dict
777 else:
778 try:
779 return memo_dict[memo_key]
780 except KeyError:
781 pass
782
783 builders = []
784 for bld in self.src_builder:
785 if SCons.Util.is_String(bld):
786 try:
787 bld = env['BUILDERS'][bld]
788 except KeyError:
789 continue
790 builders.append(bld)
791
792 memo_dict[memo_key] = builders
793 return builders
794
797
798 memoizer_counters.append(SCons.Memoize.CountDict('subst_src_suffixes', _subst_src_suffixes_key))
799
801 """
802 The suffix list may contain construction variable expansions,
803 so we have to evaluate the individual strings. To avoid doing
804 this over and over, we memoize the results for each construction
805 environment.
806 """
807 memo_key = id(env)
808 try:
809 memo_dict = self._memo['subst_src_suffixes']
810 except KeyError:
811 memo_dict = {}
812 self._memo['subst_src_suffixes'] = memo_dict
813 else:
814 try:
815 return memo_dict[memo_key]
816 except KeyError:
817 pass
818 suffixes = [env.subst(x) for x in self.src_suffix]
819 memo_dict[memo_key] = suffixes
820 return suffixes
821
823 """
824 Returns the list of source suffixes for all src_builders of this
825 Builder.
826
827 This is essentially a recursive descent of the src_builder "tree."
828 (This value isn't cached because there may be changes in a
829 src_builder many levels deep that we can't see.)
830 """
831 sdict = {}
832 suffixes = self.subst_src_suffixes(env)
833 for s in suffixes:
834 sdict[s] = 1
835 for builder in self.get_src_builders(env):
836 for s in builder.src_suffixes(env):
837 if s not in sdict:
838 sdict[s] = 1
839 suffixes.append(s)
840 return suffixes
841
843 """A Builder Proxy whose main purpose is to always have
844 a DictCmdGenerator as its action, and to provide access
845 to the DictCmdGenerator's add_action() method.
846 """
847
855
856 __call__ = SCons.Util.Delegate('__call__')
857
861
863 """"Returns True if the specified obj is one of our Builder classes.
864
865 The test is complicated a bit by the fact that CompositeBuilder
866 is a proxy, not a subclass of BuilderBase.
867 """
868 return (isinstance(obj, BuilderBase)
869 or isinstance(obj, CompositeBuilder)
870 or callable(obj))
871
872
873
874
875
876
877