1 """SCons.Environment
2
3 Base class for construction Environments. These are
4 the primary objects used to communicate dependency and
5 construction information to the build engine.
6
7 Keyword arguments supplied when the construction Environment
8 is created are construction variables used to initialize the
9 Environment
10 """
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 __revision__ = "src/engine/SCons/Environment.py 5110 2010/07/25 16:14:38 bdeegan"
36
37
38 import copy
39 import os
40 import sys
41 import re
42 import shlex
43 import string
44 from UserDict import UserDict
45
46 import SCons.Action
47 import SCons.Builder
48 from SCons.Debug import logInstanceCreation
49 import SCons.Defaults
50 import SCons.Errors
51 import SCons.Memoize
52 import SCons.Node
53 import SCons.Node.Alias
54 import SCons.Node.FS
55 import SCons.Node.Python
56 import SCons.Platform
57 import SCons.SConf
58 import SCons.SConsign
59 import SCons.Subst
60 import SCons.Tool
61 import SCons.Util
62 import SCons.Warnings
63
66
67 _null = _Null
68
69 _warn_copy_deprecated = True
70 _warn_source_signatures_deprecated = True
71 _warn_target_signatures_deprecated = True
72
73 CleanTargets = {}
74 CalculatorArgs = {}
75
76 semi_deepcopy = SCons.Util.semi_deepcopy
77
78
79
80
81 UserError = SCons.Errors.UserError
82
85
86 AliasBuilder = SCons.Builder.Builder(action = alias_builder,
87 target_factory = SCons.Node.Alias.default_ans.Alias,
88 source_factory = SCons.Node.FS.Entry,
89 multi = 1,
90 is_explicit = None,
91 name='AliasBuilder')
92
108
109
110
111
112 reserved_construction_var_names = [
113 'CHANGED_SOURCES',
114 'CHANGED_TARGETS',
115 'SOURCE',
116 'SOURCES',
117 'TARGET',
118 'TARGETS',
119 'UNCHANGED_SOURCES',
120 'UNCHANGED_TARGETS',
121 ]
122
123 future_reserved_construction_var_names = [
124
125
126
127 ]
128
137
141
146
159
163
167
169 """Delete duplicates from a sequence, keeping the first or last."""
170 seen={}
171 result=[]
172 if keep_last:
173 l.reverse()
174 for i in l:
175 try:
176 if not seen.has_key(i):
177 result.append(i)
178 seen[i]=1
179 except TypeError:
180
181 result.append(i)
182 if keep_last:
183 result.reverse()
184 return result
185
186
187
188
189
190
191
192
193
194
195
196
197
198
200 """
201 A generic Wrapper class that associates a method (which can
202 actually be any callable) with an object. As part of creating this
203 MethodWrapper object an attribute with the specified (by default,
204 the name of the supplied method) is added to the underlying object.
205 When that new "method" is called, our __call__() method adds the
206 object as the first argument, simulating the Python behavior of
207 supplying "self" on method calls.
208
209 We hang on to the name by which the method was added to the underlying
210 base class so that we can provide a method to "clone" ourselves onto
211 a new underlying object being copied (without which we wouldn't need
212 to save that info).
213 """
214 - def __init__(self, object, method, name=None):
215 if name is None:
216 name = method.__name__
217 self.object = object
218 self.method = method
219 self.name = name
220 setattr(self.object, name, self)
221
223 nargs = (self.object,) + args
224 return apply(self.method, nargs, kwargs)
225
226 - def clone(self, new_object):
227 """
228 Returns an object that re-binds the underlying "method" to
229 the specified new object.
230 """
231 return self.__class__(new_object, self.method, self.name)
232
234 """
235 A MethodWrapper subclass that that associates an environment with
236 a Builder.
237
238 This mainly exists to wrap the __call__() function so that all calls
239 to Builders can have their argument lists massaged in the same way
240 (treat a lone argument as the source, treat two arguments as target
241 then source, make sure both target and source are lists) without
242 having to have cut-and-paste code to do it.
243
244 As a bit of obsessive backwards compatibility, we also intercept
245 attempts to get or set the "env" or "builder" attributes, which were
246 the names we used before we put the common functionality into the
247 MethodWrapper base class. We'll keep this around for a while in case
248 people shipped Tool modules that reached into the wrapper (like the
249 Tool/qt.py module does, or did). There shouldn't be a lot attribute
250 fetching or setting on these, so a little extra work shouldn't hurt.
251 """
253 if source is _null:
254 source = target
255 target = None
256 if target is not None and not SCons.Util.is_List(target):
257 target = [target]
258 if source is not None and not SCons.Util.is_List(source):
259 source = [source]
260 return apply(MethodWrapper.__call__, (self, target, source) + args, kw)
261
263 return '<BuilderWrapper %s>' % repr(self.name)
264
267
269 if name == 'env':
270 return self.object
271 elif name == 'builder':
272 return self.method
273 else:
274 raise AttributeError, name
275
277 if name == 'env':
278 self.object = value
279 elif name == 'builder':
280 self.method = value
281 else:
282 self.__dict__[name] = value
283
284
285
286
287
288
289
290
291
292
293
294
296 """This is a dictionary-like class used by an Environment to hold
297 the Builders. We need to do this because every time someone changes
298 the Builders in the Environment's BUILDERS dictionary, we must
299 update the Environment's attributes."""
301
302
303
304 self.env = env
305 UserDict.__init__(self, dict)
306
308 return self.__class__(self.data, self.env)
309
311 try:
312 method = getattr(self.env, item).method
313 except AttributeError:
314 pass
315 else:
316 self.env.RemoveMethod(method)
317 UserDict.__setitem__(self, item, val)
318 BuilderWrapper(self.env, val, item)
319
321 UserDict.__delitem__(self, item)
322 delattr(self.env, item)
323
327
328
329
330 _is_valid_var = re.compile(r'[_a-zA-Z]\w*$')
331
333 """Return if the specified string is a legitimate construction
334 variable.
335 """
336 return _is_valid_var.match(varstr)
337
338
339
341 """Base class for different flavors of construction environments.
342
343 This class contains a minimal set of methods that handle contruction
344 variable expansion and conversion of strings to Nodes, which may or
345 may not be actually useful as a stand-alone class. Which methods
346 ended up in this class is pretty arbitrary right now. They're
347 basically the ones which we've empirically determined are common to
348 the different construction environment subclasses, and most of the
349 others that use or touch the underlying dictionary of construction
350 variables.
351
352 Eventually, this class should contain all the methods that we
353 determine are necessary for a "minimal" interface to the build engine.
354 A full "native Python" SCons environment has gotten pretty heavyweight
355 with all of the methods and Tools and construction variables we've
356 jammed in there, so it would be nice to have a lighter weight
357 alternative for interfaces that don't need all of the bells and
358 whistles. (At some point, we'll also probably rename this class
359 "Base," since that more reflects what we want this class to become,
360 but because we've released comments that tell people to subclass
361 Environment.Base to create their own flavors of construction
362 environment, we'll save that for a future refactoring when this
363 class actually becomes useful.)
364 """
365
366 if SCons.Memoize.use_memoizer:
367 __metaclass__ = SCons.Memoize.Memoized_Metaclass
368
379
380
399
401 return cmp(self._dict, other._dict)
402
404 special = self._special_del.get(key)
405 if special:
406 special(self, key)
407 else:
408 del self._dict[key]
409
411 return self._dict[key]
412
414
415
416
417
418
419
420
421
422
423
424
425
426 if key in self._special_set_keys:
427 self._special_set[key](self, key, value)
428 else:
429
430
431
432
433 if not self._dict.has_key(key) \
434 and not _is_valid_var.match(key):
435 raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
436 self._dict[key] = value
437
438 - def get(self, key, default=None):
439 """Emulates the get() method of dictionaries."""
440 return self._dict.get(key, default)
441
444
447
449 return self._dict.items()
450
452 if node_factory is _null:
453 node_factory = self.fs.File
454 if lookup_list is _null:
455 lookup_list = self.lookup_list
456
457 if not args:
458 return []
459
460 args = SCons.Util.flatten(args)
461
462 nodes = []
463 for v in args:
464 if SCons.Util.is_String(v):
465 n = None
466 for l in lookup_list:
467 n = l(v)
468 if n is not None:
469 break
470 if n is not None:
471 if SCons.Util.is_String(n):
472
473 kw['raw'] = 1
474 n = apply(self.subst, (n,), kw)
475 if node_factory:
476 n = node_factory(n)
477 if SCons.Util.is_List(n):
478 nodes.extend(n)
479 else:
480 nodes.append(n)
481 elif node_factory:
482
483 kw['raw'] = 1
484 v = node_factory(apply(self.subst, (v,), kw))
485 if SCons.Util.is_List(v):
486 nodes.extend(v)
487 else:
488 nodes.append(v)
489 else:
490 nodes.append(v)
491
492 return nodes
493
496
499
500 - def subst(self, string, raw=0, target=None, source=None, conv=None, executor=None):
501 """Recursively interpolates construction variables from the
502 Environment into the specified string, returning the expanded
503 result. Construction variables are specified by a $ prefix
504 in the string and begin with an initial underscore or
505 alphabetic character followed by any number of underscores
506 or alphanumeric characters. The construction variable names
507 may be surrounded by curly braces to separate the name from
508 trailing characters.
509 """
510 gvars = self.gvars()
511 lvars = self.lvars()
512 lvars['__env__'] = self
513 if executor:
514 lvars.update(executor.get_lvars())
515 return SCons.Subst.scons_subst(string, self, raw, target, source, gvars, lvars, conv)
516
517 - def subst_kw(self, kw, raw=0, target=None, source=None):
518 nkw = {}
519 for k, v in kw.items():
520 k = self.subst(k, raw, target, source)
521 if SCons.Util.is_String(v):
522 v = self.subst(v, raw, target, source)
523 nkw[k] = v
524 return nkw
525
526 - def subst_list(self, string, raw=0, target=None, source=None, conv=None, executor=None):
535
536 - def subst_path(self, path, target=None, source=None):
537 """Substitute a path list, turning EntryProxies into Nodes
538 and leaving Nodes (and other objects) as-is."""
539
540 if not SCons.Util.is_List(path):
541 path = [path]
542
543 def s(obj):
544 """This is the "string conversion" routine that we have our
545 substitutions use to return Nodes, not strings. This relies
546 on the fact that an EntryProxy object has a get() method that
547 returns the underlying Node that it wraps, which is a bit of
548 architectural dependence that we might need to break or modify
549 in the future in response to additional requirements."""
550 try:
551 get = obj.get
552 except AttributeError:
553 obj = SCons.Util.to_String_for_subst(obj)
554 else:
555 obj = get()
556 return obj
557
558 r = []
559 for p in path:
560 if SCons.Util.is_String(p):
561 p = self.subst(p, target=target, source=source, conv=s)
562 if SCons.Util.is_List(p):
563 if len(p) == 1:
564 p = p[0]
565 else:
566
567
568
569 p = string.join(map(SCons.Util.to_String_for_subst, p), '')
570 else:
571 p = s(p)
572 r.append(p)
573 return r
574
575 subst_target_source = subst
576
578 import subprocess
579
580 kw = { 'stdin' : 'devnull',
581 'stdout' : subprocess.PIPE,
582 'stderr' : subprocess.PIPE,
583 'universal_newlines' : True,
584 }
585
586
587 if not SCons.Util.is_List(command): kw['shell'] = True
588
589
590 p = apply(SCons.Action._subproc, (self, command), kw)
591 out,err = p.communicate()
592 status = p.wait()
593 if err:
594 sys.stderr.write(err)
595 if status:
596 raise OSError("'%s' exited %d" % (command, status))
597 return out
598
600 """
601 Adds the specified function as a method of this construction
602 environment with the specified name. If the name is omitted,
603 the default name is the name of the function itself.
604 """
605 method = MethodWrapper(self, function, name)
606 self.added_methods.append(method)
607
609 """
610 Removes the specified function's MethodWrapper from the
611 added_methods list, so we don't re-bind it when making a clone.
612 """
613 is_not_func = lambda dm, f=function: not dm.method is f
614 self.added_methods = filter(is_not_func, self.added_methods)
615
617 """
618 Produce a modified environment whose variables are overriden by
619 the overrides dictionaries. "overrides" is a dictionary that
620 will override the variables of this environment.
621
622 This function is much more efficient than Clone() or creating
623 a new Environment because it doesn't copy the construction
624 environment dictionary, it just wraps the underlying construction
625 environment, and doesn't even create a wrapper object if there
626 are no overrides.
627 """
628 if not overrides: return self
629 o = copy_non_reserved_keywords(overrides)
630 if not o: return self
631 overrides = {}
632 merges = None
633 for key, value in o.items():
634 if key == 'parse_flags':
635 merges = value
636 else:
637 overrides[key] = SCons.Subst.scons_subst_once(value, self, key)
638 env = OverrideEnvironment(self, overrides)
639 if merges: env.MergeFlags(merges)
640 return env
641
643 """
644 Parse the set of flags and return a dict with the flags placed
645 in the appropriate entry. The flags are treated as a typical
646 set of command-line flags for a GNU-like toolchain and used to
647 populate the entries in the dict immediately below. If one of
648 the flag strings begins with a bang (exclamation mark), it is
649 assumed to be a command and the rest of the string is executed;
650 the result of that evaluation is then added to the dict.
651 """
652 dict = {
653 'ASFLAGS' : SCons.Util.CLVar(''),
654 'CFLAGS' : SCons.Util.CLVar(''),
655 'CCFLAGS' : SCons.Util.CLVar(''),
656 'CPPDEFINES' : [],
657 'CPPFLAGS' : SCons.Util.CLVar(''),
658 'CPPPATH' : [],
659 'FRAMEWORKPATH' : SCons.Util.CLVar(''),
660 'FRAMEWORKS' : SCons.Util.CLVar(''),
661 'LIBPATH' : [],
662 'LIBS' : [],
663 'LINKFLAGS' : SCons.Util.CLVar(''),
664 'RPATH' : [],
665 }
666
667
668
669 def do_parse(arg, me, self = self, dict = dict):
670
671 if not arg:
672 return
673
674 if not SCons.Util.is_String(arg):
675 for t in arg: me(t, me)
676 return
677
678
679 if arg[0] == '!':
680 arg = self.backtick(arg[1:])
681
682
683 def append_define(name, dict = dict):
684 t = string.split(name, '=')
685 if len(t) == 1:
686 dict['CPPDEFINES'].append(name)
687 else:
688 dict['CPPDEFINES'].append([t[0], string.join(t[1:], '=')])
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710 params = shlex.split(arg)
711 append_next_arg_to = None
712 for arg in params:
713 if append_next_arg_to:
714 if append_next_arg_to == 'CPPDEFINES':
715 append_define(arg)
716 elif append_next_arg_to == '-include':
717 t = ('-include', self.fs.File(arg))
718 dict['CCFLAGS'].append(t)
719 elif append_next_arg_to == '-isysroot':
720 t = ('-isysroot', arg)
721 dict['CCFLAGS'].append(t)
722 dict['LINKFLAGS'].append(t)
723 elif append_next_arg_to == '-arch':
724 t = ('-arch', arg)
725 dict['CCFLAGS'].append(t)
726 dict['LINKFLAGS'].append(t)
727 else:
728 dict[append_next_arg_to].append(arg)
729 append_next_arg_to = None
730 elif not arg[0] in ['-', '+']:
731 dict['LIBS'].append(self.fs.File(arg))
732 elif arg[:2] == '-L':
733 if arg[2:]:
734 dict['LIBPATH'].append(arg[2:])
735 else:
736 append_next_arg_to = 'LIBPATH'
737 elif arg[:2] == '-l':
738 if arg[2:]:
739 dict['LIBS'].append(arg[2:])
740 else:
741 append_next_arg_to = 'LIBS'
742 elif arg[:2] == '-I':
743 if arg[2:]:
744 dict['CPPPATH'].append(arg[2:])
745 else:
746 append_next_arg_to = 'CPPPATH'
747 elif arg[:4] == '-Wa,':
748 dict['ASFLAGS'].append(arg[4:])
749 dict['CCFLAGS'].append(arg)
750 elif arg[:4] == '-Wl,':
751 if arg[:11] == '-Wl,-rpath=':
752 dict['RPATH'].append(arg[11:])
753 elif arg[:7] == '-Wl,-R,':
754 dict['RPATH'].append(arg[7:])
755 elif arg[:6] == '-Wl,-R':
756 dict['RPATH'].append(arg[6:])
757 else:
758 dict['LINKFLAGS'].append(arg)
759 elif arg[:4] == '-Wp,':
760 dict['CPPFLAGS'].append(arg)
761 elif arg[:2] == '-D':
762 if arg[2:]:
763 append_define(arg[2:])
764 else:
765 append_next_arg_to = 'CPPDEFINES'
766 elif arg == '-framework':
767 append_next_arg_to = 'FRAMEWORKS'
768 elif arg[:14] == '-frameworkdir=':
769 dict['FRAMEWORKPATH'].append(arg[14:])
770 elif arg[:2] == '-F':
771 if arg[2:]:
772 dict['FRAMEWORKPATH'].append(arg[2:])
773 else:
774 append_next_arg_to = 'FRAMEWORKPATH'
775 elif arg == '-mno-cygwin':
776 dict['CCFLAGS'].append(arg)
777 dict['LINKFLAGS'].append(arg)
778 elif arg == '-mwindows':
779 dict['LINKFLAGS'].append(arg)
780 elif arg == '-pthread':
781 dict['CCFLAGS'].append(arg)
782 dict['LINKFLAGS'].append(arg)
783 elif arg[:5] == '-std=':
784 dict['CFLAGS'].append(arg)
785 elif arg[0] == '+':
786 dict['CCFLAGS'].append(arg)
787 dict['LINKFLAGS'].append(arg)
788 elif arg in ['-include', '-isysroot', '-arch']:
789 append_next_arg_to = arg
790 else:
791 dict['CCFLAGS'].append(arg)
792
793 for arg in flags:
794 do_parse(arg, do_parse)
795 return dict
796
798 """
799 Merge the dict in args into the construction variables of this
800 env, or the passed-in dict. If args is not a dict, it is
801 converted into a dict using ParseFlags. If unique is not set,
802 the flags are appended rather than merged.
803 """
804
805 if dict is None:
806 dict = self
807 if not SCons.Util.is_Dict(args):
808 args = self.ParseFlags(args)
809 if not unique:
810 apply(self.Append, (), args)
811 return self
812 for key, value in args.items():
813 if not value:
814 continue
815 try:
816 orig = self[key]
817 except KeyError:
818 orig = value
819 else:
820 if not orig:
821 orig = value
822 elif value:
823
824
825
826
827
828
829 try:
830 orig = orig + value
831 except (KeyError, TypeError):
832 try:
833 add_to_orig = orig.append
834 except AttributeError:
835 value.insert(0, orig)
836 orig = value
837 else:
838 add_to_orig(value)
839 t = []
840 if key[-4:] == 'PATH':
841
842 for v in orig:
843 if v not in t:
844 t.append(v)
845 else:
846
847 orig.reverse()
848 for v in orig:
849 if v not in t:
850 t.insert(0, v)
851 self[key] = t
852 return self
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
884
888
892
894 f = SCons.Defaults.DefaultEnvironment().copy_from_cache
895 return f(src, dst)
896
897 -class Base(SubstitutionEnvironment):
898 """Base class for "real" construction Environments. These are the
899 primary objects used to communicate dependency and construction
900 information to the build engine.
901
902 Keyword arguments supplied when the construction Environment
903 is created are construction variables used to initialize the
904 Environment.
905 """
906
907 memoizer_counters = []
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923 - def __init__(self,
924 platform=None,
925 tools=None,
926 toolpath=None,
927 variables=None,
928 parse_flags = None,
929 **kw):
930 """
931 Initialization of a basic SCons construction environment,
932 including setting up special construction variables like BUILDER,
933 PLATFORM, etc., and searching for and applying available Tools.
934
935 Note that we do *not* call the underlying base class
936 (SubsitutionEnvironment) initialization, because we need to
937 initialize things in a very specific order that doesn't work
938 with the much simpler base class initialization.
939 """
940 if __debug__: logInstanceCreation(self, 'Environment.Base')
941 self._memo = {}
942 self.fs = SCons.Node.FS.get_default_fs()
943 self.ans = SCons.Node.Alias.default_ans
944 self.lookup_list = SCons.Node.arg2nodes_lookups
945 self._dict = semi_deepcopy(SCons.Defaults.ConstructionEnvironment)
946 self._init_special()
947 self.added_methods = []
948
949
950
951
952
953
954
955 self.decide_target = default_decide_target
956 self.decide_source = default_decide_source
957
958 self.copy_from_cache = default_copy_from_cache
959
960 self._dict['BUILDERS'] = BuilderDict(self._dict['BUILDERS'], self)
961
962 if platform is None:
963 platform = self._dict.get('PLATFORM', None)
964 if platform is None:
965 platform = SCons.Platform.Platform()
966 if SCons.Util.is_String(platform):
967 platform = SCons.Platform.Platform(platform)
968 self._dict['PLATFORM'] = str(platform)
969 platform(self)
970
971 self._dict['HOST_OS'] = self._dict.get('HOST_OS',None)
972 self._dict['HOST_ARCH'] = self._dict.get('HOST_ARCH',None)
973
974
975
976
977 if kw.has_key('options'):
978
979
980 variables = kw['options']
981 del kw['options']
982 apply(self.Replace, (), kw)
983 keys = kw.keys()
984 if variables:
985 keys = keys + variables.keys()
986 variables.Update(self)
987
988 save = {}
989 for k in keys:
990 try:
991 save[k] = self._dict[k]
992 except KeyError:
993
994
995 pass
996
997 SCons.Tool.Initializers(self)
998
999 if tools is None:
1000 tools = self._dict.get('TOOLS', None)
1001 if tools is None:
1002 tools = ['default']
1003 apply_tools(self, tools, toolpath)
1004
1005
1006
1007
1008 self._dict['TARGET_OS'] = self._dict.get('HOST_OS',None)
1009
1010
1011
1012
1013
1014
1015 for key, val in save.items():
1016 self._dict[key] = val
1017
1018
1019 if parse_flags: self.MergeFlags(parse_flags)
1020
1021
1022
1023
1024
1025
1027 """Fetch the builder with the specified name from the environment.
1028 """
1029 try:
1030 return self._dict['BUILDERS'][name]
1031 except KeyError:
1032 return None
1033
1035 try:
1036 path = self._CacheDir_path
1037 except AttributeError:
1038 path = SCons.Defaults.DefaultEnvironment()._CacheDir_path
1039 try:
1040 if path == self._last_CacheDir_path:
1041 return self._last_CacheDir
1042 except AttributeError:
1043 pass
1044 cd = SCons.CacheDir.CacheDir(path)
1045 self._last_CacheDir_path = path
1046 self._last_CacheDir = cd
1047 return cd
1048
1050 """Return a factory function for creating Nodes for this
1051 construction environment.
1052 """
1053 name = default
1054 try:
1055 is_node = issubclass(factory, SCons.Node.FS.Base)
1056 except TypeError:
1057
1058
1059 pass
1060 else:
1061 if is_node:
1062
1063
1064
1065
1066 try: name = factory.__name__
1067 except AttributeError: pass
1068 else: factory = None
1069 if not factory:
1070
1071
1072
1073
1074
1075 factory = getattr(self.fs, name)
1076 return factory
1077
1078 memoizer_counters.append(SCons.Memoize.CountValue('_gsm'))
1079
1081 try:
1082 return self._memo['_gsm']
1083 except KeyError:
1084 pass
1085
1086 result = {}
1087
1088 try:
1089 scanners = self._dict['SCANNERS']
1090 except KeyError:
1091 pass
1092 else:
1093
1094
1095
1096
1097 if not SCons.Util.is_List(scanners):
1098 scanners = [scanners]
1099 else:
1100 scanners = scanners[:]
1101 scanners.reverse()
1102 for scanner in scanners:
1103 for k in scanner.get_skeys(self):
1104 if k and self['PLATFORM'] == 'win32':
1105 k = string.lower(k)
1106 result[k] = scanner
1107
1108 self._memo['_gsm'] = result
1109
1110 return result
1111
1113 """Find the appropriate scanner given a key (usually a file suffix).
1114 """
1115 if skey and self['PLATFORM'] == 'win32':
1116 skey = string.lower(skey)
1117 return self._gsm().get(skey)
1118
1120 """Delete the cached scanner map (if we need to).
1121 """
1122 try:
1123 del self._memo['_gsm']
1124 except KeyError:
1125 pass
1126
1128 """Update an environment's values directly, bypassing the normal
1129 checks that occur when users try to set items.
1130 """
1131 self._dict.update(dict)
1132
1134 try:
1135 return self.src_sig_type
1136 except AttributeError:
1137 t = SCons.Defaults.DefaultEnvironment().src_sig_type
1138 self.src_sig_type = t
1139 return t
1140
1142 try:
1143 return self.tgt_sig_type
1144 except AttributeError:
1145 t = SCons.Defaults.DefaultEnvironment().tgt_sig_type
1146 self.tgt_sig_type = t
1147 return t
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1159 """Append values to existing construction variables
1160 in an Environment.
1161 """
1162 kw = copy_non_reserved_keywords(kw)
1163 for key, val in kw.items():
1164
1165
1166
1167
1168 try:
1169 orig = self._dict[key]
1170 except KeyError:
1171
1172
1173 self._dict[key] = val
1174 else:
1175 try:
1176
1177
1178
1179
1180
1181 update_dict = orig.update
1182 except AttributeError:
1183 try:
1184
1185
1186
1187 self._dict[key] = orig + val
1188 except (KeyError, TypeError):
1189 try:
1190
1191 add_to_orig = orig.append
1192 except AttributeError:
1193
1194
1195
1196
1197
1198 if orig:
1199 val.insert(0, orig)
1200 self._dict[key] = val
1201 else:
1202
1203
1204 if val:
1205 add_to_orig(val)
1206 else:
1207
1208
1209 if SCons.Util.is_List(val):
1210 for v in val:
1211 orig[v] = None
1212 else:
1213 try:
1214 update_dict(val)
1215 except (AttributeError, TypeError, ValueError):
1216 if SCons.Util.is_Dict(val):
1217 for k, v in val.items():
1218 orig[k] = v
1219 else:
1220 orig[val] = None
1221 self.scanner_map_delete(kw)
1222
1223
1224
1231
1232 - def AppendENVPath(self, name, newpath, envname = 'ENV',
1233 sep = os.pathsep, delete_existing=1):
1234 """Append path elements to the path 'name' in the 'ENV'
1235 dictionary for this environment. Will only add any particular
1236 path once, and will normpath and normcase all paths to help
1237 assure this. This can also handle the case where the env
1238 variable is a list instead of a string.
1239
1240 If delete_existing is 0, a newpath which is already in the path
1241 will not be moved to the end (it will be left where it is).
1242 """
1243
1244 orig = ''
1245 if self._dict.has_key(envname) and self._dict[envname].has_key(name):
1246 orig = self._dict[envname][name]
1247
1248 nv = SCons.Util.AppendPath(orig, newpath, sep, delete_existing,
1249 canonicalize=self._canonicalize)
1250
1251 if not self._dict.has_key(envname):
1252 self._dict[envname] = {}
1253
1254 self._dict[envname][name] = nv
1255
1257 """Append values to existing construction variables
1258 in an Environment, if they're not already there.
1259 If delete_existing is 1, removes existing values first, so
1260 values move to end.
1261 """
1262 kw = copy_non_reserved_keywords(kw)
1263 for key, val in kw.items():
1264 if SCons.Util.is_List(val):
1265 val = _delete_duplicates(val, delete_existing)
1266 if not self._dict.has_key(key) or self._dict[key] in ('', None):
1267 self._dict[key] = val
1268 elif SCons.Util.is_Dict(self._dict[key]) and \
1269 SCons.Util.is_Dict(val):
1270 self._dict[key].update(val)
1271 elif SCons.Util.is_List(val):
1272 dk = self._dict[key]
1273 if not SCons.Util.is_List(dk):
1274 dk = [dk]
1275 if delete_existing:
1276 dk = filter(lambda x, val=val: x not in val, dk)
1277 else:
1278 val = filter(lambda x, dk=dk: x not in dk, val)
1279 self._dict[key] = dk + val
1280 else:
1281 dk = self._dict[key]
1282 if SCons.Util.is_List(dk):
1283
1284
1285 if delete_existing:
1286 dk = filter(lambda x, val=val: x not in val, dk)
1287 self._dict[key] = dk + [val]
1288 else:
1289 if not val in dk:
1290 self._dict[key] = dk + [val]
1291 else:
1292 if delete_existing:
1293 dk = filter(lambda x, val=val: x not in val, dk)
1294 self._dict[key] = dk + val
1295 self.scanner_map_delete(kw)
1296
1297 - def Clone(self, tools=[], toolpath=None, parse_flags = None, **kw):
1298 """Return a copy of a construction Environment. The
1299 copy is like a Python "deep copy"--that is, independent
1300 copies are made recursively of each objects--except that
1301 a reference is copied when an object is not deep-copyable
1302 (like a function). There are no references to any mutable
1303 objects in the original Environment.
1304 """
1305 clone = copy.copy(self)
1306 clone._dict = semi_deepcopy(self._dict)
1307
1308 try:
1309 cbd = clone._dict['BUILDERS']
1310 except KeyError:
1311 pass
1312 else:
1313 clone._dict['BUILDERS'] = BuilderDict(cbd, clone)
1314
1315
1316
1317
1318
1319 clone.added_methods = []
1320 for mw in self.added_methods:
1321 if mw == getattr(self, mw.name):
1322 clone.added_methods.append(mw.clone(clone))
1323
1324 clone._memo = {}
1325
1326
1327
1328 kw = copy_non_reserved_keywords(kw)
1329 new = {}
1330 for key, value in kw.items():
1331 new[key] = SCons.Subst.scons_subst_once(value, self, key)
1332 apply(clone.Replace, (), new)
1333
1334 apply_tools(clone, tools, toolpath)
1335
1336
1337 apply(clone.Replace, (), new)
1338
1339
1340 if parse_flags: clone.MergeFlags(parse_flags)
1341
1342 if __debug__: logInstanceCreation(self, 'Environment.EnvironmentClone')
1343 return clone
1344
1345 - def Copy(self, *args, **kw):
1352
1357
1358 - def _changed_content(self, dependency, target, prev_ni):
1359 return dependency.changed_content(target, prev_ni)
1360
1368
1369 - def _changed_timestamp_then_content(self, dependency, target, prev_ni):
1370 return dependency.changed_timestamp_then_content(target, prev_ni)
1371
1374
1377
1379 return self.fs.copy(src, dst)
1380
1382 return self.fs.copy2(src, dst)
1383
1407
1409 """Return the first available program in progs.
1410 """
1411 if not SCons.Util.is_List(progs):
1412 progs = [ progs ]
1413 for prog in progs:
1414 path = self.WhereIs(prog)
1415 if path: return prog
1416 return None
1417
1419 if not args:
1420 return self._dict
1421 dlist = map(lambda x, s=self: s._dict[x], args)
1422 if len(dlist) == 1:
1423 dlist = dlist[0]
1424 return dlist
1425
1426 - def Dump(self, key = None):
1427 """
1428 Using the standard Python pretty printer, dump the contents of the
1429 scons build environment to stdout.
1430
1431 If the key passed in is anything other than None, then that will
1432 be used as an index into the build environment dictionary and
1433 whatever is found there will be fed into the pretty printer. Note
1434 that this key is case sensitive.
1435 """
1436 import pprint
1437 pp = pprint.PrettyPrinter(indent=2)
1438 if key:
1439 dict = self.Dictionary(key)
1440 else:
1441 dict = self.Dictionary()
1442 return pp.pformat(dict)
1443
1444 - def FindIxes(self, paths, prefix, suffix):
1445 """
1446 Search a list of paths for something that matches the prefix and suffix.
1447
1448 paths - the list of paths or nodes.
1449 prefix - construction variable for the prefix.
1450 suffix - construction variable for the suffix.
1451 """
1452
1453 suffix = self.subst('$'+suffix)
1454 prefix = self.subst('$'+prefix)
1455
1456 for path in paths:
1457 dir,name = os.path.split(str(path))
1458 if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix:
1459 return path
1460
1461 - def ParseConfig(self, command, function=None, unique=1):
1462 """
1463 Use the specified function to parse the output of the command
1464 in order to modify the current environment. The 'command' can
1465 be a string or a list of strings representing a command and
1466 its arguments. 'Function' is an optional argument that takes
1467 the environment, the output of the command, and the unique flag.
1468 If no function is specified, MergeFlags, which treats the output
1469 as the result of a typical 'X-config' command (i.e. gtk-config),
1470 will merge the output into the appropriate variables.
1471 """
1472 if function is None:
1473 def parse_conf(env, cmd, unique=unique):
1474 return env.MergeFlags(cmd, unique)
1475 function = parse_conf
1476 if SCons.Util.is_List(command):
1477 command = string.join(command)
1478 command = self.subst(command)
1479 return function(self, self.backtick(command))
1480
1481 - def ParseDepends(self, filename, must_exist=None, only_one=0):
1482 """
1483 Parse a mkdep-style file for explicit dependencies. This is
1484 completely abusable, and should be unnecessary in the "normal"
1485 case of proper SCons configuration, but it may help make
1486 the transition from a Make hierarchy easier for some people
1487 to swallow. It can also be genuinely useful when using a tool
1488 that can write a .d file, but for which writing a scanner would
1489 be too complicated.
1490 """
1491 filename = self.subst(filename)
1492 try:
1493 fp = open(filename, 'r')
1494 except IOError:
1495 if must_exist:
1496 raise
1497 return
1498 lines = SCons.Util.LogicalLines(fp).readlines()
1499 lines = filter(lambda l: l[0] != '#', lines)
1500 tdlist = []
1501 for line in lines:
1502 try:
1503 target, depends = string.split(line, ':', 1)
1504 except (AttributeError, TypeError, ValueError):
1505
1506
1507
1508
1509 pass
1510 else:
1511 tdlist.append((string.split(target), string.split(depends)))
1512 if only_one:
1513 targets = reduce(lambda x, y: x+y, map(lambda p: p[0], tdlist))
1514 if len(targets) > 1:
1515 raise SCons.Errors.UserError, "More than one dependency target found in `%s': %s" % (filename, targets)
1516 for target, depends in tdlist:
1517 self.Depends(target, depends)
1518
1522
1524 """Prepend values to existing construction variables
1525 in an Environment.
1526 """
1527 kw = copy_non_reserved_keywords(kw)
1528 for key, val in kw.items():
1529
1530
1531
1532
1533 try:
1534 orig = self._dict[key]
1535 except KeyError:
1536
1537
1538 self._dict[key] = val
1539 else:
1540 try:
1541
1542
1543
1544
1545
1546 update_dict = orig.update
1547 except AttributeError:
1548 try:
1549
1550
1551
1552 self._dict[key] = val + orig
1553 except (KeyError, TypeError):
1554 try:
1555
1556 add_to_val = val.append
1557 except AttributeError:
1558
1559
1560
1561
1562 if val:
1563 orig.insert(0, val)
1564 else:
1565
1566
1567
1568 if orig:
1569 add_to_val(orig)
1570 self._dict[key] = val
1571 else:
1572
1573
1574 if SCons.Util.is_List(val):
1575 for v in val:
1576 orig[v] = None
1577 else:
1578 try:
1579 update_dict(val)
1580 except (AttributeError, TypeError, ValueError):
1581 if SCons.Util.is_Dict(val):
1582 for k, v in val.items():
1583 orig[k] = v
1584 else:
1585 orig[val] = None
1586 self.scanner_map_delete(kw)
1587
1588 - def PrependENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep,
1589 delete_existing=1):
1590 """Prepend path elements to the path 'name' in the 'ENV'
1591 dictionary for this environment. Will only add any particular
1592 path once, and will normpath and normcase all paths to help
1593 assure this. This can also handle the case where the env
1594 variable is a list instead of a string.
1595
1596 If delete_existing is 0, a newpath which is already in the path
1597 will not be moved to the front (it will be left where it is).
1598 """
1599
1600 orig = ''
1601 if self._dict.has_key(envname) and self._dict[envname].has_key(name):
1602 orig = self._dict[envname][name]
1603
1604 nv = SCons.Util.PrependPath(orig, newpath, sep, delete_existing,
1605 canonicalize=self._canonicalize)
1606
1607 if not self._dict.has_key(envname):
1608 self._dict[envname] = {}
1609
1610 self._dict[envname][name] = nv
1611
1613 """Prepend values to existing construction variables
1614 in an Environment, if they're not already there.
1615 If delete_existing is 1, removes existing values first, so
1616 values move to front.
1617 """
1618 kw = copy_non_reserved_keywords(kw)
1619 for key, val in kw.items():
1620 if SCons.Util.is_List(val):
1621 val = _delete_duplicates(val, not delete_existing)
1622 if not self._dict.has_key(key) or self._dict[key] in ('', None):
1623 self._dict[key] = val
1624 elif SCons.Util.is_Dict(self._dict[key]) and \
1625 SCons.Util.is_Dict(val):
1626 self._dict[key].update(val)
1627 elif SCons.Util.is_List(val):
1628 dk = self._dict[key]
1629 if not SCons.Util.is_List(dk):
1630 dk = [dk]
1631 if delete_existing:
1632 dk = filter(lambda x, val=val: x not in val, dk)
1633 else:
1634 val = filter(lambda x, dk=dk: x not in dk, val)
1635 self._dict[key] = val + dk
1636 else:
1637 dk = self._dict[key]
1638 if SCons.Util.is_List(dk):
1639
1640
1641 if delete_existing:
1642 dk = filter(lambda x, val=val: x not in val, dk)
1643 self._dict[key] = [val] + dk
1644 else:
1645 if not val in dk:
1646 self._dict[key] = [val] + dk
1647 else:
1648 if delete_existing:
1649 dk = filter(lambda x, val=val: x not in val, dk)
1650 self._dict[key] = val + dk
1651 self.scanner_map_delete(kw)
1652
1654 """Replace existing construction variables in an Environment
1655 with new construction variables and/or values.
1656 """
1657 try:
1658 kwbd = kw['BUILDERS']
1659 except KeyError:
1660 pass
1661 else:
1662 kwbd = semi_deepcopy(kwbd)
1663 del kw['BUILDERS']
1664 self.__setitem__('BUILDERS', kwbd)
1665 kw = copy_non_reserved_keywords(kw)
1666 self._update(semi_deepcopy(kw))
1667 self.scanner_map_delete(kw)
1668
1669 - def ReplaceIxes(self, path, old_prefix, old_suffix, new_prefix, new_suffix):
1670 """
1671 Replace old_prefix with new_prefix and old_suffix with new_suffix.
1672
1673 env - Environment used to interpolate variables.
1674 path - the path that will be modified.
1675 old_prefix - construction variable for the old prefix.
1676 old_suffix - construction variable for the old suffix.
1677 new_prefix - construction variable for the new prefix.
1678 new_suffix - construction variable for the new suffix.
1679 """
1680 old_prefix = self.subst('$'+old_prefix)
1681 old_suffix = self.subst('$'+old_suffix)
1682
1683 new_prefix = self.subst('$'+new_prefix)
1684 new_suffix = self.subst('$'+new_suffix)
1685
1686 dir,name = os.path.split(str(path))
1687 if name[:len(old_prefix)] == old_prefix:
1688 name = name[len(old_prefix):]
1689 if name[-len(old_suffix):] == old_suffix:
1690 name = name[:-len(old_suffix)]
1691 return os.path.join(dir, new_prefix+name+new_suffix)
1692
1694 for k in kw.keys():
1695 if self._dict.has_key(k):
1696 del kw[k]
1697 apply(self.Replace, (), kw)
1698
1701
1710
1711 - def WhereIs(self, prog, path=None, pathext=None, reject=[]):
1712 """Find prog in the path.
1713 """
1714 if path is None:
1715 try:
1716 path = self['ENV']['PATH']
1717 except KeyError:
1718 pass
1719 elif SCons.Util.is_String(path):
1720 path = self.subst(path)
1721 if pathext is None:
1722 try:
1723 pathext = self['ENV']['PATHEXT']
1724 except KeyError:
1725 pass
1726 elif SCons.Util.is_String(pathext):
1727 pathext = self.subst(pathext)
1728 prog = self.subst(prog)
1729 path = SCons.Util.WhereIs(prog, path, pathext, reject)
1730 if path: return path
1731 return None
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741 - def Action(self, *args, **kw):
1746 nargs = map(subst_string, args)
1747 nkw = self.subst_kw(kw)
1748 return apply(SCons.Action.Action, nargs, nkw)
1749
1759
1760 - def AddPostAction(self, files, action):
1761 nodes = self.arg2nodes(files, self.fs.Entry)
1762 action = SCons.Action.Action(action)
1763 uniq = {}
1764 for executor in map(lambda n: n.get_executor(), nodes):
1765 uniq[executor] = 1
1766 for executor in uniq.keys():
1767 executor.add_post_action(action)
1768 return nodes
1769
1770 - def Alias(self, target, source=[], action=None, **kw):
1771 tlist = self.arg2nodes(target, self.ans.Alias)
1772 if not SCons.Util.is_List(source):
1773 source = [source]
1774 source = filter(None, source)
1775
1776 if not action:
1777 if not source:
1778
1779
1780
1781
1782
1783
1784 return tlist
1785
1786
1787
1788 result = []
1789 for t in tlist:
1790 bld = t.get_builder(AliasBuilder)
1791 result.extend(bld(self, t, source))
1792 return result
1793
1794 nkw = self.subst_kw(kw)
1795 nkw.update({
1796 'action' : SCons.Action.Action(action),
1797 'source_factory' : self.fs.Entry,
1798 'multi' : 1,
1799 'is_explicit' : None,
1800 })
1801 bld = apply(SCons.Builder.Builder, (), nkw)
1802
1803
1804
1805
1806
1807 result = []
1808 for t in tlist:
1809
1810
1811
1812
1813 b = t.get_builder()
1814 if b is None or b is AliasBuilder:
1815 b = bld
1816 else:
1817 nkw['action'] = b.action + action
1818 b = apply(SCons.Builder.Builder, (), nkw)
1819 t.convert()
1820 result.extend(b(self, t, t.sources + source))
1821 return result
1822
1830
1832 if kw.has_key('build_dir'):
1833 kw['variant_dir'] = kw['build_dir']
1834 del kw['build_dir']
1835 return apply(self.VariantDir, args, kw)
1836
1840
1846
1847 - def Clean(self, targets, files):
1856
1868
1869 - def Command(self, target, source, action, **kw):
1870 """Builds the supplied target files from the supplied
1871 source files using the supplied action. Action may
1872 be any type that the Builder constructor will accept
1873 for an action."""
1874 bkw = {
1875 'action' : action,
1876 'target_factory' : self.fs.Entry,
1877 'source_factory' : self.fs.Entry,
1878 }
1879 try: bkw['source_scanner'] = kw['source_scanner']
1880 except KeyError: pass
1881 else: del kw['source_scanner']
1882 bld = apply(SCons.Builder.Builder, (), bkw)
1883 return apply(bld, (self, target, source), kw)
1884
1885 - def Depends(self, target, dependency):
1886 """Explicity specify that 'target's depend on 'dependency'."""
1887 tlist = self.arg2nodes(target, self.fs.Entry)
1888 dlist = self.arg2nodes(dependency, self.fs.Entry)
1889 for t in tlist:
1890 t.add_dependency(dlist)
1891 return tlist
1892
1893 - def Dir(self, name, *args, **kw):
1903
1905 """Tags a target so that it will not be cleaned by -c"""
1906 tlist = []
1907 for t in targets:
1908 tlist.extend(self.arg2nodes(t, self.fs.Entry))
1909 for t in tlist:
1910 t.set_noclean()
1911 return tlist
1912
1914 """Tags a target so that it will not be cached"""
1915 tlist = []
1916 for t in targets:
1917 tlist.extend(self.arg2nodes(t, self.fs.Entry))
1918 for t in tlist:
1919 t.set_nocache()
1920 return tlist
1921
1922 - def Entry(self, name, *args, **kw):
1923 """
1924 """
1925 s = self.subst(name)
1926 if SCons.Util.is_Sequence(s):
1927 result=[]
1928 for e in s:
1929 result.append(apply(self.fs.Entry, (e,) + args, kw))
1930 return result
1931 return apply(self.fs.Entry, (s,) + args, kw)
1932
1935
1936 - def Execute(self, action, *args, **kw):
1937 """Directly execute an action through an Environment
1938 """
1939 action = apply(self.Action, (action,) + args, kw)
1940 result = action([], [], self)
1941 if isinstance(result, SCons.Errors.BuildError):
1942 errstr = result.errstr
1943 if result.filename:
1944 errstr = result.filename + ': ' + errstr
1945 sys.stderr.write("scons: *** %s\n" % errstr)
1946 return result.status
1947 else:
1948 return result
1949
1950 - def File(self, name, *args, **kw):
1960
1965
1968
1975
1977 return self.fs.Glob(self.subst(pattern), ondisk, source, strings)
1978
1979 - def Ignore(self, target, dependency):
1986
1989
1990 - def Local(self, *targets):
2001
2009
2013
2014 - def Requires(self, target, prerequisite):
2015 """Specify that 'prerequisite' must be built before 'target',
2016 (but 'target' does not actually depend on 'prerequisite'
2017 and need not be rebuilt if it changes)."""
2018 tlist = self.arg2nodes(target, self.fs.Entry)
2019 plist = self.arg2nodes(prerequisite, self.fs.Entry)
2020 for t in tlist:
2021 t.add_prerequisite(plist)
2022 return tlist
2023
2032
2033 - def SConsignFile(self, name=".sconsign", dbm_module=None):
2034 if name is not None:
2035 name = self.subst(name)
2036 if not os.path.isabs(name):
2037 name = os.path.join(str(self.fs.SConstruct_dir), name)
2038 if name:
2039 name = os.path.normpath(name)
2040 sconsign_dir = os.path.dirname(name)
2041 if sconsign_dir and not os.path.exists(sconsign_dir):
2042 self.Execute(SCons.Defaults.Mkdir(sconsign_dir))
2043 SCons.SConsign.File(name, dbm_module)
2044
2046 """Tell scons that side_effects are built as side
2047 effects of building targets."""
2048 side_effects = self.arg2nodes(side_effect, self.fs.Entry)
2049 targets = self.arg2nodes(target, self.fs.Entry)
2050
2051 for side_effect in side_effects:
2052 if side_effect.multiple_side_effect_has_builder():
2053 raise SCons.Errors.UserError, "Multiple ways to build the same target were specified for: %s" % str(side_effect)
2054 side_effect.add_source(targets)
2055 side_effect.side_effect = 1
2056 self.Precious(side_effect)
2057 for target in targets:
2058 target.side_effects.append(side_effect)
2059 return side_effects
2060
2062 """Arrange for a source code builder for (part of) a tree."""
2063 entries = self.arg2nodes(entry, self.fs.Entry)
2064 for entry in entries:
2065 entry.set_src_builder(builder)
2066 return entries
2067
2085
2087 """This function converts a string or list into a list of strings
2088 or Nodes. This makes things easier for users by allowing files to
2089 be specified as a white-space separated list to be split.
2090 The input rules are:
2091 - A single string containing names separated by spaces. These will be
2092 split apart at the spaces.
2093 - A single Node instance
2094 - A list containing either strings or Node instances. Any strings
2095 in the list are not split at spaces.
2096 In all cases, the function returns a list of Nodes and strings."""
2097 if SCons.Util.is_List(arg):
2098 return map(self.subst, arg)
2099 elif SCons.Util.is_String(arg):
2100 return string.split(self.subst(arg))
2101 else:
2102 return [self.subst(arg)]
2103
2125
2126 - def Value(self, value, built_value=None):
2130
2131 - def VariantDir(self, variant_dir, src_dir, duplicate=1):
2135
2137 """ returns a list of all source files.
2138 """
2139 node = self.arg2nodes(node, self.fs.Entry)[0]
2140
2141 sources = []
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152 build_source(node.all_children(), sources)
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163 return list(set(sources))
2164
2166 """ returns the list of all targets of the Install and InstallAs Builder.
2167 """
2168 from SCons.Tool import install
2169 if install._UNIQUE_INSTALLED_FILES is None:
2170 install._UNIQUE_INSTALLED_FILES = SCons.Util.uniquer_hashables(install._INSTALLED_FILES)
2171 return install._UNIQUE_INSTALLED_FILES
2172
2174 """A proxy that overrides variables in a wrapped construction
2175 environment by returning values from an overrides dictionary in
2176 preference to values from the underlying subject environment.
2177
2178 This is a lightweight (I hope) proxy that passes through most use of
2179 attributes to the underlying Environment.Base class, but has just
2180 enough additional methods defined to act like a real construction
2181 environment with overridden values. It can wrap either a Base
2182 construction environment, or another OverrideEnvironment, which
2183 can in turn nest arbitrary OverrideEnvironments...
2184
2185 Note that we do *not* call the underlying base class
2186 (SubsitutionEnvironment) initialization, because we get most of those
2187 from proxying the attributes of the subject construction environment.
2188 But because we subclass SubstitutionEnvironment, this class also
2189 has inherited arg2nodes() and subst*() methods; those methods can't
2190 be proxied because they need *this* object's methods to fetch the
2191 values from the overrides dictionary.
2192 """
2193
2194 - def __init__(self, subject, overrides={}):
2195 if __debug__: logInstanceCreation(self, 'Environment.OverrideEnvironment')
2196 self.__dict__['__subject'] = subject
2197 self.__dict__['overrides'] = overrides
2198
2199
2201 return getattr(self.__dict__['__subject'], name)
2203 setattr(self.__dict__['__subject'], name, value)
2204
2205
2207 try:
2208 return self.__dict__['overrides'][key]
2209 except KeyError:
2210 return self.__dict__['__subject'].__getitem__(key)
2216 try:
2217 del self.__dict__['overrides'][key]
2218 except KeyError:
2219 deleted = 0
2220 else:
2221 deleted = 1
2222 try:
2223 result = self.__dict__['__subject'].__delitem__(key)
2224 except KeyError:
2225 if not deleted:
2226 raise
2227 result = None
2228 return result
2229 - def get(self, key, default=None):
2230 """Emulates the get() method of dictionaries."""
2231 try:
2232 return self.__dict__['overrides'][key]
2233 except KeyError:
2234 return self.__dict__['__subject'].get(key, default)
2236 try:
2237 self.__dict__['overrides'][key]
2238 return 1
2239 except KeyError:
2240 return self.__dict__['__subject'].has_key(key)
2242 if self.__dict__['overrides'].__contains__(key):
2243 return 1
2244 return self.__dict__['__subject'].__contains__(key)
2246 """Emulates the items() method of dictionaries."""
2247 d = self.__dict__['__subject'].Dictionary().copy()
2248 d.update(self.__dict__['overrides'])
2249 return d
2251 """Emulates the items() method of dictionaries."""
2252 return self.Dictionary().items()
2253
2254
2256 """Update an environment's values directly, bypassing the normal
2257 checks that occur when users try to set items.
2258 """
2259 self.__dict__['overrides'].update(dict)
2260
2262 return self.__dict__['__subject'].gvars()
2263
2268
2269
2273
2274
2275
2276
2277
2278
2279
2280 Environment = Base
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2295 class _NoSubstitutionProxy(Environment):
2296 def __init__(self, subject):
2297 self.__dict__['__subject'] = subject
2298 def __getattr__(self, name):
2299 return getattr(self.__dict__['__subject'], name)
2300 def __setattr__(self, name, value):
2301 return setattr(self.__dict__['__subject'], name, value)
2302 def raw_to_mode(self, dict):
2303 try:
2304 raw = dict['raw']
2305 except KeyError:
2306 pass
2307 else:
2308 del dict['raw']
2309 dict['mode'] = raw
2310 def subst(self, string, *args, **kwargs):
2311 return string
2312 def subst_kw(self, kw, *args, **kwargs):
2313 return kw
2314 def subst_list(self, string, *args, **kwargs):
2315 nargs = (string, self,) + args
2316 nkw = kwargs.copy()
2317 nkw['gvars'] = {}
2318 self.raw_to_mode(nkw)
2319 return apply(SCons.Subst.scons_subst_list, nargs, nkw)
2320 def subst_target_source(self, string, *args, **kwargs):
2321 nargs = (string, self,) + args
2322 nkw = kwargs.copy()
2323 nkw['gvars'] = {}
2324 self.raw_to_mode(nkw)
2325 return apply(SCons.Subst.scons_subst, nargs, nkw)
2326 return _NoSubstitutionProxy(subject)
2327
2328
2329
2330
2331
2332
2333