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