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