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