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 __revision__ = "src/engine/SCons/Environment.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog"
35
36
37 import copy
38 import os
39 import sys
40 import re
41 import shlex
42 from collections import UserDict
43
44 import SCons.Action
45 import SCons.Builder
46 import SCons.Debug
47 from SCons.Debug import logInstanceCreation
48 import SCons.Defaults
49 import SCons.Errors
50 import SCons.Memoize
51 import SCons.Node
52 import SCons.Node.Alias
53 import SCons.Node.FS
54 import SCons.Node.Python
55 import SCons.Platform
56 import SCons.SConf
57 import SCons.SConsign
58 import SCons.Subst
59 import SCons.Tool
60 import SCons.Util
61 import SCons.Warnings
65
66 _null = _Null
67
68 _warn_copy_deprecated = True
69 _warn_source_signatures_deprecated = True
70 _warn_target_signatures_deprecated = True
71
72 CleanTargets = {}
73 CalculatorArgs = {}
74
75 semi_deepcopy = SCons.Util.semi_deepcopy
76 semi_deepcopy_dict = SCons.Util.semi_deepcopy_dict
77
78
79
80
81 UserError = SCons.Errors.UserError
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')
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 ]
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 i not in seen:
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
199 -class MethodWrapper(object):
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 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 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
295 -class BuilderDict(UserDict):
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."""
306
308
309
310 raise TypeError( 'cannot semi_deepcopy a BuilderDict' )
311
321
325
329
330
331
332 _is_valid_var = re.compile(r'[_a-zA-Z]\w*$')
335 """Return if the specified string is a legitimate construction
336 variable.
337 """
338 return _is_valid_var.match(varstr)
339
343 """Base class for different flavors of construction environments.
344
345 This class contains a minimal set of methods that handle contruction
346 variable expansion and conversion of strings to Nodes, which may or
347 may not be actually useful as a stand-alone class. Which methods
348 ended up in this class is pretty arbitrary right now. They're
349 basically the ones which we've empirically determined are common to
350 the different construction environment subclasses, and most of the
351 others that use or touch the underlying dictionary of construction
352 variables.
353
354 Eventually, this class should contain all the methods that we
355 determine are necessary for a "minimal" interface to the build engine.
356 A full "native Python" SCons environment has gotten pretty heavyweight
357 with all of the methods and Tools and construction variables we've
358 jammed in there, so it would be nice to have a lighter weight
359 alternative for interfaces that don't need all of the bells and
360 whistles. (At some point, we'll also probably rename this class
361 "Base," since that more reflects what we want this class to become,
362 but because we've released comments that tell people to subclass
363 Environment.Base to create their own flavors of construction
364 environment, we'll save that for a future refactoring when this
365 class actually becomes useful.)
366 """
367
378
379
398
400 return cmp(self._dict, other._dict)
401
403 special = self._special_del.get(key)
404 if special:
405 special(self, key)
406 else:
407 del self._dict[key]
408
410 return self._dict[key]
411
413
414
415
416
417
418
419
420
421
422
423
424
425 if key in self._special_set_keys:
426 self._special_set[key](self, key, value)
427 else:
428
429
430
431
432 if key not in self._dict \
433 and not _is_valid_var.match(key):
434 raise SCons.Errors.UserError("Illegal construction variable `%s'" % key)
435 self._dict[key] = value
436
437 - def get(self, key, default=None):
438 """Emulates the get() method of dictionaries."""
439 return self._dict.get(key, default)
440
442 return key in self._dict
443
446
448 return list(self._dict.items())
449
451 if node_factory is _null:
452 node_factory = self.fs.File
453 if lookup_list is _null:
454 lookup_list = self.lookup_list
455
456 if not args:
457 return []
458
459 args = SCons.Util.flatten(args)
460
461 nodes = []
462 for v in args:
463 if SCons.Util.is_String(v):
464 n = None
465 for l in lookup_list:
466 n = l(v)
467 if n is not None:
468 break
469 if n is not None:
470 if SCons.Util.is_String(n):
471
472 kw['raw'] = 1
473 n = self.subst(n, **kw)
474 if node_factory:
475 n = node_factory(n)
476 if SCons.Util.is_List(n):
477 nodes.extend(n)
478 else:
479 nodes.append(n)
480 elif node_factory:
481
482 kw['raw'] = 1
483 v = node_factory(self.subst(v, **kw))
484 if SCons.Util.is_List(v):
485 nodes.extend(v)
486 else:
487 nodes.append(v)
488 else:
489 nodes.append(v)
490
491 return nodes
492
495
498
499 - def subst(self, string, raw=0, target=None, source=None, conv=None, executor=None):
500 """Recursively interpolates construction variables from the
501 Environment into the specified string, returning the expanded
502 result. Construction variables are specified by a $ prefix
503 in the string and begin with an initial underscore or
504 alphabetic character followed by any number of underscores
505 or alphanumeric characters. The construction variable names
506 may be surrounded by curly braces to separate the name from
507 trailing characters.
508 """
509 gvars = self.gvars()
510 lvars = self.lvars()
511 lvars['__env__'] = self
512 if executor:
513 lvars.update(executor.get_lvars())
514 return SCons.Subst.scons_subst(string, self, raw, target, source, gvars, lvars, conv)
515
516 - def subst_kw(self, kw, raw=0, target=None, source=None):
517 nkw = {}
518 for k, v in kw.items():
519 k = self.subst(k, raw, target, source)
520 if SCons.Util.is_String(v):
521 v = self.subst(v, raw, target, source)
522 nkw[k] = v
523 return nkw
524
525 - def subst_list(self, string, raw=0, target=None, source=None, conv=None, executor=None):
534
535 - def subst_path(self, path, target=None, source=None):
536 """Substitute a path list, turning EntryProxies into Nodes
537 and leaving Nodes (and other objects) as-is."""
538
539 if not SCons.Util.is_List(path):
540 path = [path]
541
542 def s(obj):
543 """This is the "string conversion" routine that we have our
544 substitutions use to return Nodes, not strings. This relies
545 on the fact that an EntryProxy object has a get() method that
546 returns the underlying Node that it wraps, which is a bit of
547 architectural dependence that we might need to break or modify
548 in the future in response to additional requirements."""
549 try:
550 get = obj.get
551 except AttributeError:
552 obj = SCons.Util.to_String_for_subst(obj)
553 else:
554 obj = get()
555 return obj
556
557 r = []
558 for p in path:
559 if SCons.Util.is_String(p):
560 p = self.subst(p, target=target, source=source, conv=s)
561 if SCons.Util.is_List(p):
562 if len(p) == 1:
563 p = p[0]
564 else:
565
566
567
568 p = ''.join(map(SCons.Util.to_String_for_subst, p))
569 else:
570 p = s(p)
571 r.append(p)
572 return r
573
574 subst_target_source = subst
575
577 import subprocess
578
579 kw = { 'stdin' : 'devnull',
580 'stdout' : subprocess.PIPE,
581 'stderr' : subprocess.PIPE,
582 'universal_newlines' : True,
583 }
584
585
586 if not SCons.Util.is_List(command): kw['shell'] = True
587
588 p = SCons.Action._subproc(self, command, **kw)
589 out,err = p.communicate()
590 status = p.wait()
591 if err:
592 sys.stderr.write(unicode(err))
593 if status:
594 raise OSError("'%s' exited %d" % (command, status))
595 return out
596
598 """
599 Adds the specified function as a method of this construction
600 environment with the specified name. If the name is omitted,
601 the default name is the name of the function itself.
602 """
603 method = MethodWrapper(self, function, name)
604 self.added_methods.append(method)
605
607 """
608 Removes the specified function's MethodWrapper from the
609 added_methods list, so we don't re-bind it when making a clone.
610 """
611 self.added_methods = [dm for dm in self.added_methods if not dm.method is function]
612
614 """
615 Produce a modified environment whose variables are overridden 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 'CXXFLAGS' : SCons.Util.CLVar(''),
654 'CPPDEFINES' : [],
655 'CPPFLAGS' : SCons.Util.CLVar(''),
656 'CPPPATH' : [],
657 'FRAMEWORKPATH' : SCons.Util.CLVar(''),
658 'FRAMEWORKS' : SCons.Util.CLVar(''),
659 'LIBPATH' : [],
660 'LIBS' : [],
661 'LINKFLAGS' : SCons.Util.CLVar(''),
662 'RPATH' : [],
663 }
664
665 def do_parse(arg):
666
667 if not arg:
668 return
669
670 if not SCons.Util.is_String(arg):
671 for t in arg: do_parse(t)
672 return
673
674
675 if arg[0] == '!':
676 arg = self.backtick(arg[1:])
677
678
679 def append_define(name, dict = dict):
680 t = name.split('=')
681 if len(t) == 1:
682 dict['CPPDEFINES'].append(name)
683 else:
684 dict['CPPDEFINES'].append([t[0], '='.join(t[1:])])
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706 params = shlex.split(arg)
707 append_next_arg_to = None
708 for arg in params:
709 if append_next_arg_to:
710 if append_next_arg_to == 'CPPDEFINES':
711 append_define(arg)
712 elif append_next_arg_to == '-include':
713 t = ('-include', self.fs.File(arg))
714 dict['CCFLAGS'].append(t)
715 elif append_next_arg_to == '-isysroot':
716 t = ('-isysroot', arg)
717 dict['CCFLAGS'].append(t)
718 dict['LINKFLAGS'].append(t)
719 elif append_next_arg_to == '-isystem':
720 t = ('-isystem', arg)
721 dict['CCFLAGS'].append(t)
722 elif append_next_arg_to == '-arch':
723 t = ('-arch', arg)
724 dict['CCFLAGS'].append(t)
725 dict['LINKFLAGS'].append(t)
726 else:
727 dict[append_next_arg_to].append(arg)
728 append_next_arg_to = None
729 elif not arg[0] in ['-', '+']:
730 dict['LIBS'].append(self.fs.File(arg))
731 elif arg == '-dylib_file':
732 dict['LINKFLAGS'].append(arg)
733 append_next_arg_to = 'LINKFLAGS'
734 elif arg[:2] == '-L':
735 if arg[2:]:
736 dict['LIBPATH'].append(arg[2:])
737 else:
738 append_next_arg_to = 'LIBPATH'
739 elif arg[:2] == '-l':
740 if arg[2:]:
741 dict['LIBS'].append(arg[2:])
742 else:
743 append_next_arg_to = 'LIBS'
744 elif arg[:2] == '-I':
745 if arg[2:]:
746 dict['CPPPATH'].append(arg[2:])
747 else:
748 append_next_arg_to = 'CPPPATH'
749 elif arg[:4] == '-Wa,':
750 dict['ASFLAGS'].append(arg[4:])
751 dict['CCFLAGS'].append(arg)
752 elif arg[:4] == '-Wl,':
753 if arg[:11] == '-Wl,-rpath=':
754 dict['RPATH'].append(arg[11:])
755 elif arg[:7] == '-Wl,-R,':
756 dict['RPATH'].append(arg[7:])
757 elif arg[:6] == '-Wl,-R':
758 dict['RPATH'].append(arg[6:])
759 else:
760 dict['LINKFLAGS'].append(arg)
761 elif arg[:4] == '-Wp,':
762 dict['CPPFLAGS'].append(arg)
763 elif arg[:2] == '-D':
764 if arg[2:]:
765 append_define(arg[2:])
766 else:
767 append_next_arg_to = 'CPPDEFINES'
768 elif arg == '-framework':
769 append_next_arg_to = 'FRAMEWORKS'
770 elif arg[:14] == '-frameworkdir=':
771 dict['FRAMEWORKPATH'].append(arg[14:])
772 elif arg[:2] == '-F':
773 if arg[2:]:
774 dict['FRAMEWORKPATH'].append(arg[2:])
775 else:
776 append_next_arg_to = 'FRAMEWORKPATH'
777 elif arg in ['-mno-cygwin',
778 '-pthread',
779 '-openmp',
780 '-fopenmp']:
781 dict['CCFLAGS'].append(arg)
782 dict['LINKFLAGS'].append(arg)
783 elif arg == '-mwindows':
784 dict['LINKFLAGS'].append(arg)
785 elif arg[:5] == '-std=':
786 if arg[5:].find('++')!=-1:
787 key='CXXFLAGS'
788 else:
789 key='CFLAGS'
790 dict[key].append(arg)
791 elif arg[0] == '+':
792 dict['CCFLAGS'].append(arg)
793 dict['LINKFLAGS'].append(arg)
794 elif arg in ['-include', '-isysroot', '-isystem', '-arch']:
795 append_next_arg_to = arg
796 else:
797 dict['CCFLAGS'].append(arg)
798
799 for arg in flags:
800 do_parse(arg)
801 return dict
802
804 """
805 Merge the dict in args into the construction variables of this
806 env, or the passed-in dict. If args is not a dict, it is
807 converted into a dict using ParseFlags. If unique is not set,
808 the flags are appended rather than merged.
809 """
810
811 if dict is None:
812 dict = self
813 if not SCons.Util.is_Dict(args):
814 args = self.ParseFlags(args)
815 if not unique:
816 self.Append(**args)
817 return self
818 for key, value in args.items():
819 if not value:
820 continue
821 try:
822 orig = self[key]
823 except KeyError:
824 orig = value
825 else:
826 if not orig:
827 orig = value
828 elif value:
829
830
831
832
833
834
835 try:
836 orig = orig + value
837 except (KeyError, TypeError):
838 try:
839 add_to_orig = orig.append
840 except AttributeError:
841 value.insert(0, orig)
842 orig = value
843 else:
844 add_to_orig(value)
845 t = []
846 if key[-4:] == 'PATH':
847
848 for v in orig:
849 if v not in t:
850 t.append(v)
851 else:
852
853 orig.reverse()
854 for v in orig:
855 if v not in t:
856 t.insert(0, v)
857 self[key] = t
858 return self
859
862 f = SCons.Defaults.DefaultEnvironment().decide_source
863 return f(dependency, target, prev_ni)
864
866 f = SCons.Defaults.DefaultEnvironment().decide_target
867 return f(dependency, target, prev_ni)
868
870 f = SCons.Defaults.DefaultEnvironment().copy_from_cache
871 return f(src, dst)
872
873 -class Base(SubstitutionEnvironment):
874 """Base class for "real" construction Environments. These are the
875 primary objects used to communicate dependency and construction
876 information to the build engine.
877
878 Keyword arguments supplied when the construction Environment
879 is created are construction variables used to initialize the
880 Environment.
881 """
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897 - def __init__(self,
898 platform=None,
899 tools=None,
900 toolpath=None,
901 variables=None,
902 parse_flags = None,
903 **kw):
904 """
905 Initialization of a basic SCons construction environment,
906 including setting up special construction variables like BUILDER,
907 PLATFORM, etc., and searching for and applying available Tools.
908
909 Note that we do *not* call the underlying base class
910 (SubsitutionEnvironment) initialization, because we need to
911 initialize things in a very specific order that doesn't work
912 with the much simpler base class initialization.
913 """
914 if SCons.Debug.track_instances: logInstanceCreation(self, 'Environment.Base')
915 self._memo = {}
916 self.fs = SCons.Node.FS.get_default_fs()
917 self.ans = SCons.Node.Alias.default_ans
918 self.lookup_list = SCons.Node.arg2nodes_lookups
919 self._dict = semi_deepcopy(SCons.Defaults.ConstructionEnvironment)
920 self._init_special()
921 self.added_methods = []
922
923
924
925
926
927
928
929 self.decide_target = default_decide_target
930 self.decide_source = default_decide_source
931
932 self.copy_from_cache = default_copy_from_cache
933
934 self._dict['BUILDERS'] = BuilderDict(self._dict['BUILDERS'], self)
935
936 if platform is None:
937 platform = self._dict.get('PLATFORM', None)
938 if platform is None:
939 platform = SCons.Platform.Platform()
940 if SCons.Util.is_String(platform):
941 platform = SCons.Platform.Platform(platform)
942 self._dict['PLATFORM'] = str(platform)
943 platform(self)
944
945 self._dict['HOST_OS'] = self._dict.get('HOST_OS',None)
946 self._dict['HOST_ARCH'] = self._dict.get('HOST_ARCH',None)
947
948
949 self._dict['TARGET_OS'] = self._dict.get('TARGET_OS',None)
950 self._dict['TARGET_ARCH'] = self._dict.get('TARGET_ARCH',None)
951
952
953
954
955
956 if 'options' in kw:
957
958
959 variables = kw['options']
960 del kw['options']
961 self.Replace(**kw)
962 keys = list(kw.keys())
963 if variables:
964 keys = keys + list(variables.keys())
965 variables.Update(self)
966
967 save = {}
968 for k in keys:
969 try:
970 save[k] = self._dict[k]
971 except KeyError:
972
973
974 pass
975
976 SCons.Tool.Initializers(self)
977
978 if tools is None:
979 tools = self._dict.get('TOOLS', None)
980 if tools is None:
981 tools = ['default']
982 apply_tools(self, tools, toolpath)
983
984
985
986
987 for key, val in save.items():
988 self._dict[key] = val
989
990
991 if parse_flags: self.MergeFlags(parse_flags)
992
993
994
995
996
997
999 """Fetch the builder with the specified name from the environment.
1000 """
1001 try:
1002 return self._dict['BUILDERS'][name]
1003 except KeyError:
1004 return None
1005
1020
1022 """Return a factory function for creating Nodes for this
1023 construction environment.
1024 """
1025 name = default
1026 try:
1027 is_node = issubclass(factory, SCons.Node.FS.Base)
1028 except TypeError:
1029
1030
1031 pass
1032 else:
1033 if is_node:
1034
1035
1036
1037
1038 try: name = factory.__name__
1039 except AttributeError: pass
1040 else: factory = None
1041 if not factory:
1042
1043
1044
1045
1046
1047 factory = getattr(self.fs, name)
1048 return factory
1049
1050 @SCons.Memoize.CountMethodCall
1052 try:
1053 return self._memo['_gsm']
1054 except KeyError:
1055 pass
1056
1057 result = {}
1058
1059 try:
1060 scanners = self._dict['SCANNERS']
1061 except KeyError:
1062 pass
1063 else:
1064
1065
1066
1067
1068 if not SCons.Util.is_List(scanners):
1069 scanners = [scanners]
1070 else:
1071 scanners = scanners[:]
1072 scanners.reverse()
1073 for scanner in scanners:
1074 for k in scanner.get_skeys(self):
1075 if k and self['PLATFORM'] == 'win32':
1076 k = k.lower()
1077 result[k] = scanner
1078
1079 self._memo['_gsm'] = result
1080
1081 return result
1082
1084 """Find the appropriate scanner given a key (usually a file suffix).
1085 """
1086 if skey and self['PLATFORM'] == 'win32':
1087 skey = skey.lower()
1088 return self._gsm().get(skey)
1089
1091 """Delete the cached scanner map (if we need to).
1092 """
1093 try:
1094 del self._memo['_gsm']
1095 except KeyError:
1096 pass
1097
1099 """Update an environment's values directly, bypassing the normal
1100 checks that occur when users try to set items.
1101 """
1102 self._dict.update(dict)
1103
1105 try:
1106 return self.src_sig_type
1107 except AttributeError:
1108 t = SCons.Defaults.DefaultEnvironment().src_sig_type
1109 self.src_sig_type = t
1110 return t
1111
1113 try:
1114 return self.tgt_sig_type
1115 except AttributeError:
1116 t = SCons.Defaults.DefaultEnvironment().tgt_sig_type
1117 self.tgt_sig_type = t
1118 return t
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1130 """Append values to existing construction variables
1131 in an Environment.
1132 """
1133 kw = copy_non_reserved_keywords(kw)
1134 for key, val in kw.items():
1135
1136
1137
1138
1139 try:
1140 if key == 'CPPDEFINES' and SCons.Util.is_String(self._dict[key]):
1141 self._dict[key] = [self._dict[key]]
1142 orig = self._dict[key]
1143 except KeyError:
1144
1145
1146 if key == 'CPPDEFINES' and SCons.Util.is_String(val):
1147 self._dict[key] = [val]
1148 else:
1149 self._dict[key] = val
1150 else:
1151 try:
1152
1153
1154
1155
1156
1157 update_dict = orig.update
1158 except AttributeError:
1159 try:
1160
1161
1162
1163 self._dict[key] = orig + val
1164 except (KeyError, TypeError):
1165 try:
1166
1167 add_to_orig = orig.append
1168 except AttributeError:
1169
1170
1171
1172
1173
1174 if orig:
1175 val.insert(0, orig)
1176 self._dict[key] = val
1177 else:
1178
1179
1180 if val:
1181 add_to_orig(val)
1182 else:
1183
1184
1185 if SCons.Util.is_List(val):
1186 if key == 'CPPDEFINES':
1187 tmp = []
1188 for (k, v) in orig.iteritems():
1189 if v is not None:
1190 tmp.append((k, v))
1191 else:
1192 tmp.append((k,))
1193 orig = tmp
1194 orig += val
1195 self._dict[key] = orig
1196 else:
1197 for v in val:
1198 orig[v] = None
1199 else:
1200 try:
1201 update_dict(val)
1202 except (AttributeError, TypeError, ValueError):
1203 if SCons.Util.is_Dict(val):
1204 for k, v in val.items():
1205 orig[k] = v
1206 else:
1207 orig[val] = None
1208 self.scanner_map_delete(kw)
1209
1210
1211
1218
1219 - def AppendENVPath(self, name, newpath, envname = 'ENV',
1220 sep = os.pathsep, delete_existing=1):
1221 """Append path elements to the path 'name' in the 'ENV'
1222 dictionary for this environment. Will only add any particular
1223 path once, and will normpath and normcase all paths to help
1224 assure this. This can also handle the case where the env
1225 variable is a list instead of a string.
1226
1227 If delete_existing is 0, a newpath which is already in the path
1228 will not be moved to the end (it will be left where it is).
1229 """
1230
1231 orig = ''
1232 if envname in self._dict and name in self._dict[envname]:
1233 orig = self._dict[envname][name]
1234
1235 nv = SCons.Util.AppendPath(orig, newpath, sep, delete_existing,
1236 canonicalize=self._canonicalize)
1237
1238 if envname not in self._dict:
1239 self._dict[envname] = {}
1240
1241 self._dict[envname][name] = nv
1242
1244 """Append values to existing construction variables
1245 in an Environment, if they're not already there.
1246 If delete_existing is 1, removes existing values first, so
1247 values move to end.
1248 """
1249 kw = copy_non_reserved_keywords(kw)
1250 for key, val in kw.items():
1251 if SCons.Util.is_List(val):
1252 val = _delete_duplicates(val, delete_existing)
1253 if key not in self._dict or self._dict[key] in ('', None):
1254 self._dict[key] = val
1255 elif SCons.Util.is_Dict(self._dict[key]) and \
1256 SCons.Util.is_Dict(val):
1257 self._dict[key].update(val)
1258 elif SCons.Util.is_List(val):
1259 dk = self._dict[key]
1260 if key == 'CPPDEFINES':
1261 tmp = []
1262 for i in val:
1263 if SCons.Util.is_List(i):
1264 if len(i) >= 2:
1265 tmp.append((i[0], i[1]))
1266 else:
1267 tmp.append((i[0],))
1268 elif SCons.Util.is_Tuple(i):
1269 tmp.append(i)
1270 else:
1271 tmp.append((i,))
1272 val = tmp
1273
1274 if SCons.Util.is_Dict(dk):
1275 tmp = []
1276 for (k, v) in dk.iteritems():
1277 if v is not None:
1278 tmp.append((k, v))
1279 else:
1280 tmp.append((k,))
1281 dk = tmp
1282 elif SCons.Util.is_String(dk):
1283 dk = [(dk,)]
1284 else:
1285 tmp = []
1286 for i in dk:
1287 if SCons.Util.is_List(i):
1288 if len(i) >= 2:
1289 tmp.append((i[0], i[1]))
1290 else:
1291 tmp.append((i[0],))
1292 elif SCons.Util.is_Tuple(i):
1293 tmp.append(i)
1294 else:
1295 tmp.append((i,))
1296 dk = tmp
1297 else:
1298 if not SCons.Util.is_List(dk):
1299 dk = [dk]
1300 if delete_existing:
1301 dk = [x for x in dk if x not in val]
1302 else:
1303 val = [x for x in val if x not in dk]
1304 self._dict[key] = dk + val
1305 else:
1306 dk = self._dict[key]
1307 if SCons.Util.is_List(dk):
1308 if key == 'CPPDEFINES':
1309 tmp = []
1310 for i in dk:
1311 if SCons.Util.is_List(i):
1312 if len(i) >= 2:
1313 tmp.append((i[0], i[1]))
1314 else:
1315 tmp.append((i[0],))
1316 elif SCons.Util.is_Tuple(i):
1317 tmp.append(i)
1318 else:
1319 tmp.append((i,))
1320 dk = tmp
1321
1322 if SCons.Util.is_Dict(val):
1323 tmp = []
1324 for (k, v) in val.iteritems():
1325 if v is not None:
1326 tmp.append((k, v))
1327 else:
1328 tmp.append((k,))
1329 val = tmp
1330 elif SCons.Util.is_String(val):
1331 val = [(val,)]
1332 if delete_existing:
1333 dk = filter(lambda x, val=val: x not in val, dk)
1334 self._dict[key] = dk + val
1335 else:
1336 dk = [x for x in dk if x not in val]
1337 self._dict[key] = dk + val
1338 else:
1339
1340
1341 if delete_existing:
1342 dk = filter(lambda x, val=val: x not in val, dk)
1343 self._dict[key] = dk + [val]
1344 else:
1345 if not val in dk:
1346 self._dict[key] = dk + [val]
1347 else:
1348 if key == 'CPPDEFINES':
1349 if SCons.Util.is_String(dk):
1350 dk = [dk]
1351 elif SCons.Util.is_Dict(dk):
1352 tmp = []
1353 for (k, v) in dk.iteritems():
1354 if v is not None:
1355 tmp.append((k, v))
1356 else:
1357 tmp.append((k,))
1358 dk = tmp
1359 if SCons.Util.is_String(val):
1360 if val in dk:
1361 val = []
1362 else:
1363 val = [val]
1364 elif SCons.Util.is_Dict(val):
1365 tmp = []
1366 for i,j in val.iteritems():
1367 if j is not None:
1368 tmp.append((i,j))
1369 else:
1370 tmp.append(i)
1371 val = tmp
1372 if delete_existing:
1373 dk = [x for x in dk if x not in val]
1374 self._dict[key] = dk + val
1375 self.scanner_map_delete(kw)
1376
1377 - def Clone(self, tools=[], toolpath=None, parse_flags = None, **kw):
1378 """Return a copy of a construction Environment. The
1379 copy is like a Python "deep copy"--that is, independent
1380 copies are made recursively of each objects--except that
1381 a reference is copied when an object is not deep-copyable
1382 (like a function). There are no references to any mutable
1383 objects in the original Environment.
1384 """
1385
1386 builders = self._dict.get('BUILDERS', {})
1387
1388 clone = copy.copy(self)
1389
1390 clone._dict = semi_deepcopy_dict(self._dict, ['BUILDERS'])
1391 clone._dict['BUILDERS'] = BuilderDict(builders, clone)
1392
1393
1394
1395
1396
1397 clone.added_methods = []
1398 for mw in self.added_methods:
1399 if mw == getattr(self, mw.name):
1400 clone.added_methods.append(mw.clone(clone))
1401
1402 clone._memo = {}
1403
1404
1405
1406 kw = copy_non_reserved_keywords(kw)
1407 new = {}
1408 for key, value in kw.items():
1409 new[key] = SCons.Subst.scons_subst_once(value, self, key)
1410 clone.Replace(**new)
1411
1412 apply_tools(clone, tools, toolpath)
1413
1414
1415 clone.Replace(**new)
1416
1417
1418 if parse_flags: clone.MergeFlags(parse_flags)
1419
1420 if SCons.Debug.track_instances: logInstanceCreation(self, 'Environment.EnvironmentClone')
1421 return clone
1422
1423 - def Copy(self, *args, **kw):
1430
1432 if dependency.changed_state(target, prev_ni):
1433 return 1
1434 return self.decide_source(dependency, target, prev_ni)
1435
1436 - def _changed_content(self, dependency, target, prev_ni):
1437 return dependency.changed_content(target, prev_ni)
1438
1440 target_env = dependency.get_build_env()
1441 type = target_env.get_tgt_sig_type()
1442 if type == 'source':
1443 return target_env.decide_source(dependency, target, prev_ni)
1444 else:
1445 return target_env.decide_target(dependency, target, prev_ni)
1446
1447 - def _changed_timestamp_then_content(self, dependency, target, prev_ni):
1448 return dependency.changed_timestamp_then_content(target, prev_ni)
1449
1452
1455
1457 return self.fs.copy(src, dst)
1458
1460 return self.fs.copy2(src, dst)
1461
1485
1487 """Return the first available program in progs.
1488 """
1489 if not SCons.Util.is_List(progs):
1490 progs = [ progs ]
1491 for prog in progs:
1492 path = self.WhereIs(prog)
1493 if path: return prog
1494 return None
1495
1497 if not args:
1498 return self._dict
1499 dlist = [self._dict[x] for x in args]
1500 if len(dlist) == 1:
1501 dlist = dlist[0]
1502 return dlist
1503
1504 - def Dump(self, key = None):
1505 """
1506 Using the standard Python pretty printer, return the contents of the
1507 scons build environment as a string.
1508
1509 If the key passed in is anything other than None, then that will
1510 be used as an index into the build environment dictionary and
1511 whatever is found there will be fed into the pretty printer. Note
1512 that this key is case sensitive.
1513 """
1514 import pprint
1515 pp = pprint.PrettyPrinter(indent=2)
1516 if key:
1517 dict = self.Dictionary(key)
1518 else:
1519 dict = self.Dictionary()
1520 return pp.pformat(dict)
1521
1522 - def FindIxes(self, paths, prefix, suffix):
1523 """
1524 Search a list of paths for something that matches the prefix and suffix.
1525
1526 paths - the list of paths or nodes.
1527 prefix - construction variable for the prefix.
1528 suffix - construction variable for the suffix.
1529 """
1530
1531 suffix = self.subst('$'+suffix)
1532 prefix = self.subst('$'+prefix)
1533
1534 for path in paths:
1535 dir,name = os.path.split(str(path))
1536 if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix:
1537 return path
1538
1539 - def ParseConfig(self, command, function=None, unique=1):
1540 """
1541 Use the specified function to parse the output of the command
1542 in order to modify the current environment. The 'command' can
1543 be a string or a list of strings representing a command and
1544 its arguments. 'Function' is an optional argument that takes
1545 the environment, the output of the command, and the unique flag.
1546 If no function is specified, MergeFlags, which treats the output
1547 as the result of a typical 'X-config' command (i.e. gtk-config),
1548 will merge the output into the appropriate variables.
1549 """
1550 if function is None:
1551 def parse_conf(env, cmd, unique=unique):
1552 return env.MergeFlags(cmd, unique)
1553 function = parse_conf
1554 if SCons.Util.is_List(command):
1555 command = ' '.join(command)
1556 command = self.subst(command)
1557 return function(self, self.backtick(command))
1558
1559 - def ParseDepends(self, filename, must_exist=None, only_one=0):
1560 """
1561 Parse a mkdep-style file for explicit dependencies. This is
1562 completely abusable, and should be unnecessary in the "normal"
1563 case of proper SCons configuration, but it may help make
1564 the transition from a Make hierarchy easier for some people
1565 to swallow. It can also be genuinely useful when using a tool
1566 that can write a .d file, but for which writing a scanner would
1567 be too complicated.
1568 """
1569 filename = self.subst(filename)
1570 try:
1571 fp = open(filename, 'r')
1572 except IOError:
1573 if must_exist:
1574 raise
1575 return
1576 lines = SCons.Util.LogicalLines(fp).readlines()
1577 lines = [l for l in lines if l[0] != '#']
1578 tdlist = []
1579 for line in lines:
1580 try:
1581 target, depends = line.split(':', 1)
1582 except (AttributeError, ValueError):
1583
1584
1585 pass
1586 else:
1587 tdlist.append((target.split(), depends.split()))
1588 if only_one:
1589 targets = []
1590 for td in tdlist:
1591 targets.extend(td[0])
1592 if len(targets) > 1:
1593 raise SCons.Errors.UserError(
1594 "More than one dependency target found in `%s': %s"
1595 % (filename, targets))
1596 for target, depends in tdlist:
1597 self.Depends(target, depends)
1598
1602
1604 """Prepend values to existing construction variables
1605 in an Environment.
1606 """
1607 kw = copy_non_reserved_keywords(kw)
1608 for key, val in kw.items():
1609
1610
1611
1612
1613 try:
1614 orig = self._dict[key]
1615 except KeyError:
1616
1617
1618 self._dict[key] = val
1619 else:
1620 try:
1621
1622
1623
1624
1625
1626 update_dict = orig.update
1627 except AttributeError:
1628 try:
1629
1630
1631
1632 self._dict[key] = val + orig
1633 except (KeyError, TypeError):
1634 try:
1635
1636 add_to_val = val.append
1637 except AttributeError:
1638
1639
1640
1641
1642 if val:
1643 orig.insert(0, val)
1644 else:
1645
1646
1647
1648 if orig:
1649 add_to_val(orig)
1650 self._dict[key] = val
1651 else:
1652
1653
1654 if SCons.Util.is_List(val):
1655 for v in val:
1656 orig[v] = None
1657 else:
1658 try:
1659 update_dict(val)
1660 except (AttributeError, TypeError, ValueError):
1661 if SCons.Util.is_Dict(val):
1662 for k, v in val.items():
1663 orig[k] = v
1664 else:
1665 orig[val] = None
1666 self.scanner_map_delete(kw)
1667
1668 - def PrependENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep,
1669 delete_existing=1):
1670 """Prepend path elements to the path 'name' in the 'ENV'
1671 dictionary for this environment. Will only add any particular
1672 path once, and will normpath and normcase all paths to help
1673 assure this. This can also handle the case where the env
1674 variable is a list instead of a string.
1675
1676 If delete_existing is 0, a newpath which is already in the path
1677 will not be moved to the front (it will be left where it is).
1678 """
1679
1680 orig = ''
1681 if envname in self._dict and name in self._dict[envname]:
1682 orig = self._dict[envname][name]
1683
1684 nv = SCons.Util.PrependPath(orig, newpath, sep, delete_existing,
1685 canonicalize=self._canonicalize)
1686
1687 if envname not in self._dict:
1688 self._dict[envname] = {}
1689
1690 self._dict[envname][name] = nv
1691
1693 """Prepend values to existing construction variables
1694 in an Environment, if they're not already there.
1695 If delete_existing is 1, removes existing values first, so
1696 values move to front.
1697 """
1698 kw = copy_non_reserved_keywords(kw)
1699 for key, val in kw.items():
1700 if SCons.Util.is_List(val):
1701 val = _delete_duplicates(val, not delete_existing)
1702 if key not in self._dict or self._dict[key] in ('', None):
1703 self._dict[key] = val
1704 elif SCons.Util.is_Dict(self._dict[key]) and \
1705 SCons.Util.is_Dict(val):
1706 self._dict[key].update(val)
1707 elif SCons.Util.is_List(val):
1708 dk = self._dict[key]
1709 if not SCons.Util.is_List(dk):
1710 dk = [dk]
1711 if delete_existing:
1712 dk = [x for x in dk if x not in val]
1713 else:
1714 val = [x for x in val if x not in dk]
1715 self._dict[key] = val + dk
1716 else:
1717 dk = self._dict[key]
1718 if SCons.Util.is_List(dk):
1719
1720
1721 if delete_existing:
1722 dk = [x for x in dk if x not in val]
1723 self._dict[key] = [val] + dk
1724 else:
1725 if not val in dk:
1726 self._dict[key] = [val] + dk
1727 else:
1728 if delete_existing:
1729 dk = [x for x in dk if x not in val]
1730 self._dict[key] = val + dk
1731 self.scanner_map_delete(kw)
1732
1734 """Replace existing construction variables in an Environment
1735 with new construction variables and/or values.
1736 """
1737 try:
1738 kwbd = kw['BUILDERS']
1739 except KeyError:
1740 pass
1741 else:
1742 kwbd = BuilderDict(kwbd,self)
1743 del kw['BUILDERS']
1744 self.__setitem__('BUILDERS', kwbd)
1745 kw = copy_non_reserved_keywords(kw)
1746 self._update(semi_deepcopy(kw))
1747 self.scanner_map_delete(kw)
1748
1749 - def ReplaceIxes(self, path, old_prefix, old_suffix, new_prefix, new_suffix):
1750 """
1751 Replace old_prefix with new_prefix and old_suffix with new_suffix.
1752
1753 env - Environment used to interpolate variables.
1754 path - the path that will be modified.
1755 old_prefix - construction variable for the old prefix.
1756 old_suffix - construction variable for the old suffix.
1757 new_prefix - construction variable for the new prefix.
1758 new_suffix - construction variable for the new suffix.
1759 """
1760 old_prefix = self.subst('$'+old_prefix)
1761 old_suffix = self.subst('$'+old_suffix)
1762
1763 new_prefix = self.subst('$'+new_prefix)
1764 new_suffix = self.subst('$'+new_suffix)
1765
1766 dir,name = os.path.split(str(path))
1767 if name[:len(old_prefix)] == old_prefix:
1768 name = name[len(old_prefix):]
1769 if name[-len(old_suffix):] == old_suffix:
1770 name = name[:-len(old_suffix)]
1771 return os.path.join(dir, new_prefix+name+new_suffix)
1772
1774 for k in kw.keys():
1775 if k in self._dict:
1776 del kw[k]
1777 self.Replace(**kw)
1778
1781
1790
1791 - def WhereIs(self, prog, path=None, pathext=None, reject=[]):
1792 """Find prog in the path.
1793 """
1794 if path is None:
1795 try:
1796 path = self['ENV']['PATH']
1797 except KeyError:
1798 pass
1799 elif SCons.Util.is_String(path):
1800 path = self.subst(path)
1801 if pathext is None:
1802 try:
1803 pathext = self['ENV']['PATHEXT']
1804 except KeyError:
1805 pass
1806 elif SCons.Util.is_String(pathext):
1807 pathext = self.subst(pathext)
1808 prog = SCons.Util.CLVar(self.subst(prog))
1809 path = SCons.Util.WhereIs(prog[0], path, pathext, reject)
1810 if path: return path
1811 return None
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821 - def Action(self, *args, **kw):
1822 def subst_string(a, self=self):
1823 if SCons.Util.is_String(a):
1824 a = self.subst(a)
1825 return a
1826 nargs = list(map(subst_string, args))
1827 nkw = self.subst_kw(kw)
1828 return SCons.Action.Action(*nargs, **nkw)
1829
1839
1840 - def AddPostAction(self, files, action):
1841 nodes = self.arg2nodes(files, self.fs.Entry)
1842 action = SCons.Action.Action(action)
1843 uniq = {}
1844 for executor in [n.get_executor() for n in nodes]:
1845 uniq[executor] = 1
1846 for executor in uniq.keys():
1847 executor.add_post_action(action)
1848 return nodes
1849
1850 - def Alias(self, target, source=[], action=None, **kw):
1902
1910
1918
1922
1928
1929 - def Clean(self, targets, files):
1938
1950
1951 - def Command(self, target, source, action, **kw):
1952 """Builds the supplied target files from the supplied
1953 source files using the supplied action. Action may
1954 be any type that the Builder constructor will accept
1955 for an action."""
1956 bkw = {
1957 'action' : action,
1958 'target_factory' : self.fs.Entry,
1959 'source_factory' : self.fs.Entry,
1960 }
1961 try: bkw['source_scanner'] = kw['source_scanner']
1962 except KeyError: pass
1963 else: del kw['source_scanner']
1964 bld = SCons.Builder.Builder(**bkw)
1965 return bld(self, target, source, **kw)
1966
1967 - def Depends(self, target, dependency):
1968 """Explicity specify that 'target's depend on 'dependency'."""
1969 tlist = self.arg2nodes(target, self.fs.Entry)
1970 dlist = self.arg2nodes(dependency, self.fs.Entry)
1971 for t in tlist:
1972 t.add_dependency(dlist)
1973 return tlist
1974
1975 - def Dir(self, name, *args, **kw):
1985
1987 """Tags a target so that it will not be cleaned by -c"""
1988 tlist = []
1989 for t in targets:
1990 tlist.extend(self.arg2nodes(t, self.fs.Entry))
1991 for t in tlist:
1992 t.set_noclean()
1993 return tlist
1994
1996 """Tags a target so that it will not be cached"""
1997 tlist = []
1998 for t in targets:
1999 tlist.extend(self.arg2nodes(t, self.fs.Entry))
2000 for t in tlist:
2001 t.set_nocache()
2002 return tlist
2003
2004 - def Entry(self, name, *args, **kw):
2005 """
2006 """
2007 s = self.subst(name)
2008 if SCons.Util.is_Sequence(s):
2009 result=[]
2010 for e in s:
2011 result.append(self.fs.Entry(e, *args, **kw))
2012 return result
2013 return self.fs.Entry(s, *args, **kw)
2014
2017
2018 - def Execute(self, action, *args, **kw):
2019 """Directly execute an action through an Environment
2020 """
2021 action = self.Action(action, *args, **kw)
2022 result = action([], [], self)
2023 if isinstance(result, SCons.Errors.BuildError):
2024 errstr = result.errstr
2025 if result.filename:
2026 errstr = result.filename + ': ' + errstr
2027 sys.stderr.write("scons: *** %s\n" % errstr)
2028 return result.status
2029 else:
2030 return result
2031
2032 - def File(self, name, *args, **kw):
2042
2047
2050
2057
2058 - def Glob(self, pattern, ondisk=True, source=False, strings=False, exclude=None):
2059 return self.fs.Glob(self.subst(pattern), ondisk, source, strings, exclude)
2060
2061 - def Ignore(self, target, dependency):
2068
2071
2072 - def Local(self, *targets):
2083
2091
2099
2103
2104 - def Requires(self, target, prerequisite):
2105 """Specify that 'prerequisite' must be built before 'target',
2106 (but 'target' does not actually depend on 'prerequisite'
2107 and need not be rebuilt if it changes)."""
2108 tlist = self.arg2nodes(target, self.fs.Entry)
2109 plist = self.arg2nodes(prerequisite, self.fs.Entry)
2110 for t in tlist:
2111 t.add_prerequisite(plist)
2112 return tlist
2113
2122
2123 - def SConsignFile(self, name=".sconsign", dbm_module=None):
2134
2150
2160
2178
2180 """This function converts a string or list into a list of strings
2181 or Nodes. This makes things easier for users by allowing files to
2182 be specified as a white-space separated list to be split.
2183 The input rules are:
2184 - A single string containing names separated by spaces. These will be
2185 split apart at the spaces.
2186 - A single Node instance
2187 - A list containing either strings or Node instances. Any strings
2188 in the list are not split at spaces.
2189 In all cases, the function returns a list of Nodes and strings."""
2190 if SCons.Util.is_List(arg):
2191 return list(map(self.subst, arg))
2192 elif SCons.Util.is_String(arg):
2193 return self.subst(arg).split()
2194 else:
2195 return [self.subst(arg)]
2196
2218
2219 - def Value(self, value, built_value=None):
2223
2224 - def VariantDir(self, variant_dir, src_dir, duplicate=1):
2228
2243 build_source(node.all_children())
2244
2245 def final_source(node):
2246 while (node != node.srcnode()):
2247 node = node.srcnode()
2248 return node
2249 sources = map( final_source, sources );
2250
2251 return list(set(sources))
2252
2254 """ returns the list of all targets of the Install and InstallAs Builder.
2255 """
2256 from SCons.Tool import install
2257 if install._UNIQUE_INSTALLED_FILES is None:
2258 install._UNIQUE_INSTALLED_FILES = SCons.Util.uniquer_hashables(install._INSTALLED_FILES)
2259 return install._UNIQUE_INSTALLED_FILES
2260
2263 """A proxy that overrides variables in a wrapped construction
2264 environment by returning values from an overrides dictionary in
2265 preference to values from the underlying subject environment.
2266
2267 This is a lightweight (I hope) proxy that passes through most use of
2268 attributes to the underlying Environment.Base class, but has just
2269 enough additional methods defined to act like a real construction
2270 environment with overridden values. It can wrap either a Base
2271 construction environment, or another OverrideEnvironment, which
2272 can in turn nest arbitrary OverrideEnvironments...
2273
2274 Note that we do *not* call the underlying base class
2275 (SubsitutionEnvironment) initialization, because we get most of those
2276 from proxying the attributes of the subject construction environment.
2277 But because we subclass SubstitutionEnvironment, this class also
2278 has inherited arg2nodes() and subst*() methods; those methods can't
2279 be proxied because they need *this* object's methods to fetch the
2280 values from the overrides dictionary.
2281 """
2282
2283 - def __init__(self, subject, overrides={}):
2287
2288
2290 return getattr(self.__dict__['__subject'], name)
2292 setattr(self.__dict__['__subject'], name, value)
2293
2294
2296 try:
2297 return self.__dict__['overrides'][key]
2298 except KeyError:
2299 return self.__dict__['__subject'].__getitem__(key)
2305 try:
2306 del self.__dict__['overrides'][key]
2307 except KeyError:
2308 deleted = 0
2309 else:
2310 deleted = 1
2311 try:
2312 result = self.__dict__['__subject'].__delitem__(key)
2313 except KeyError:
2314 if not deleted:
2315 raise
2316 result = None
2317 return result
2318 - def get(self, key, default=None):
2319 """Emulates the get() method of dictionaries."""
2320 try:
2321 return self.__dict__['overrides'][key]
2322 except KeyError:
2323 return self.__dict__['__subject'].get(key, default)
2325 try:
2326 self.__dict__['overrides'][key]
2327 return 1
2328 except KeyError:
2329 return key in self.__dict__['__subject']
2335 """Emulates the items() method of dictionaries."""
2336 d = self.__dict__['__subject'].Dictionary().copy()
2337 d.update(self.__dict__['overrides'])
2338 return d
2340 """Emulates the items() method of dictionaries."""
2341 return list(self.Dictionary().items())
2342
2343
2345 """Update an environment's values directly, bypassing the normal
2346 checks that occur when users try to set items.
2347 """
2348 self.__dict__['overrides'].update(dict)
2349
2351 return self.__dict__['__subject'].gvars()
2352
2357
2358
2362
2363
2364
2365
2366
2367
2368
2369 Environment = Base
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383 -def NoSubstitutionProxy(subject):
2384 class _NoSubstitutionProxy(Environment):
2385 def __init__(self, subject):
2386 self.__dict__['__subject'] = subject
2387 def __getattr__(self, name):
2388 return getattr(self.__dict__['__subject'], name)
2389 def __setattr__(self, name, value):
2390 return setattr(self.__dict__['__subject'], name, value)
2391 def executor_to_lvars(self, kwdict):
2392 if kwdict.has_key('executor'):
2393 kwdict['lvars'] = kwdict['executor'].get_lvars()
2394 del kwdict['executor']
2395 else:
2396 kwdict['lvars'] = {}
2397 def raw_to_mode(self, dict):
2398 try:
2399 raw = dict['raw']
2400 except KeyError:
2401 pass
2402 else:
2403 del dict['raw']
2404 dict['mode'] = raw
2405 def subst(self, string, *args, **kwargs):
2406 return string
2407 def subst_kw(self, kw, *args, **kwargs):
2408 return kw
2409 def subst_list(self, string, *args, **kwargs):
2410 nargs = (string, self,) + args
2411 nkw = kwargs.copy()
2412 nkw['gvars'] = {}
2413 self.executor_to_lvars(nkw)
2414 self.raw_to_mode(nkw)
2415 return SCons.Subst.scons_subst_list(*nargs, **nkw)
2416 def subst_target_source(self, string, *args, **kwargs):
2417 nargs = (string, self,) + args
2418 nkw = kwargs.copy()
2419 nkw['gvars'] = {}
2420 self.executor_to_lvars(nkw)
2421 self.raw_to_mode(nkw)
2422 return SCons.Subst.scons_subst(*nargs, **nkw)
2423 return _NoSubstitutionProxy(subject)
2424
2425
2426
2427
2428
2429
2430