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 5357 2011/09/09 21:31:03 bdeegan"
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 from SCons.Debug import logInstanceCreation
47 import SCons.Defaults
48 import SCons.Errors
49 import SCons.Memoize
50 import SCons.Node
51 import SCons.Node.Alias
52 import SCons.Node.FS
53 import SCons.Node.Python
54 import SCons.Platform
55 import SCons.SConf
56 import SCons.SConsign
57 import SCons.Subst
58 import SCons.Tool
59 import SCons.Util
60 import SCons.Warnings
61
64
65 _null = _Null
66
67 _warn_copy_deprecated = True
68 _warn_source_signatures_deprecated = True
69 _warn_target_signatures_deprecated = True
70
71 CleanTargets = {}
72 CalculatorArgs = {}
73
74 semi_deepcopy = SCons.Util.semi_deepcopy
75
76
77
78
79 UserError = SCons.Errors.UserError
80
83
84 AliasBuilder = SCons.Builder.Builder(action = alias_builder,
85 target_factory = SCons.Node.Alias.default_ans.Alias,
86 source_factory = SCons.Node.FS.Entry,
87 multi = 1,
88 is_explicit = None,
89 name='AliasBuilder')
90
106
107
108
109
110 reserved_construction_var_names = [
111 'CHANGED_SOURCES',
112 'CHANGED_TARGETS',
113 'SOURCE',
114 'SOURCES',
115 'TARGET',
116 'TARGETS',
117 'UNCHANGED_SOURCES',
118 'UNCHANGED_TARGETS',
119 ]
120
121 future_reserved_construction_var_names = [
122
123
124
125 ]
126
135
139
144
157
161
165
167 """Delete duplicates from a sequence, keeping the first or last."""
168 seen={}
169 result=[]
170 if keep_last:
171 l.reverse()
172 for i in l:
173 try:
174 if i not in seen:
175 result.append(i)
176 seen[i]=1
177 except TypeError:
178
179 result.append(i)
180 if keep_last:
181 result.reverse()
182 return result
183
184
185
186
187
188
189
190
191
192
193
194
195
196
198 """
199 A generic Wrapper class that associates a method (which can
200 actually be any callable) with an object. As part of creating this
201 MethodWrapper object an attribute with the specified (by default,
202 the name of the supplied method) is added to the underlying object.
203 When that new "method" is called, our __call__() method adds the
204 object as the first argument, simulating the Python behavior of
205 supplying "self" on method calls.
206
207 We hang on to the name by which the method was added to the underlying
208 base class so that we can provide a method to "clone" ourselves onto
209 a new underlying object being copied (without which we wouldn't need
210 to save that info).
211 """
212 - def __init__(self, object, method, name=None):
213 if name is None:
214 name = method.__name__
215 self.object = object
216 self.method = method
217 self.name = name
218 setattr(self.object, name, self)
219
221 nargs = (self.object,) + args
222 return self.method(*nargs, **kwargs)
223
224 - def clone(self, new_object):
225 """
226 Returns an object that re-binds the underlying "method" to
227 the specified new object.
228 """
229 return self.__class__(new_object, self.method, self.name)
230
232 """
233 A MethodWrapper subclass that that associates an environment with
234 a Builder.
235
236 This mainly exists to wrap the __call__() function so that all calls
237 to Builders can have their argument lists massaged in the same way
238 (treat a lone argument as the source, treat two arguments as target
239 then source, make sure both target and source are lists) without
240 having to have cut-and-paste code to do it.
241
242 As a bit of obsessive backwards compatibility, we also intercept
243 attempts to get or set the "env" or "builder" attributes, which were
244 the names we used before we put the common functionality into the
245 MethodWrapper base class. We'll keep this around for a while in case
246 people shipped Tool modules that reached into the wrapper (like the
247 Tool/qt.py module does, or did). There shouldn't be a lot attribute
248 fetching or setting on these, so a little extra work shouldn't hurt.
249 """
251 if source is _null:
252 source = target
253 target = None
254 if target is not None and not SCons.Util.is_List(target):
255 target = [target]
256 if source is not None and not SCons.Util.is_List(source):
257 source = [source]
258 return MethodWrapper.__call__(self, target, source, *args, **kw)
259
261 return '<BuilderWrapper %s>' % repr(self.name)
262
265
267 if name == 'env':
268 return self.object
269 elif name == 'builder':
270 return self.method
271 else:
272 raise AttributeError(name)
273
275 if name == 'env':
276 self.object = value
277 elif name == 'builder':
278 self.method = value
279 else:
280 self.__dict__[name] = value
281
282
283
284
285
286
287
288
289
290
291
292
294 """This is a dictionary-like class used by an Environment to hold
295 the Builders. We need to do this because every time someone changes
296 the Builders in the Environment's BUILDERS dictionary, we must
297 update the Environment's attributes."""
299
300
301
302 self.env = env
303 UserDict.__init__(self, dict)
304
306 return self.__class__(self.data, self.env)
307
309 try:
310 method = getattr(self.env, item).method
311 except AttributeError:
312 pass
313 else:
314 self.env.RemoveMethod(method)
315 UserDict.__setitem__(self, item, val)
316 BuilderWrapper(self.env, val, item)
317
319 UserDict.__delitem__(self, item)
320 delattr(self.env, item)
321
325
326
327
328 _is_valid_var = re.compile(r'[_a-zA-Z]\w*$')
329
331 """Return if the specified string is a legitimate construction
332 variable.
333 """
334 return _is_valid_var.match(varstr)
335
336
337
339 """Base class for different flavors of construction environments.
340
341 This class contains a minimal set of methods that handle contruction
342 variable expansion and conversion of strings to Nodes, which may or
343 may not be actually useful as a stand-alone class. Which methods
344 ended up in this class is pretty arbitrary right now. They're
345 basically the ones which we've empirically determined are common to
346 the different construction environment subclasses, and most of the
347 others that use or touch the underlying dictionary of construction
348 variables.
349
350 Eventually, this class should contain all the methods that we
351 determine are necessary for a "minimal" interface to the build engine.
352 A full "native Python" SCons environment has gotten pretty heavyweight
353 with all of the methods and Tools and construction variables we've
354 jammed in there, so it would be nice to have a lighter weight
355 alternative for interfaces that don't need all of the bells and
356 whistles. (At some point, we'll also probably rename this class
357 "Base," since that more reflects what we want this class to become,
358 but because we've released comments that tell people to subclass
359 Environment.Base to create their own flavors of construction
360 environment, we'll save that for a future refactoring when this
361 class actually becomes useful.)
362 """
363
364 if SCons.Memoize.use_memoizer:
365 __metaclass__ = SCons.Memoize.Memoized_Metaclass
366
377
378
397
399 return cmp(self._dict, other._dict)
400
402 special = self._special_del.get(key)
403 if special:
404 special(self, key)
405 else:
406 del self._dict[key]
407
409 return self._dict[key]
410
412
413
414
415
416
417
418
419
420
421
422
423
424 if key in self._special_set_keys:
425 self._special_set[key](self, key, value)
426 else:
427
428
429
430
431 if key not in self._dict \
432 and not _is_valid_var.match(key):
433 raise SCons.Errors.UserError("Illegal construction variable `%s'" % key)
434 self._dict[key] = value
435
436 - def get(self, key, default=None):
437 """Emulates the get() method of dictionaries."""
438 return self._dict.get(key, default)
439
441 return key in self._dict
442
445
447 return list(self._dict.items())
448
450 if node_factory is _null:
451 node_factory = self.fs.File
452 if lookup_list is _null:
453 lookup_list = self.lookup_list
454
455 if not args:
456 return []
457
458 args = SCons.Util.flatten(args)
459
460 nodes = []
461 for v in args:
462 if SCons.Util.is_String(v):
463 n = None
464 for l in lookup_list:
465 n = l(v)
466 if n is not None:
467 break
468 if n is not None:
469 if SCons.Util.is_String(n):
470
471 kw['raw'] = 1
472 n = self.subst(n, **kw)
473 if node_factory:
474 n = node_factory(n)
475 if SCons.Util.is_List(n):
476 nodes.extend(n)
477 else:
478 nodes.append(n)
479 elif node_factory:
480
481 kw['raw'] = 1
482 v = node_factory(self.subst(v, **kw))
483 if SCons.Util.is_List(v):
484 nodes.extend(v)
485 else:
486 nodes.append(v)
487 else:
488 nodes.append(v)
489
490 return nodes
491
494
497
498 - def subst(self, string, raw=0, target=None, source=None, conv=None, executor=None):
499 """Recursively interpolates construction variables from the
500 Environment into the specified string, returning the expanded
501 result. Construction variables are specified by a $ prefix
502 in the string and begin with an initial underscore or
503 alphabetic character followed by any number of underscores
504 or alphanumeric characters. The construction variable names
505 may be surrounded by curly braces to separate the name from
506 trailing characters.
507 """
508 gvars = self.gvars()
509 lvars = self.lvars()
510 lvars['__env__'] = self
511 if executor:
512 lvars.update(executor.get_lvars())
513 return SCons.Subst.scons_subst(string, self, raw, target, source, gvars, lvars, conv)
514
515 - def subst_kw(self, kw, raw=0, target=None, source=None):
516 nkw = {}
517 for k, v in kw.items():
518 k = self.subst(k, raw, target, source)
519 if SCons.Util.is_String(v):
520 v = self.subst(v, raw, target, source)
521 nkw[k] = v
522 return nkw
523
524 - def subst_list(self, string, raw=0, target=None, source=None, conv=None, executor=None):
533
534 - def subst_path(self, path, target=None, source=None):
535 """Substitute a path list, turning EntryProxies into Nodes
536 and leaving Nodes (and other objects) as-is."""
537
538 if not SCons.Util.is_List(path):
539 path = [path]
540
541 def s(obj):
542 """This is the "string conversion" routine that we have our
543 substitutions use to return Nodes, not strings. This relies
544 on the fact that an EntryProxy object has a get() method that
545 returns the underlying Node that it wraps, which is a bit of
546 architectural dependence that we might need to break or modify
547 in the future in response to additional requirements."""
548 try:
549 get = obj.get
550 except AttributeError:
551 obj = SCons.Util.to_String_for_subst(obj)
552 else:
553 obj = get()
554 return obj
555
556 r = []
557 for p in path:
558 if SCons.Util.is_String(p):
559 p = self.subst(p, target=target, source=source, conv=s)
560 if SCons.Util.is_List(p):
561 if len(p) == 1:
562 p = p[0]
563 else:
564
565
566
567 p = ''.join(map(SCons.Util.to_String_for_subst, p))
568 else:
569 p = s(p)
570 r.append(p)
571 return r
572
573 subst_target_source = subst
574
576 import subprocess
577
578 kw = { 'stdin' : 'devnull',
579 'stdout' : subprocess.PIPE,
580 'stderr' : subprocess.PIPE,
581 'universal_newlines' : True,
582 }
583
584
585 if not SCons.Util.is_List(command): kw['shell'] = True
586
587 p = SCons.Action._subproc(self, command, **kw)
588 out,err = p.communicate()
589 status = p.wait()
590 if err:
591 sys.stderr.write(unicode(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 self.added_methods = [dm for dm in self.added_methods if not dm.method is function]
611
613 """
614 Produce a modified environment whose variables are overriden by
615 the overrides dictionaries. "overrides" is a dictionary that
616 will override the variables of this environment.
617
618 This function is much more efficient than Clone() or creating
619 a new Environment because it doesn't copy the construction
620 environment dictionary, it just wraps the underlying construction
621 environment, and doesn't even create a wrapper object if there
622 are no overrides.
623 """
624 if not overrides: return self
625 o = copy_non_reserved_keywords(overrides)
626 if not o: return self
627 overrides = {}
628 merges = None
629 for key, value in o.items():
630 if key == 'parse_flags':
631 merges = value
632 else:
633 overrides[key] = SCons.Subst.scons_subst_once(value, self, key)
634 env = OverrideEnvironment(self, overrides)
635 if merges: env.MergeFlags(merges)
636 return env
637
639 """
640 Parse the set of flags and return a dict with the flags placed
641 in the appropriate entry. The flags are treated as a typical
642 set of command-line flags for a GNU-like toolchain and used to
643 populate the entries in the dict immediately below. If one of
644 the flag strings begins with a bang (exclamation mark), it is
645 assumed to be a command and the rest of the string is executed;
646 the result of that evaluation is then added to the dict.
647 """
648 dict = {
649 'ASFLAGS' : SCons.Util.CLVar(''),
650 'CFLAGS' : SCons.Util.CLVar(''),
651 'CCFLAGS' : SCons.Util.CLVar(''),
652 'CXXFLAGS' : 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 def do_parse(arg):
665
666 if not arg:
667 return
668
669 if not SCons.Util.is_String(arg):
670 for t in arg: do_parse(t)
671 return
672
673
674 if arg[0] == '!':
675 arg = self.backtick(arg[1:])
676
677
678 def append_define(name, dict = dict):
679 t = name.split('=')
680 if len(t) == 1:
681 dict['CPPDEFINES'].append(name)
682 else:
683 dict['CPPDEFINES'].append([t[0], '='.join(t[1:])])
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705 params = shlex.split(arg)
706 append_next_arg_to = None
707 for arg in params:
708 if append_next_arg_to:
709 if append_next_arg_to == 'CPPDEFINES':
710 append_define(arg)
711 elif append_next_arg_to == '-include':
712 t = ('-include', self.fs.File(arg))
713 dict['CCFLAGS'].append(t)
714 elif append_next_arg_to == '-isysroot':
715 t = ('-isysroot', arg)
716 dict['CCFLAGS'].append(t)
717 dict['LINKFLAGS'].append(t)
718 elif append_next_arg_to == '-arch':
719 t = ('-arch', arg)
720 dict['CCFLAGS'].append(t)
721 dict['LINKFLAGS'].append(t)
722 else:
723 dict[append_next_arg_to].append(arg)
724 append_next_arg_to = None
725 elif not arg[0] in ['-', '+']:
726 dict['LIBS'].append(self.fs.File(arg))
727 elif arg == '-dylib_file':
728 dict['LINKFLAGS'].append(arg)
729 append_next_arg_to = 'LINKFLAGS'
730 elif arg[:2] == '-L':
731 if arg[2:]:
732 dict['LIBPATH'].append(arg[2:])
733 else:
734 append_next_arg_to = 'LIBPATH'
735 elif arg[:2] == '-l':
736 if arg[2:]:
737 dict['LIBS'].append(arg[2:])
738 else:
739 append_next_arg_to = 'LIBS'
740 elif arg[:2] == '-I':
741 if arg[2:]:
742 dict['CPPPATH'].append(arg[2:])
743 else:
744 append_next_arg_to = 'CPPPATH'
745 elif arg[:4] == '-Wa,':
746 dict['ASFLAGS'].append(arg[4:])
747 dict['CCFLAGS'].append(arg)
748 elif arg[:4] == '-Wl,':
749 if arg[:11] == '-Wl,-rpath=':
750 dict['RPATH'].append(arg[11:])
751 elif arg[:7] == '-Wl,-R,':
752 dict['RPATH'].append(arg[7:])
753 elif arg[:6] == '-Wl,-R':
754 dict['RPATH'].append(arg[6:])
755 else:
756 dict['LINKFLAGS'].append(arg)
757 elif arg[:4] == '-Wp,':
758 dict['CPPFLAGS'].append(arg)
759 elif arg[:2] == '-D':
760 if arg[2:]:
761 append_define(arg[2:])
762 else:
763 append_next_arg_to = 'CPPDEFINES'
764 elif arg == '-framework':
765 append_next_arg_to = 'FRAMEWORKS'
766 elif arg[:14] == '-frameworkdir=':
767 dict['FRAMEWORKPATH'].append(arg[14:])
768 elif arg[:2] == '-F':
769 if arg[2:]:
770 dict['FRAMEWORKPATH'].append(arg[2:])
771 else:
772 append_next_arg_to = 'FRAMEWORKPATH'
773 elif arg in ['-mno-cygwin',
774 '-pthread',
775 '-openmp',
776 '-fopenmp']:
777 dict['CCFLAGS'].append(arg)
778 dict['LINKFLAGS'].append(arg)
779 elif arg == '-mwindows':
780 dict['LINKFLAGS'].append(arg)
781 elif arg[:5] == '-std=':
782 if arg[5:].find('++')!=-1:
783 key='CXXFLAGS'
784 else:
785 key='CFLAGS'
786 dict[key].append(arg)
787 elif arg[0] == '+':
788 dict['CCFLAGS'].append(arg)
789 dict['LINKFLAGS'].append(arg)
790 elif arg in ['-include', '-isysroot', '-arch']:
791 append_next_arg_to = arg
792 else:
793 dict['CCFLAGS'].append(arg)
794
795 for arg in flags:
796 do_parse(arg)
797 return dict
798
800 """
801 Merge the dict in args into the construction variables of this
802 env, or the passed-in dict. If args is not a dict, it is
803 converted into a dict using ParseFlags. If unique is not set,
804 the flags are appended rather than merged.
805 """
806
807 if dict is None:
808 dict = self
809 if not SCons.Util.is_Dict(args):
810 args = self.ParseFlags(args)
811 if not unique:
812 self.Append(**args)
813 return self
814 for key, value in args.items():
815 if not value:
816 continue
817 try:
818 orig = self[key]
819 except KeyError:
820 orig = value
821 else:
822 if not orig:
823 orig = value
824 elif value:
825
826
827
828
829
830
831 try:
832 orig = orig + value
833 except (KeyError, TypeError):
834 try:
835 add_to_orig = orig.append
836 except AttributeError:
837 value.insert(0, orig)
838 orig = value
839 else:
840 add_to_orig(value)
841 t = []
842 if key[-4:] == 'PATH':
843
844 for v in orig:
845 if v not in t:
846 t.append(v)
847 else:
848
849 orig.reverse()
850 for v in orig:
851 if v not in t:
852 t.insert(0, v)
853 self[key] = t
854 return self
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
879
883
885 f = SCons.Defaults.DefaultEnvironment().copy_from_cache
886 return f(src, dst)
887
888 -class Base(SubstitutionEnvironment):
889 """Base class for "real" construction Environments. These are the
890 primary objects used to communicate dependency and construction
891 information to the build engine.
892
893 Keyword arguments supplied when the construction Environment
894 is created are construction variables used to initialize the
895 Environment.
896 """
897
898 memoizer_counters = []
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914 - def __init__(self,
915 platform=None,
916 tools=None,
917 toolpath=None,
918 variables=None,
919 parse_flags = None,
920 **kw):
921 """
922 Initialization of a basic SCons construction environment,
923 including setting up special construction variables like BUILDER,
924 PLATFORM, etc., and searching for and applying available Tools.
925
926 Note that we do *not* call the underlying base class
927 (SubsitutionEnvironment) initialization, because we need to
928 initialize things in a very specific order that doesn't work
929 with the much simpler base class initialization.
930 """
931 if __debug__: logInstanceCreation(self, 'Environment.Base')
932 self._memo = {}
933 self.fs = SCons.Node.FS.get_default_fs()
934 self.ans = SCons.Node.Alias.default_ans
935 self.lookup_list = SCons.Node.arg2nodes_lookups
936 self._dict = semi_deepcopy(SCons.Defaults.ConstructionEnvironment)
937 self._init_special()
938 self.added_methods = []
939
940
941
942
943
944
945
946 self.decide_target = default_decide_target
947 self.decide_source = default_decide_source
948
949 self.copy_from_cache = default_copy_from_cache
950
951 self._dict['BUILDERS'] = BuilderDict(self._dict['BUILDERS'], self)
952
953 if platform is None:
954 platform = self._dict.get('PLATFORM', None)
955 if platform is None:
956 platform = SCons.Platform.Platform()
957 if SCons.Util.is_String(platform):
958 platform = SCons.Platform.Platform(platform)
959 self._dict['PLATFORM'] = str(platform)
960 platform(self)
961
962 self._dict['HOST_OS'] = self._dict.get('HOST_OS',None)
963 self._dict['HOST_ARCH'] = self._dict.get('HOST_ARCH',None)
964
965
966 self._dict['TARGET_OS'] = self._dict.get('HOST_OS',None)
967 self._dict['TARGET_ARCH'] = self._dict.get('HOST_ARCH',None)
968
969
970
971
972
973 if 'options' in kw:
974
975
976 variables = kw['options']
977 del kw['options']
978 self.Replace(**kw)
979 keys = list(kw.keys())
980 if variables:
981 keys = keys + list(variables.keys())
982 variables.Update(self)
983
984 save = {}
985 for k in keys:
986 try:
987 save[k] = self._dict[k]
988 except KeyError:
989
990
991 pass
992
993 SCons.Tool.Initializers(self)
994
995 if tools is None:
996 tools = self._dict.get('TOOLS', None)
997 if tools is None:
998 tools = ['default']
999 apply_tools(self, tools, toolpath)
1000
1001
1002
1003
1004 for key, val in save.items():
1005 self._dict[key] = val
1006
1007
1008 if parse_flags: self.MergeFlags(parse_flags)
1009
1010
1011
1012
1013
1014
1016 """Fetch the builder with the specified name from the environment.
1017 """
1018 try:
1019 return self._dict['BUILDERS'][name]
1020 except KeyError:
1021 return None
1022
1024 try:
1025 path = self._CacheDir_path
1026 except AttributeError:
1027 path = SCons.Defaults.DefaultEnvironment()._CacheDir_path
1028 try:
1029 if path == self._last_CacheDir_path:
1030 return self._last_CacheDir
1031 except AttributeError:
1032 pass
1033 cd = SCons.CacheDir.CacheDir(path)
1034 self._last_CacheDir_path = path
1035 self._last_CacheDir = cd
1036 return cd
1037
1039 """Return a factory function for creating Nodes for this
1040 construction environment.
1041 """
1042 name = default
1043 try:
1044 is_node = issubclass(factory, SCons.Node.FS.Base)
1045 except TypeError:
1046
1047
1048 pass
1049 else:
1050 if is_node:
1051
1052
1053
1054
1055 try: name = factory.__name__
1056 except AttributeError: pass
1057 else: factory = None
1058 if not factory:
1059
1060
1061
1062
1063
1064 factory = getattr(self.fs, name)
1065 return factory
1066
1067 memoizer_counters.append(SCons.Memoize.CountValue('_gsm'))
1068
1070 try:
1071 return self._memo['_gsm']
1072 except KeyError:
1073 pass
1074
1075 result = {}
1076
1077 try:
1078 scanners = self._dict['SCANNERS']
1079 except KeyError:
1080 pass
1081 else:
1082
1083
1084
1085
1086 if not SCons.Util.is_List(scanners):
1087 scanners = [scanners]
1088 else:
1089 scanners = scanners[:]
1090 scanners.reverse()
1091 for scanner in scanners:
1092 for k in scanner.get_skeys(self):
1093 if k and self['PLATFORM'] == 'win32':
1094 k = k.lower()
1095 result[k] = scanner
1096
1097 self._memo['_gsm'] = result
1098
1099 return result
1100
1102 """Find the appropriate scanner given a key (usually a file suffix).
1103 """
1104 if skey and self['PLATFORM'] == 'win32':
1105 skey = skey.lower()
1106 return self._gsm().get(skey)
1107
1109 """Delete the cached scanner map (if we need to).
1110 """
1111 try:
1112 del self._memo['_gsm']
1113 except KeyError:
1114 pass
1115
1117 """Update an environment's values directly, bypassing the normal
1118 checks that occur when users try to set items.
1119 """
1120 self._dict.update(dict)
1121
1123 try:
1124 return self.src_sig_type
1125 except AttributeError:
1126 t = SCons.Defaults.DefaultEnvironment().src_sig_type
1127 self.src_sig_type = t
1128 return t
1129
1131 try:
1132 return self.tgt_sig_type
1133 except AttributeError:
1134 t = SCons.Defaults.DefaultEnvironment().tgt_sig_type
1135 self.tgt_sig_type = t
1136 return t
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1148 """Append values to existing construction variables
1149 in an Environment.
1150 """
1151 kw = copy_non_reserved_keywords(kw)
1152 for key, val in kw.items():
1153
1154
1155
1156
1157 try:
1158 if key == 'CPPDEFINES' and SCons.Util.is_String(self._dict[key]):
1159 self._dict[key] = [self._dict[key]]
1160 orig = self._dict[key]
1161 except KeyError:
1162
1163
1164 if key == 'CPPDEFINES' and SCons.Util.is_String(val):
1165 self._dict[key] = [val]
1166 else:
1167 self._dict[key] = val
1168 else:
1169 try:
1170
1171
1172
1173
1174
1175 update_dict = orig.update
1176 except AttributeError:
1177 try:
1178
1179
1180
1181 self._dict[key] = orig + val
1182 except (KeyError, TypeError):
1183 try:
1184
1185 add_to_orig = orig.append
1186 except AttributeError:
1187
1188
1189
1190
1191
1192 if orig:
1193 val.insert(0, orig)
1194 self._dict[key] = val
1195 else:
1196
1197
1198 if val:
1199 add_to_orig(val)
1200 else:
1201
1202
1203 if SCons.Util.is_List(val):
1204 if key == 'CPPDEFINES':
1205 orig = orig.items()
1206 orig += val
1207 self._dict[key] = orig
1208 else:
1209 for v in val:
1210 orig[v] = None
1211 else:
1212 try:
1213 update_dict(val)
1214 except (AttributeError, TypeError, ValueError):
1215 if SCons.Util.is_Dict(val):
1216 for k, v in val.items():
1217 orig[k] = v
1218 else:
1219 orig[val] = None
1220 self.scanner_map_delete(kw)
1221
1222
1223
1230
1231 - def AppendENVPath(self, name, newpath, envname = 'ENV',
1232 sep = os.pathsep, delete_existing=1):
1233 """Append path elements to the path 'name' in the 'ENV'
1234 dictionary for this environment. Will only add any particular
1235 path once, and will normpath and normcase all paths to help
1236 assure this. This can also handle the case where the env
1237 variable is a list instead of a string.
1238
1239 If delete_existing is 0, a newpath which is already in the path
1240 will not be moved to the end (it will be left where it is).
1241 """
1242
1243 orig = ''
1244 if envname in self._dict and name in self._dict[envname]:
1245 orig = self._dict[envname][name]
1246
1247 nv = SCons.Util.AppendPath(orig, newpath, sep, delete_existing,
1248 canonicalize=self._canonicalize)
1249
1250 if envname not in self._dict:
1251 self._dict[envname] = {}
1252
1253 self._dict[envname][name] = nv
1254
1256 """Append values to existing construction variables
1257 in an Environment, if they're not already there.
1258 If delete_existing is 1, removes existing values first, so
1259 values move to end.
1260 """
1261 kw = copy_non_reserved_keywords(kw)
1262 for key, val in kw.items():
1263 if SCons.Util.is_List(val):
1264 val = _delete_duplicates(val, delete_existing)
1265 if key not in self._dict or self._dict[key] in ('', None):
1266 self._dict[key] = val
1267 elif SCons.Util.is_Dict(self._dict[key]) and \
1268 SCons.Util.is_Dict(val):
1269 self._dict[key].update(val)
1270 elif SCons.Util.is_List(val):
1271 dk = self._dict[key]
1272 if key == 'CPPDEFINES':
1273 tmp = []
1274 for i in val:
1275 if SCons.Util.is_List(i):
1276 if len(i) >= 2:
1277 tmp.append((i[0], i[1]))
1278 else:
1279 tmp.append((i[0],))
1280 elif SCons.Util.is_Tuple(i):
1281 tmp.append(i)
1282 else:
1283 tmp.append((i,))
1284 val = tmp
1285 if SCons.Util.is_Dict(dk):
1286 dk = dk.items()
1287 elif SCons.Util.is_String(dk):
1288 dk = [(dk,)]
1289 else:
1290 tmp = []
1291 for i in dk:
1292 if SCons.Util.is_List(i):
1293 if len(i) >= 2:
1294 tmp.append((i[0], i[1]))
1295 else:
1296 tmp.append((i[0],))
1297 elif SCons.Util.is_Tuple(i):
1298 tmp.append(i)
1299 else:
1300 tmp.append((i,))
1301 dk = tmp
1302 else:
1303 if not SCons.Util.is_List(dk):
1304 dk = [dk]
1305 if delete_existing:
1306 dk = [x for x in dk if x not in val]
1307 else:
1308 val = [x for x in val if x not in dk]
1309 self._dict[key] = dk + val
1310 else:
1311 dk = self._dict[key]
1312 if SCons.Util.is_List(dk):
1313 if key == 'CPPDEFINES':
1314 tmp = []
1315 for i in dk:
1316 if SCons.Util.is_List(i):
1317 if len(i) >= 2:
1318 tmp.append((i[0], i[1]))
1319 else:
1320 tmp.append((i[0],))
1321 elif SCons.Util.is_Tuple(i):
1322 tmp.append(i)
1323 else:
1324 tmp.append((i,))
1325 dk = tmp
1326 if SCons.Util.is_Dict(val):
1327 val = val.items()
1328 elif SCons.Util.is_String(val):
1329 val = [(val,)]
1330 if delete_existing:
1331 dk = filter(lambda x, val=val: x not in val, dk)
1332 self._dict[key] = dk + val
1333 else:
1334 dk = [x for x in dk if x not in val]
1335 self._dict[key] = dk + val
1336 else:
1337
1338
1339 if delete_existing:
1340 dk = filter(lambda x, val=val: x not in val, dk)
1341 self._dict[key] = dk + [val]
1342 else:
1343 if not val in dk:
1344 self._dict[key] = dk + [val]
1345 else:
1346 if key == 'CPPDEFINES':
1347 if SCons.Util.is_String(dk):
1348 dk = [dk]
1349 elif SCons.Util.is_Dict(dk):
1350 dk = dk.items()
1351 if SCons.Util.is_String(val):
1352 if val in dk:
1353 val = []
1354 else:
1355 val = [val]
1356 elif SCons.Util.is_Dict(val):
1357 tmp = []
1358 for i,j in val.iteritems():
1359 if j is not None:
1360 tmp.append((i,j))
1361 else:
1362 tmp.append(i)
1363 val = tmp
1364 if delete_existing:
1365 dk = [x for x in dk if x not in val]
1366 self._dict[key] = dk + val
1367 self.scanner_map_delete(kw)
1368
1369 - def Clone(self, tools=[], toolpath=None, parse_flags = None, **kw):
1370 """Return a copy of a construction Environment. The
1371 copy is like a Python "deep copy"--that is, independent
1372 copies are made recursively of each objects--except that
1373 a reference is copied when an object is not deep-copyable
1374 (like a function). There are no references to any mutable
1375 objects in the original Environment.
1376 """
1377 clone = copy.copy(self)
1378 clone._dict = semi_deepcopy(self._dict)
1379
1380 try:
1381 cbd = clone._dict['BUILDERS']
1382 except KeyError:
1383 pass
1384 else:
1385 clone._dict['BUILDERS'] = BuilderDict(cbd, clone)
1386
1387
1388
1389
1390
1391 clone.added_methods = []
1392 for mw in self.added_methods:
1393 if mw == getattr(self, mw.name):
1394 clone.added_methods.append(mw.clone(clone))
1395
1396 clone._memo = {}
1397
1398
1399
1400 kw = copy_non_reserved_keywords(kw)
1401 new = {}
1402 for key, value in kw.items():
1403 new[key] = SCons.Subst.scons_subst_once(value, self, key)
1404 clone.Replace(**new)
1405
1406 apply_tools(clone, tools, toolpath)
1407
1408
1409 clone.Replace(**new)
1410
1411
1412 if parse_flags: clone.MergeFlags(parse_flags)
1413
1414 if __debug__: logInstanceCreation(self, 'Environment.EnvironmentClone')
1415 return clone
1416
1417 - def Copy(self, *args, **kw):
1424
1429
1430 - def _changed_content(self, dependency, target, prev_ni):
1431 return dependency.changed_content(target, prev_ni)
1432
1440
1441 - def _changed_timestamp_then_content(self, dependency, target, prev_ni):
1442 return dependency.changed_timestamp_then_content(target, prev_ni)
1443
1446
1449
1451 return self.fs.copy(src, dst)
1452
1454 return self.fs.copy2(src, dst)
1455
1479
1481 """Return the first available program in progs.
1482 """
1483 if not SCons.Util.is_List(progs):
1484 progs = [ progs ]
1485 for prog in progs:
1486 path = self.WhereIs(prog)
1487 if path: return prog
1488 return None
1489
1491 if not args:
1492 return self._dict
1493 dlist = [self._dict[x] for x in args]
1494 if len(dlist) == 1:
1495 dlist = dlist[0]
1496 return dlist
1497
1498 - def Dump(self, key = None):
1499 """
1500 Using the standard Python pretty printer, dump the contents of the
1501 scons build environment to stdout.
1502
1503 If the key passed in is anything other than None, then that will
1504 be used as an index into the build environment dictionary and
1505 whatever is found there will be fed into the pretty printer. Note
1506 that this key is case sensitive.
1507 """
1508 import pprint
1509 pp = pprint.PrettyPrinter(indent=2)
1510 if key:
1511 dict = self.Dictionary(key)
1512 else:
1513 dict = self.Dictionary()
1514 return pp.pformat(dict)
1515
1516 - def FindIxes(self, paths, prefix, suffix):
1517 """
1518 Search a list of paths for something that matches the prefix and suffix.
1519
1520 paths - the list of paths or nodes.
1521 prefix - construction variable for the prefix.
1522 suffix - construction variable for the suffix.
1523 """
1524
1525 suffix = self.subst('$'+suffix)
1526 prefix = self.subst('$'+prefix)
1527
1528 for path in paths:
1529 dir,name = os.path.split(str(path))
1530 if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix:
1531 return path
1532
1533 - def ParseConfig(self, command, function=None, unique=1):
1534 """
1535 Use the specified function to parse the output of the command
1536 in order to modify the current environment. The 'command' can
1537 be a string or a list of strings representing a command and
1538 its arguments. 'Function' is an optional argument that takes
1539 the environment, the output of the command, and the unique flag.
1540 If no function is specified, MergeFlags, which treats the output
1541 as the result of a typical 'X-config' command (i.e. gtk-config),
1542 will merge the output into the appropriate variables.
1543 """
1544 if function is None:
1545 def parse_conf(env, cmd, unique=unique):
1546 return env.MergeFlags(cmd, unique)
1547 function = parse_conf
1548 if SCons.Util.is_List(command):
1549 command = ' '.join(command)
1550 command = self.subst(command)
1551 return function(self, self.backtick(command))
1552
1553 - def ParseDepends(self, filename, must_exist=None, only_one=0):
1554 """
1555 Parse a mkdep-style file for explicit dependencies. This is
1556 completely abusable, and should be unnecessary in the "normal"
1557 case of proper SCons configuration, but it may help make
1558 the transition from a Make hierarchy easier for some people
1559 to swallow. It can also be genuinely useful when using a tool
1560 that can write a .d file, but for which writing a scanner would
1561 be too complicated.
1562 """
1563 filename = self.subst(filename)
1564 try:
1565 fp = open(filename, 'r')
1566 except IOError:
1567 if must_exist:
1568 raise
1569 return
1570 lines = SCons.Util.LogicalLines(fp).readlines()
1571 lines = [l for l in lines if l[0] != '#']
1572 tdlist = []
1573 for line in lines:
1574 try:
1575 target, depends = line.split(':', 1)
1576 except (AttributeError, ValueError):
1577
1578
1579 pass
1580 else:
1581 tdlist.append((target.split(), depends.split()))
1582 if only_one:
1583 targets = []
1584 for td in tdlist:
1585 targets.extend(td[0])
1586 if len(targets) > 1:
1587 raise SCons.Errors.UserError(
1588 "More than one dependency target found in `%s': %s"
1589 % (filename, targets))
1590 for target, depends in tdlist:
1591 self.Depends(target, depends)
1592
1596
1598 """Prepend values to existing construction variables
1599 in an Environment.
1600 """
1601 kw = copy_non_reserved_keywords(kw)
1602 for key, val in kw.items():
1603
1604
1605
1606
1607 try:
1608 orig = self._dict[key]
1609 except KeyError:
1610
1611
1612 self._dict[key] = val
1613 else:
1614 try:
1615
1616
1617
1618
1619
1620 update_dict = orig.update
1621 except AttributeError:
1622 try:
1623
1624
1625
1626 self._dict[key] = val + orig
1627 except (KeyError, TypeError):
1628 try:
1629
1630 add_to_val = val.append
1631 except AttributeError:
1632
1633
1634
1635
1636 if val:
1637 orig.insert(0, val)
1638 else:
1639
1640
1641
1642 if orig:
1643 add_to_val(orig)
1644 self._dict[key] = val
1645 else:
1646
1647
1648 if SCons.Util.is_List(val):
1649 for v in val:
1650 orig[v] = None
1651 else:
1652 try:
1653 update_dict(val)
1654 except (AttributeError, TypeError, ValueError):
1655 if SCons.Util.is_Dict(val):
1656 for k, v in val.items():
1657 orig[k] = v
1658 else:
1659 orig[val] = None
1660 self.scanner_map_delete(kw)
1661
1662 - def PrependENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep,
1663 delete_existing=1):
1664 """Prepend path elements to the path 'name' in the 'ENV'
1665 dictionary for this environment. Will only add any particular
1666 path once, and will normpath and normcase all paths to help
1667 assure this. This can also handle the case where the env
1668 variable is a list instead of a string.
1669
1670 If delete_existing is 0, a newpath which is already in the path
1671 will not be moved to the front (it will be left where it is).
1672 """
1673
1674 orig = ''
1675 if envname in self._dict and name in self._dict[envname]:
1676 orig = self._dict[envname][name]
1677
1678 nv = SCons.Util.PrependPath(orig, newpath, sep, delete_existing,
1679 canonicalize=self._canonicalize)
1680
1681 if envname not in self._dict:
1682 self._dict[envname] = {}
1683
1684 self._dict[envname][name] = nv
1685
1687 """Prepend values to existing construction variables
1688 in an Environment, if they're not already there.
1689 If delete_existing is 1, removes existing values first, so
1690 values move to front.
1691 """
1692 kw = copy_non_reserved_keywords(kw)
1693 for key, val in kw.items():
1694 if SCons.Util.is_List(val):
1695 val = _delete_duplicates(val, not delete_existing)
1696 if key not in self._dict or self._dict[key] in ('', None):
1697 self._dict[key] = val
1698 elif SCons.Util.is_Dict(self._dict[key]) and \
1699 SCons.Util.is_Dict(val):
1700 self._dict[key].update(val)
1701 elif SCons.Util.is_List(val):
1702 dk = self._dict[key]
1703 if not SCons.Util.is_List(dk):
1704 dk = [dk]
1705 if delete_existing:
1706 dk = [x for x in dk if x not in val]
1707 else:
1708 val = [x for x in val if x not in dk]
1709 self._dict[key] = val + dk
1710 else:
1711 dk = self._dict[key]
1712 if SCons.Util.is_List(dk):
1713
1714
1715 if delete_existing:
1716 dk = [x for x in dk if x not in val]
1717 self._dict[key] = [val] + dk
1718 else:
1719 if not val in dk:
1720 self._dict[key] = [val] + dk
1721 else:
1722 if delete_existing:
1723 dk = [x for x in dk if x not in val]
1724 self._dict[key] = val + dk
1725 self.scanner_map_delete(kw)
1726
1728 """Replace existing construction variables in an Environment
1729 with new construction variables and/or values.
1730 """
1731 try:
1732 kwbd = kw['BUILDERS']
1733 except KeyError:
1734 pass
1735 else:
1736 kwbd = semi_deepcopy(kwbd)
1737 del kw['BUILDERS']
1738 self.__setitem__('BUILDERS', kwbd)
1739 kw = copy_non_reserved_keywords(kw)
1740 self._update(semi_deepcopy(kw))
1741 self.scanner_map_delete(kw)
1742
1743 - def ReplaceIxes(self, path, old_prefix, old_suffix, new_prefix, new_suffix):
1744 """
1745 Replace old_prefix with new_prefix and old_suffix with new_suffix.
1746
1747 env - Environment used to interpolate variables.
1748 path - the path that will be modified.
1749 old_prefix - construction variable for the old prefix.
1750 old_suffix - construction variable for the old suffix.
1751 new_prefix - construction variable for the new prefix.
1752 new_suffix - construction variable for the new suffix.
1753 """
1754 old_prefix = self.subst('$'+old_prefix)
1755 old_suffix = self.subst('$'+old_suffix)
1756
1757 new_prefix = self.subst('$'+new_prefix)
1758 new_suffix = self.subst('$'+new_suffix)
1759
1760 dir,name = os.path.split(str(path))
1761 if name[:len(old_prefix)] == old_prefix:
1762 name = name[len(old_prefix):]
1763 if name[-len(old_suffix):] == old_suffix:
1764 name = name[:-len(old_suffix)]
1765 return os.path.join(dir, new_prefix+name+new_suffix)
1766
1768 for k in kw.keys():
1769 if k in self._dict:
1770 del kw[k]
1771 self.Replace(**kw)
1772
1775
1784
1785 - def WhereIs(self, prog, path=None, pathext=None, reject=[]):
1786 """Find prog in the path.
1787 """
1788 if path is None:
1789 try:
1790 path = self['ENV']['PATH']
1791 except KeyError:
1792 pass
1793 elif SCons.Util.is_String(path):
1794 path = self.subst(path)
1795 if pathext is None:
1796 try:
1797 pathext = self['ENV']['PATHEXT']
1798 except KeyError:
1799 pass
1800 elif SCons.Util.is_String(pathext):
1801 pathext = self.subst(pathext)
1802 prog = self.subst(prog)
1803 path = SCons.Util.WhereIs(prog, path, pathext, reject)
1804 if path: return path
1805 return None
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815 - def Action(self, *args, **kw):
1816 def subst_string(a, self=self):
1817 if SCons.Util.is_String(a):
1818 a = self.subst(a)
1819 return a
1820 nargs = list(map(subst_string, args))
1821 nkw = self.subst_kw(kw)
1822 return SCons.Action.Action(*nargs, **nkw)
1823
1833
1834 - def AddPostAction(self, files, action):
1835 nodes = self.arg2nodes(files, self.fs.Entry)
1836 action = SCons.Action.Action(action)
1837 uniq = {}
1838 for executor in [n.get_executor() for n in nodes]:
1839 uniq[executor] = 1
1840 for executor in uniq.keys():
1841 executor.add_post_action(action)
1842 return nodes
1843
1844 - def Alias(self, target, source=[], action=None, **kw):
1896
1904
1912
1916
1922
1923 - def Clean(self, targets, files):
1932
1944
1945 - def Command(self, target, source, action, **kw):
1946 """Builds the supplied target files from the supplied
1947 source files using the supplied action. Action may
1948 be any type that the Builder constructor will accept
1949 for an action."""
1950 bkw = {
1951 'action' : action,
1952 'target_factory' : self.fs.Entry,
1953 'source_factory' : self.fs.Entry,
1954 }
1955 try: bkw['source_scanner'] = kw['source_scanner']
1956 except KeyError: pass
1957 else: del kw['source_scanner']
1958 bld = SCons.Builder.Builder(**bkw)
1959 return bld(self, target, source, **kw)
1960
1961 - def Depends(self, target, dependency):
1962 """Explicity specify that 'target's depend on 'dependency'."""
1963 tlist = self.arg2nodes(target, self.fs.Entry)
1964 dlist = self.arg2nodes(dependency, self.fs.Entry)
1965 for t in tlist:
1966 t.add_dependency(dlist)
1967 return tlist
1968
1969 - def Dir(self, name, *args, **kw):
1979
1981 """Tags a target so that it will not be cleaned by -c"""
1982 tlist = []
1983 for t in targets:
1984 tlist.extend(self.arg2nodes(t, self.fs.Entry))
1985 for t in tlist:
1986 t.set_noclean()
1987 return tlist
1988
1990 """Tags a target so that it will not be cached"""
1991 tlist = []
1992 for t in targets:
1993 tlist.extend(self.arg2nodes(t, self.fs.Entry))
1994 for t in tlist:
1995 t.set_nocache()
1996 return tlist
1997
1998 - def Entry(self, name, *args, **kw):
1999 """
2000 """
2001 s = self.subst(name)
2002 if SCons.Util.is_Sequence(s):
2003 result=[]
2004 for e in s:
2005 result.append(self.fs.Entry(e, *args, **kw))
2006 return result
2007 return self.fs.Entry(s, *args, **kw)
2008
2011
2012 - def Execute(self, action, *args, **kw):
2013 """Directly execute an action through an Environment
2014 """
2015 action = self.Action(action, *args, **kw)
2016 result = action([], [], self)
2017 if isinstance(result, SCons.Errors.BuildError):
2018 errstr = result.errstr
2019 if result.filename:
2020 errstr = result.filename + ': ' + errstr
2021 sys.stderr.write("scons: *** %s\n" % errstr)
2022 return result.status
2023 else:
2024 return result
2025
2026 - def File(self, name, *args, **kw):
2036
2041
2044
2051
2052 - def Glob(self, pattern, ondisk=True, source=False, strings=False):
2053 return self.fs.Glob(self.subst(pattern), ondisk, source, strings)
2054
2055 - def Ignore(self, target, dependency):
2062
2065
2066 - def Local(self, *targets):
2077
2085
2089
2090 - def Requires(self, target, prerequisite):
2091 """Specify that 'prerequisite' must be built before 'target',
2092 (but 'target' does not actually depend on 'prerequisite'
2093 and need not be rebuilt if it changes)."""
2094 tlist = self.arg2nodes(target, self.fs.Entry)
2095 plist = self.arg2nodes(prerequisite, self.fs.Entry)
2096 for t in tlist:
2097 t.add_prerequisite(plist)
2098 return tlist
2099
2108
2109 - def SConsignFile(self, name=".sconsign", dbm_module=None):
2110 if name is not None:
2111 name = self.subst(name)
2112 if not os.path.isabs(name):
2113 name = os.path.join(str(self.fs.SConstruct_dir), name)
2114 if name:
2115 name = os.path.normpath(name)
2116 sconsign_dir = os.path.dirname(name)
2117 if sconsign_dir and not os.path.exists(sconsign_dir):
2118 self.Execute(SCons.Defaults.Mkdir(sconsign_dir))
2119 SCons.SConsign.File(name, dbm_module)
2120
2122 """Tell scons that side_effects are built as side
2123 effects of building targets."""
2124 side_effects = self.arg2nodes(side_effect, self.fs.Entry)
2125 targets = self.arg2nodes(target, self.fs.Entry)
2126
2127 for side_effect in side_effects:
2128 if side_effect.multiple_side_effect_has_builder():
2129 raise SCons.Errors.UserError("Multiple ways to build the same target were specified for: %s" % str(side_effect))
2130 side_effect.add_source(targets)
2131 side_effect.side_effect = 1
2132 self.Precious(side_effect)
2133 for target in targets:
2134 target.side_effects.append(side_effect)
2135 return side_effects
2136
2146
2164
2166 """This function converts a string or list into a list of strings
2167 or Nodes. This makes things easier for users by allowing files to
2168 be specified as a white-space separated list to be split.
2169 The input rules are:
2170 - A single string containing names separated by spaces. These will be
2171 split apart at the spaces.
2172 - A single Node instance
2173 - A list containing either strings or Node instances. Any strings
2174 in the list are not split at spaces.
2175 In all cases, the function returns a list of Nodes and strings."""
2176 if SCons.Util.is_List(arg):
2177 return list(map(self.subst, arg))
2178 elif SCons.Util.is_String(arg):
2179 return self.subst(arg).split()
2180 else:
2181 return [self.subst(arg)]
2182
2204
2205 - def Value(self, value, built_value=None):
2209
2210 - def VariantDir(self, variant_dir, src_dir, duplicate=1):
2214
2229 build_source(node.all_children())
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240 return list(set(sources))
2241
2243 """ returns the list of all targets of the Install and InstallAs Builder.
2244 """
2245 from SCons.Tool import install
2246 if install._UNIQUE_INSTALLED_FILES is None:
2247 install._UNIQUE_INSTALLED_FILES = SCons.Util.uniquer_hashables(install._INSTALLED_FILES)
2248 return install._UNIQUE_INSTALLED_FILES
2249
2251 """A proxy that overrides variables in a wrapped construction
2252 environment by returning values from an overrides dictionary in
2253 preference to values from the underlying subject environment.
2254
2255 This is a lightweight (I hope) proxy that passes through most use of
2256 attributes to the underlying Environment.Base class, but has just
2257 enough additional methods defined to act like a real construction
2258 environment with overridden values. It can wrap either a Base
2259 construction environment, or another OverrideEnvironment, which
2260 can in turn nest arbitrary OverrideEnvironments...
2261
2262 Note that we do *not* call the underlying base class
2263 (SubsitutionEnvironment) initialization, because we get most of those
2264 from proxying the attributes of the subject construction environment.
2265 But because we subclass SubstitutionEnvironment, this class also
2266 has inherited arg2nodes() and subst*() methods; those methods can't
2267 be proxied because they need *this* object's methods to fetch the
2268 values from the overrides dictionary.
2269 """
2270
2271 - def __init__(self, subject, overrides={}):
2272 if __debug__: logInstanceCreation(self, 'Environment.OverrideEnvironment')
2273 self.__dict__['__subject'] = subject
2274 self.__dict__['overrides'] = overrides
2275
2276
2278 return getattr(self.__dict__['__subject'], name)
2280 setattr(self.__dict__['__subject'], name, value)
2281
2282
2284 try:
2285 return self.__dict__['overrides'][key]
2286 except KeyError:
2287 return self.__dict__['__subject'].__getitem__(key)
2293 try:
2294 del self.__dict__['overrides'][key]
2295 except KeyError:
2296 deleted = 0
2297 else:
2298 deleted = 1
2299 try:
2300 result = self.__dict__['__subject'].__delitem__(key)
2301 except KeyError:
2302 if not deleted:
2303 raise
2304 result = None
2305 return result
2306 - def get(self, key, default=None):
2307 """Emulates the get() method of dictionaries."""
2308 try:
2309 return self.__dict__['overrides'][key]
2310 except KeyError:
2311 return self.__dict__['__subject'].get(key, default)
2313 try:
2314 self.__dict__['overrides'][key]
2315 return 1
2316 except KeyError:
2317 return key in self.__dict__['__subject']
2319 if self.__dict__['overrides'].__contains__(key):
2320 return 1
2321 return self.__dict__['__subject'].__contains__(key)
2323 """Emulates the items() method of dictionaries."""
2324 d = self.__dict__['__subject'].Dictionary().copy()
2325 d.update(self.__dict__['overrides'])
2326 return d
2328 """Emulates the items() method of dictionaries."""
2329 return list(self.Dictionary().items())
2330
2331
2333 """Update an environment's values directly, bypassing the normal
2334 checks that occur when users try to set items.
2335 """
2336 self.__dict__['overrides'].update(dict)
2337
2339 return self.__dict__['__subject'].gvars()
2340
2345
2346
2350
2351
2352
2353
2354
2355
2356
2357 Environment = Base
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2372 class _NoSubstitutionProxy(Environment):
2373 def __init__(self, subject):
2374 self.__dict__['__subject'] = subject
2375 def __getattr__(self, name):
2376 return getattr(self.__dict__['__subject'], name)
2377 def __setattr__(self, name, value):
2378 return setattr(self.__dict__['__subject'], name, value)
2379 def executor_to_lvars(self, kwdict):
2380 if kwdict.has_key('executor'):
2381 kwdict['lvars'] = kwdict['executor'].get_lvars()
2382 del kwdict['executor']
2383 else:
2384 kwdict['lvars'] = {}
2385 def raw_to_mode(self, dict):
2386 try:
2387 raw = dict['raw']
2388 except KeyError:
2389 pass
2390 else:
2391 del dict['raw']
2392 dict['mode'] = raw
2393 def subst(self, string, *args, **kwargs):
2394 return string
2395 def subst_kw(self, kw, *args, **kwargs):
2396 return kw
2397 def subst_list(self, string, *args, **kwargs):
2398 nargs = (string, self,) + args
2399 nkw = kwargs.copy()
2400 nkw['gvars'] = {}
2401 self.executor_to_lvars(nkw)
2402 self.raw_to_mode(nkw)
2403 return SCons.Subst.scons_subst_list(*nargs, **nkw)
2404 def subst_target_source(self, string, *args, **kwargs):
2405 nargs = (string, self,) + args
2406 nkw = kwargs.copy()
2407 nkw['gvars'] = {}
2408 self.executor_to_lvars(nkw)
2409 self.raw_to_mode(nkw)
2410 return SCons.Subst.scons_subst(*nargs, **nkw)
2411 return _NoSubstitutionProxy(subject)
2412
2413
2414
2415
2416
2417
2418