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 2014/03/02 14:18:15 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 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 == '-arch':
723 t = ('-arch', arg)
724 dict['CCFLAGS'].append(t)
725 dict['LINKFLAGS'].append(t)
726 else:
727 dict[append_next_arg_to].append(arg)
728 append_next_arg_to = None
729 elif not arg[0] in ['-', '+']:
730 dict['LIBS'].append(self.fs.File(arg))
731 elif arg == '-dylib_file':
732 dict['LINKFLAGS'].append(arg)
733 append_next_arg_to = 'LINKFLAGS'
734 elif arg[:2] == '-L':
735 if arg[2:]:
736 dict['LIBPATH'].append(arg[2:])
737 else:
738 append_next_arg_to = 'LIBPATH'
739 elif arg[:2] == '-l':
740 if arg[2:]:
741 dict['LIBS'].append(arg[2:])
742 else:
743 append_next_arg_to = 'LIBS'
744 elif arg[:2] == '-I':
745 if arg[2:]:
746 dict['CPPPATH'].append(arg[2:])
747 else:
748 append_next_arg_to = 'CPPPATH'
749 elif arg[:4] == '-Wa,':
750 dict['ASFLAGS'].append(arg[4:])
751 dict['CCFLAGS'].append(arg)
752 elif arg[:4] == '-Wl,':
753 if arg[:11] == '-Wl,-rpath=':
754 dict['RPATH'].append(arg[11:])
755 elif arg[:7] == '-Wl,-R,':
756 dict['RPATH'].append(arg[7:])
757 elif arg[:6] == '-Wl,-R':
758 dict['RPATH'].append(arg[6:])
759 else:
760 dict['LINKFLAGS'].append(arg)
761 elif arg[:4] == '-Wp,':
762 dict['CPPFLAGS'].append(arg)
763 elif arg[:2] == '-D':
764 if arg[2:]:
765 append_define(arg[2:])
766 else:
767 append_next_arg_to = 'CPPDEFINES'
768 elif arg == '-framework':
769 append_next_arg_to = 'FRAMEWORKS'
770 elif arg[:14] == '-frameworkdir=':
771 dict['FRAMEWORKPATH'].append(arg[14:])
772 elif arg[:2] == '-F':
773 if arg[2:]:
774 dict['FRAMEWORKPATH'].append(arg[2:])
775 else:
776 append_next_arg_to = 'FRAMEWORKPATH'
777 elif arg in ['-mno-cygwin',
778 '-pthread',
779 '-openmp',
780 '-fopenmp']:
781 dict['CCFLAGS'].append(arg)
782 dict['LINKFLAGS'].append(arg)
783 elif arg == '-mwindows':
784 dict['LINKFLAGS'].append(arg)
785 elif arg[:5] == '-std=':
786 if arg[5:].find('++')!=-1:
787 key='CXXFLAGS'
788 else:
789 key='CFLAGS'
790 dict[key].append(arg)
791 elif arg[0] == '+':
792 dict['CCFLAGS'].append(arg)
793 dict['LINKFLAGS'].append(arg)
794 elif arg in ['-include', '-isysroot', '-arch']:
795 append_next_arg_to = arg
796 else:
797 dict['CCFLAGS'].append(arg)
798
799 for arg in flags:
800 do_parse(arg)
801 return dict
802
804 """
805 Merge the dict in args into the construction variables of this
806 env, or the passed-in dict. If args is not a dict, it is
807 converted into a dict using ParseFlags. If unique is not set,
808 the flags are appended rather than merged.
809 """
810
811 if dict is None:
812 dict = self
813 if not SCons.Util.is_Dict(args):
814 args = self.ParseFlags(args)
815 if not unique:
816 self.Append(**args)
817 return self
818 for key, value in args.items():
819 if not value:
820 continue
821 try:
822 orig = self[key]
823 except KeyError:
824 orig = value
825 else:
826 if not orig:
827 orig = value
828 elif value:
829
830
831
832
833
834
835 try:
836 orig = orig + value
837 except (KeyError, TypeError):
838 try:
839 add_to_orig = orig.append
840 except AttributeError:
841 value.insert(0, orig)
842 orig = value
843 else:
844 add_to_orig(value)
845 t = []
846 if key[-4:] == 'PATH':
847
848 for v in orig:
849 if v not in t:
850 t.append(v)
851 else:
852
853 orig.reverse()
854 for v in orig:
855 if v not in t:
856 t.insert(0, v)
857 self[key] = t
858 return self
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
883
887
889 f = SCons.Defaults.DefaultEnvironment().copy_from_cache
890 return f(src, dst)
891
892 -class Base(SubstitutionEnvironment):
893 """Base class for "real" construction Environments. These are the
894 primary objects used to communicate dependency and construction
895 information to the build engine.
896
897 Keyword arguments supplied when the construction Environment
898 is created are construction variables used to initialize the
899 Environment.
900 """
901
902 memoizer_counters = []
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918 - def __init__(self,
919 platform=None,
920 tools=None,
921 toolpath=None,
922 variables=None,
923 parse_flags = None,
924 **kw):
925 """
926 Initialization of a basic SCons construction environment,
927 including setting up special construction variables like BUILDER,
928 PLATFORM, etc., and searching for and applying available Tools.
929
930 Note that we do *not* call the underlying base class
931 (SubsitutionEnvironment) initialization, because we need to
932 initialize things in a very specific order that doesn't work
933 with the much simpler base class initialization.
934 """
935 if SCons.Debug.track_instances: logInstanceCreation(self, 'Environment.Base')
936 self._memo = {}
937 self.fs = SCons.Node.FS.get_default_fs()
938 self.ans = SCons.Node.Alias.default_ans
939 self.lookup_list = SCons.Node.arg2nodes_lookups
940 self._dict = semi_deepcopy(SCons.Defaults.ConstructionEnvironment)
941 self._init_special()
942 self.added_methods = []
943
944
945
946
947
948
949
950 self.decide_target = default_decide_target
951 self.decide_source = default_decide_source
952
953 self.copy_from_cache = default_copy_from_cache
954
955 self._dict['BUILDERS'] = BuilderDict(self._dict['BUILDERS'], self)
956
957 if platform is None:
958 platform = self._dict.get('PLATFORM', None)
959 if platform is None:
960 platform = SCons.Platform.Platform()
961 if SCons.Util.is_String(platform):
962 platform = SCons.Platform.Platform(platform)
963 self._dict['PLATFORM'] = str(platform)
964 platform(self)
965
966 self._dict['HOST_OS'] = self._dict.get('HOST_OS',None)
967 self._dict['HOST_ARCH'] = self._dict.get('HOST_ARCH',None)
968
969
970 self._dict['TARGET_OS'] = self._dict.get('TARGET_OS',None)
971 self._dict['TARGET_ARCH'] = self._dict.get('TARGET_ARCH',None)
972
973
974
975
976
977 if 'options' in kw:
978
979
980 variables = kw['options']
981 del kw['options']
982 self.Replace(**kw)
983 keys = list(kw.keys())
984 if variables:
985 keys = keys + list(variables.keys())
986 variables.Update(self)
987
988 save = {}
989 for k in keys:
990 try:
991 save[k] = self._dict[k]
992 except KeyError:
993
994
995 pass
996
997 SCons.Tool.Initializers(self)
998
999 if tools is None:
1000 tools = self._dict.get('TOOLS', None)
1001 if tools is None:
1002 tools = ['default']
1003 apply_tools(self, tools, toolpath)
1004
1005
1006
1007
1008 for key, val in save.items():
1009 self._dict[key] = val
1010
1011
1012 if parse_flags: self.MergeFlags(parse_flags)
1013
1014
1015
1016
1017
1018
1020 """Fetch the builder with the specified name from the environment.
1021 """
1022 try:
1023 return self._dict['BUILDERS'][name]
1024 except KeyError:
1025 return None
1026
1028 try:
1029 path = self._CacheDir_path
1030 except AttributeError:
1031 path = SCons.Defaults.DefaultEnvironment()._CacheDir_path
1032 try:
1033 if path == self._last_CacheDir_path:
1034 return self._last_CacheDir
1035 except AttributeError:
1036 pass
1037 cd = SCons.CacheDir.CacheDir(path)
1038 self._last_CacheDir_path = path
1039 self._last_CacheDir = cd
1040 return cd
1041
1043 """Return a factory function for creating Nodes for this
1044 construction environment.
1045 """
1046 name = default
1047 try:
1048 is_node = issubclass(factory, SCons.Node.FS.Base)
1049 except TypeError:
1050
1051
1052 pass
1053 else:
1054 if is_node:
1055
1056
1057
1058
1059 try: name = factory.__name__
1060 except AttributeError: pass
1061 else: factory = None
1062 if not factory:
1063
1064
1065
1066
1067
1068 factory = getattr(self.fs, name)
1069 return factory
1070
1071 memoizer_counters.append(SCons.Memoize.CountValue('_gsm'))
1072
1074 try:
1075 return self._memo['_gsm']
1076 except KeyError:
1077 pass
1078
1079 result = {}
1080
1081 try:
1082 scanners = self._dict['SCANNERS']
1083 except KeyError:
1084 pass
1085 else:
1086
1087
1088
1089
1090 if not SCons.Util.is_List(scanners):
1091 scanners = [scanners]
1092 else:
1093 scanners = scanners[:]
1094 scanners.reverse()
1095 for scanner in scanners:
1096 for k in scanner.get_skeys(self):
1097 if k and self['PLATFORM'] == 'win32':
1098 k = k.lower()
1099 result[k] = scanner
1100
1101 self._memo['_gsm'] = result
1102
1103 return result
1104
1106 """Find the appropriate scanner given a key (usually a file suffix).
1107 """
1108 if skey and self['PLATFORM'] == 'win32':
1109 skey = skey.lower()
1110 return self._gsm().get(skey)
1111
1113 """Delete the cached scanner map (if we need to).
1114 """
1115 try:
1116 del self._memo['_gsm']
1117 except KeyError:
1118 pass
1119
1121 """Update an environment's values directly, bypassing the normal
1122 checks that occur when users try to set items.
1123 """
1124 self._dict.update(dict)
1125
1127 try:
1128 return self.src_sig_type
1129 except AttributeError:
1130 t = SCons.Defaults.DefaultEnvironment().src_sig_type
1131 self.src_sig_type = t
1132 return t
1133
1135 try:
1136 return self.tgt_sig_type
1137 except AttributeError:
1138 t = SCons.Defaults.DefaultEnvironment().tgt_sig_type
1139 self.tgt_sig_type = t
1140 return t
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1152 """Append values to existing construction variables
1153 in an Environment.
1154 """
1155 kw = copy_non_reserved_keywords(kw)
1156 for key, val in kw.items():
1157
1158
1159
1160
1161 try:
1162 if key == 'CPPDEFINES' and SCons.Util.is_String(self._dict[key]):
1163 self._dict[key] = [self._dict[key]]
1164 orig = self._dict[key]
1165 except KeyError:
1166
1167
1168 if key == 'CPPDEFINES' and SCons.Util.is_String(val):
1169 self._dict[key] = [val]
1170 else:
1171 self._dict[key] = val
1172 else:
1173 try:
1174
1175
1176
1177
1178
1179 update_dict = orig.update
1180 except AttributeError:
1181 try:
1182
1183
1184
1185 self._dict[key] = orig + val
1186 except (KeyError, TypeError):
1187 try:
1188
1189 add_to_orig = orig.append
1190 except AttributeError:
1191
1192
1193
1194
1195
1196 if orig:
1197 val.insert(0, orig)
1198 self._dict[key] = val
1199 else:
1200
1201
1202 if val:
1203 add_to_orig(val)
1204 else:
1205
1206
1207 if SCons.Util.is_List(val):
1208 if key == 'CPPDEFINES':
1209 orig = orig.items()
1210 orig += val
1211 self._dict[key] = orig
1212 else:
1213 for v in val:
1214 orig[v] = None
1215 else:
1216 try:
1217 update_dict(val)
1218 except (AttributeError, TypeError, ValueError):
1219 if SCons.Util.is_Dict(val):
1220 for k, v in val.items():
1221 orig[k] = v
1222 else:
1223 orig[val] = None
1224 self.scanner_map_delete(kw)
1225
1226
1227
1234
1235 - def AppendENVPath(self, name, newpath, envname = 'ENV',
1236 sep = os.pathsep, delete_existing=1):
1237 """Append path elements to the path 'name' in the 'ENV'
1238 dictionary for this environment. Will only add any particular
1239 path once, and will normpath and normcase all paths to help
1240 assure this. This can also handle the case where the env
1241 variable is a list instead of a string.
1242
1243 If delete_existing is 0, a newpath which is already in the path
1244 will not be moved to the end (it will be left where it is).
1245 """
1246
1247 orig = ''
1248 if envname in self._dict and name in self._dict[envname]:
1249 orig = self._dict[envname][name]
1250
1251 nv = SCons.Util.AppendPath(orig, newpath, sep, delete_existing,
1252 canonicalize=self._canonicalize)
1253
1254 if envname not in self._dict:
1255 self._dict[envname] = {}
1256
1257 self._dict[envname][name] = nv
1258
1260 """Append values to existing construction variables
1261 in an Environment, if they're not already there.
1262 If delete_existing is 1, removes existing values first, so
1263 values move to end.
1264 """
1265 kw = copy_non_reserved_keywords(kw)
1266 for key, val in kw.items():
1267 if SCons.Util.is_List(val):
1268 val = _delete_duplicates(val, delete_existing)
1269 if key not in self._dict or self._dict[key] in ('', None):
1270 self._dict[key] = val
1271 elif SCons.Util.is_Dict(self._dict[key]) and \
1272 SCons.Util.is_Dict(val):
1273 self._dict[key].update(val)
1274 elif SCons.Util.is_List(val):
1275 dk = self._dict[key]
1276 if key == 'CPPDEFINES':
1277 tmp = []
1278 for i in val:
1279 if SCons.Util.is_List(i):
1280 if len(i) >= 2:
1281 tmp.append((i[0], i[1]))
1282 else:
1283 tmp.append((i[0],))
1284 elif SCons.Util.is_Tuple(i):
1285 tmp.append(i)
1286 else:
1287 tmp.append((i,))
1288 val = tmp
1289 if SCons.Util.is_Dict(dk):
1290 dk = dk.items()
1291 elif SCons.Util.is_String(dk):
1292 dk = [(dk,)]
1293 else:
1294 tmp = []
1295 for i in dk:
1296 if SCons.Util.is_List(i):
1297 if len(i) >= 2:
1298 tmp.append((i[0], i[1]))
1299 else:
1300 tmp.append((i[0],))
1301 elif SCons.Util.is_Tuple(i):
1302 tmp.append(i)
1303 else:
1304 tmp.append((i,))
1305 dk = tmp
1306 else:
1307 if not SCons.Util.is_List(dk):
1308 dk = [dk]
1309 if delete_existing:
1310 dk = [x for x in dk if x not in val]
1311 else:
1312 val = [x for x in val if x not in dk]
1313 self._dict[key] = dk + val
1314 else:
1315 dk = self._dict[key]
1316 if SCons.Util.is_List(dk):
1317 if key == 'CPPDEFINES':
1318 tmp = []
1319 for i in dk:
1320 if SCons.Util.is_List(i):
1321 if len(i) >= 2:
1322 tmp.append((i[0], i[1]))
1323 else:
1324 tmp.append((i[0],))
1325 elif SCons.Util.is_Tuple(i):
1326 tmp.append(i)
1327 else:
1328 tmp.append((i,))
1329 dk = tmp
1330 if SCons.Util.is_Dict(val):
1331 val = val.items()
1332 elif SCons.Util.is_String(val):
1333 val = [(val,)]
1334 if delete_existing:
1335 dk = filter(lambda x, val=val: x not in val, dk)
1336 self._dict[key] = dk + val
1337 else:
1338 dk = [x for x in dk if x not in val]
1339 self._dict[key] = dk + val
1340 else:
1341
1342
1343 if delete_existing:
1344 dk = filter(lambda x, val=val: x not in val, dk)
1345 self._dict[key] = dk + [val]
1346 else:
1347 if not val in dk:
1348 self._dict[key] = dk + [val]
1349 else:
1350 if key == 'CPPDEFINES':
1351 if SCons.Util.is_String(dk):
1352 dk = [dk]
1353 elif SCons.Util.is_Dict(dk):
1354 dk = dk.items()
1355 if SCons.Util.is_String(val):
1356 if val in dk:
1357 val = []
1358 else:
1359 val = [val]
1360 elif SCons.Util.is_Dict(val):
1361 tmp = []
1362 for i,j in val.iteritems():
1363 if j is not None:
1364 tmp.append((i,j))
1365 else:
1366 tmp.append(i)
1367 val = tmp
1368 if delete_existing:
1369 dk = [x for x in dk if x not in val]
1370 self._dict[key] = dk + val
1371 self.scanner_map_delete(kw)
1372
1373 - def Clone(self, tools=[], toolpath=None, parse_flags = None, **kw):
1374 """Return a copy of a construction Environment. The
1375 copy is like a Python "deep copy"--that is, independent
1376 copies are made recursively of each objects--except that
1377 a reference is copied when an object is not deep-copyable
1378 (like a function). There are no references to any mutable
1379 objects in the original Environment.
1380 """
1381 try:
1382 builders = self._dict['BUILDERS']
1383 except KeyError:
1384 pass
1385
1386 clone = copy.copy(self)
1387
1388 clone._dict = semi_deepcopy_dict(self._dict, ['BUILDERS'])
1389 clone._dict['BUILDERS'] = BuilderDict(builders, clone)
1390
1391
1392
1393
1394
1395 clone.added_methods = []
1396 for mw in self.added_methods:
1397 if mw == getattr(self, mw.name):
1398 clone.added_methods.append(mw.clone(clone))
1399
1400 clone._memo = {}
1401
1402
1403
1404 kw = copy_non_reserved_keywords(kw)
1405 new = {}
1406 for key, value in kw.items():
1407 new[key] = SCons.Subst.scons_subst_once(value, self, key)
1408 clone.Replace(**new)
1409
1410 apply_tools(clone, tools, toolpath)
1411
1412
1413 clone.Replace(**new)
1414
1415
1416 if parse_flags: clone.MergeFlags(parse_flags)
1417
1418 if SCons.Debug.track_instances: logInstanceCreation(self, 'Environment.EnvironmentClone')
1419 return clone
1420
1421 - def Copy(self, *args, **kw):
1428
1433
1434 - def _changed_content(self, dependency, target, prev_ni):
1435 return dependency.changed_content(target, prev_ni)
1436
1444
1445 - def _changed_timestamp_then_content(self, dependency, target, prev_ni):
1446 return dependency.changed_timestamp_then_content(target, prev_ni)
1447
1450
1453
1455 return self.fs.copy(src, dst)
1456
1458 return self.fs.copy2(src, dst)
1459
1483
1485 """Return the first available program in progs.
1486 """
1487 if not SCons.Util.is_List(progs):
1488 progs = [ progs ]
1489 for prog in progs:
1490 path = self.WhereIs(prog)
1491 if path: return prog
1492 return None
1493
1495 if not args:
1496 return self._dict
1497 dlist = [self._dict[x] for x in args]
1498 if len(dlist) == 1:
1499 dlist = dlist[0]
1500 return dlist
1501
1502 - def Dump(self, key = None):
1503 """
1504 Using the standard Python pretty printer, dump the contents of the
1505 scons build environment to stdout.
1506
1507 If the key passed in is anything other than None, then that will
1508 be used as an index into the build environment dictionary and
1509 whatever is found there will be fed into the pretty printer. Note
1510 that this key is case sensitive.
1511 """
1512 import pprint
1513 pp = pprint.PrettyPrinter(indent=2)
1514 if key:
1515 dict = self.Dictionary(key)
1516 else:
1517 dict = self.Dictionary()
1518 return pp.pformat(dict)
1519
1520 - def FindIxes(self, paths, prefix, suffix):
1521 """
1522 Search a list of paths for something that matches the prefix and suffix.
1523
1524 paths - the list of paths or nodes.
1525 prefix - construction variable for the prefix.
1526 suffix - construction variable for the suffix.
1527 """
1528
1529 suffix = self.subst('$'+suffix)
1530 prefix = self.subst('$'+prefix)
1531
1532 for path in paths:
1533 dir,name = os.path.split(str(path))
1534 if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix:
1535 return path
1536
1537 - def ParseConfig(self, command, function=None, unique=1):
1538 """
1539 Use the specified function to parse the output of the command
1540 in order to modify the current environment. The 'command' can
1541 be a string or a list of strings representing a command and
1542 its arguments. 'Function' is an optional argument that takes
1543 the environment, the output of the command, and the unique flag.
1544 If no function is specified, MergeFlags, which treats the output
1545 as the result of a typical 'X-config' command (i.e. gtk-config),
1546 will merge the output into the appropriate variables.
1547 """
1548 if function is None:
1549 def parse_conf(env, cmd, unique=unique):
1550 return env.MergeFlags(cmd, unique)
1551 function = parse_conf
1552 if SCons.Util.is_List(command):
1553 command = ' '.join(command)
1554 command = self.subst(command)
1555 return function(self, self.backtick(command))
1556
1557 - def ParseDepends(self, filename, must_exist=None, only_one=0):
1558 """
1559 Parse a mkdep-style file for explicit dependencies. This is
1560 completely abusable, and should be unnecessary in the "normal"
1561 case of proper SCons configuration, but it may help make
1562 the transition from a Make hierarchy easier for some people
1563 to swallow. It can also be genuinely useful when using a tool
1564 that can write a .d file, but for which writing a scanner would
1565 be too complicated.
1566 """
1567 filename = self.subst(filename)
1568 try:
1569 fp = open(filename, 'r')
1570 except IOError:
1571 if must_exist:
1572 raise
1573 return
1574 lines = SCons.Util.LogicalLines(fp).readlines()
1575 lines = [l for l in lines if l[0] != '#']
1576 tdlist = []
1577 for line in lines:
1578 try:
1579 target, depends = line.split(':', 1)
1580 except (AttributeError, ValueError):
1581
1582
1583 pass
1584 else:
1585 tdlist.append((target.split(), depends.split()))
1586 if only_one:
1587 targets = []
1588 for td in tdlist:
1589 targets.extend(td[0])
1590 if len(targets) > 1:
1591 raise SCons.Errors.UserError(
1592 "More than one dependency target found in `%s': %s"
1593 % (filename, targets))
1594 for target, depends in tdlist:
1595 self.Depends(target, depends)
1596
1600
1602 """Prepend values to existing construction variables
1603 in an Environment.
1604 """
1605 kw = copy_non_reserved_keywords(kw)
1606 for key, val in kw.items():
1607
1608
1609
1610
1611 try:
1612 orig = self._dict[key]
1613 except KeyError:
1614
1615
1616 self._dict[key] = val
1617 else:
1618 try:
1619
1620
1621
1622
1623
1624 update_dict = orig.update
1625 except AttributeError:
1626 try:
1627
1628
1629
1630 self._dict[key] = val + orig
1631 except (KeyError, TypeError):
1632 try:
1633
1634 add_to_val = val.append
1635 except AttributeError:
1636
1637
1638
1639
1640 if val:
1641 orig.insert(0, val)
1642 else:
1643
1644
1645
1646 if orig:
1647 add_to_val(orig)
1648 self._dict[key] = val
1649 else:
1650
1651
1652 if SCons.Util.is_List(val):
1653 for v in val:
1654 orig[v] = None
1655 else:
1656 try:
1657 update_dict(val)
1658 except (AttributeError, TypeError, ValueError):
1659 if SCons.Util.is_Dict(val):
1660 for k, v in val.items():
1661 orig[k] = v
1662 else:
1663 orig[val] = None
1664 self.scanner_map_delete(kw)
1665
1666 - def PrependENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep,
1667 delete_existing=1):
1668 """Prepend path elements to the path 'name' in the 'ENV'
1669 dictionary for this environment. Will only add any particular
1670 path once, and will normpath and normcase all paths to help
1671 assure this. This can also handle the case where the env
1672 variable is a list instead of a string.
1673
1674 If delete_existing is 0, a newpath which is already in the path
1675 will not be moved to the front (it will be left where it is).
1676 """
1677
1678 orig = ''
1679 if envname in self._dict and name in self._dict[envname]:
1680 orig = self._dict[envname][name]
1681
1682 nv = SCons.Util.PrependPath(orig, newpath, sep, delete_existing,
1683 canonicalize=self._canonicalize)
1684
1685 if envname not in self._dict:
1686 self._dict[envname] = {}
1687
1688 self._dict[envname][name] = nv
1689
1691 """Prepend values to existing construction variables
1692 in an Environment, if they're not already there.
1693 If delete_existing is 1, removes existing values first, so
1694 values move to front.
1695 """
1696 kw = copy_non_reserved_keywords(kw)
1697 for key, val in kw.items():
1698 if SCons.Util.is_List(val):
1699 val = _delete_duplicates(val, not delete_existing)
1700 if key not in self._dict or self._dict[key] in ('', None):
1701 self._dict[key] = val
1702 elif SCons.Util.is_Dict(self._dict[key]) and \
1703 SCons.Util.is_Dict(val):
1704 self._dict[key].update(val)
1705 elif SCons.Util.is_List(val):
1706 dk = self._dict[key]
1707 if not SCons.Util.is_List(dk):
1708 dk = [dk]
1709 if delete_existing:
1710 dk = [x for x in dk if x not in val]
1711 else:
1712 val = [x for x in val if x not in dk]
1713 self._dict[key] = val + dk
1714 else:
1715 dk = self._dict[key]
1716 if SCons.Util.is_List(dk):
1717
1718
1719 if delete_existing:
1720 dk = [x for x in dk if x not in val]
1721 self._dict[key] = [val] + dk
1722 else:
1723 if not val in dk:
1724 self._dict[key] = [val] + dk
1725 else:
1726 if delete_existing:
1727 dk = [x for x in dk if x not in val]
1728 self._dict[key] = val + dk
1729 self.scanner_map_delete(kw)
1730
1732 """Replace existing construction variables in an Environment
1733 with new construction variables and/or values.
1734 """
1735 try:
1736 kwbd = kw['BUILDERS']
1737 except KeyError:
1738 pass
1739 else:
1740 kwbd = BuilderDict(kwbd,self)
1741 del kw['BUILDERS']
1742 self.__setitem__('BUILDERS', kwbd)
1743 kw = copy_non_reserved_keywords(kw)
1744 self._update(semi_deepcopy(kw))
1745 self.scanner_map_delete(kw)
1746
1747 - def ReplaceIxes(self, path, old_prefix, old_suffix, new_prefix, new_suffix):
1748 """
1749 Replace old_prefix with new_prefix and old_suffix with new_suffix.
1750
1751 env - Environment used to interpolate variables.
1752 path - the path that will be modified.
1753 old_prefix - construction variable for the old prefix.
1754 old_suffix - construction variable for the old suffix.
1755 new_prefix - construction variable for the new prefix.
1756 new_suffix - construction variable for the new suffix.
1757 """
1758 old_prefix = self.subst('$'+old_prefix)
1759 old_suffix = self.subst('$'+old_suffix)
1760
1761 new_prefix = self.subst('$'+new_prefix)
1762 new_suffix = self.subst('$'+new_suffix)
1763
1764 dir,name = os.path.split(str(path))
1765 if name[:len(old_prefix)] == old_prefix:
1766 name = name[len(old_prefix):]
1767 if name[-len(old_suffix):] == old_suffix:
1768 name = name[:-len(old_suffix)]
1769 return os.path.join(dir, new_prefix+name+new_suffix)
1770
1772 for k in kw.keys():
1773 if k in self._dict:
1774 del kw[k]
1775 self.Replace(**kw)
1776
1779
1788
1789 - def WhereIs(self, prog, path=None, pathext=None, reject=[]):
1790 """Find prog in the path.
1791 """
1792 if path is None:
1793 try:
1794 path = self['ENV']['PATH']
1795 except KeyError:
1796 pass
1797 elif SCons.Util.is_String(path):
1798 path = self.subst(path)
1799 if pathext is None:
1800 try:
1801 pathext = self['ENV']['PATHEXT']
1802 except KeyError:
1803 pass
1804 elif SCons.Util.is_String(pathext):
1805 pathext = self.subst(pathext)
1806 prog = self.subst(prog)
1807 path = SCons.Util.WhereIs(prog, path, pathext, reject)
1808 if path: return path
1809 return None
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819 - def Action(self, *args, **kw):
1820 def subst_string(a, self=self):
1821 if SCons.Util.is_String(a):
1822 a = self.subst(a)
1823 return a
1824 nargs = list(map(subst_string, args))
1825 nkw = self.subst_kw(kw)
1826 return SCons.Action.Action(*nargs, **nkw)
1827
1837
1838 - def AddPostAction(self, files, action):
1839 nodes = self.arg2nodes(files, self.fs.Entry)
1840 action = SCons.Action.Action(action)
1841 uniq = {}
1842 for executor in [n.get_executor() for n in nodes]:
1843 uniq[executor] = 1
1844 for executor in uniq.keys():
1845 executor.add_post_action(action)
1846 return nodes
1847
1848 - def Alias(self, target, source=[], action=None, **kw):
1900
1908
1916
1920
1926
1927 - def Clean(self, targets, files):
1936
1948
1949 - def Command(self, target, source, action, **kw):
1950 """Builds the supplied target files from the supplied
1951 source files using the supplied action. Action may
1952 be any type that the Builder constructor will accept
1953 for an action."""
1954 bkw = {
1955 'action' : action,
1956 'target_factory' : self.fs.Entry,
1957 'source_factory' : self.fs.Entry,
1958 }
1959 try: bkw['source_scanner'] = kw['source_scanner']
1960 except KeyError: pass
1961 else: del kw['source_scanner']
1962 bld = SCons.Builder.Builder(**bkw)
1963 return bld(self, target, source, **kw)
1964
1965 - def Depends(self, target, dependency):
1966 """Explicity specify that 'target's depend on 'dependency'."""
1967 tlist = self.arg2nodes(target, self.fs.Entry)
1968 dlist = self.arg2nodes(dependency, self.fs.Entry)
1969 for t in tlist:
1970 t.add_dependency(dlist)
1971 return tlist
1972
1973 - def Dir(self, name, *args, **kw):
1983
1985 """Tags a target so that it will not be cleaned by -c"""
1986 tlist = []
1987 for t in targets:
1988 tlist.extend(self.arg2nodes(t, self.fs.Entry))
1989 for t in tlist:
1990 t.set_noclean()
1991 return tlist
1992
1994 """Tags a target so that it will not be cached"""
1995 tlist = []
1996 for t in targets:
1997 tlist.extend(self.arg2nodes(t, self.fs.Entry))
1998 for t in tlist:
1999 t.set_nocache()
2000 return tlist
2001
2002 - def Entry(self, name, *args, **kw):
2003 """
2004 """
2005 s = self.subst(name)
2006 if SCons.Util.is_Sequence(s):
2007 result=[]
2008 for e in s:
2009 result.append(self.fs.Entry(e, *args, **kw))
2010 return result
2011 return self.fs.Entry(s, *args, **kw)
2012
2015
2016 - def Execute(self, action, *args, **kw):
2017 """Directly execute an action through an Environment
2018 """
2019 action = self.Action(action, *args, **kw)
2020 result = action([], [], self)
2021 if isinstance(result, SCons.Errors.BuildError):
2022 errstr = result.errstr
2023 if result.filename:
2024 errstr = result.filename + ': ' + errstr
2025 sys.stderr.write("scons: *** %s\n" % errstr)
2026 return result.status
2027 else:
2028 return result
2029
2030 - def File(self, name, *args, **kw):
2040
2045
2048
2055
2056 - def Glob(self, pattern, ondisk=True, source=False, strings=False):
2057 return self.fs.Glob(self.subst(pattern), ondisk, source, strings)
2058
2059 - def Ignore(self, target, dependency):
2066
2069
2070 - def Local(self, *targets):
2081
2089
2097
2101
2102 - def Requires(self, target, prerequisite):
2103 """Specify that 'prerequisite' must be built before 'target',
2104 (but 'target' does not actually depend on 'prerequisite'
2105 and need not be rebuilt if it changes)."""
2106 tlist = self.arg2nodes(target, self.fs.Entry)
2107 plist = self.arg2nodes(prerequisite, self.fs.Entry)
2108 for t in tlist:
2109 t.add_prerequisite(plist)
2110 return tlist
2111
2120
2121 - def SConsignFile(self, name=".sconsign", dbm_module=None):
2122 if name is not None:
2123 name = self.subst(name)
2124 if not os.path.isabs(name):
2125 name = os.path.join(str(self.fs.SConstruct_dir), name)
2126 if name:
2127 name = os.path.normpath(name)
2128 sconsign_dir = os.path.dirname(name)
2129 if sconsign_dir and not os.path.exists(sconsign_dir):
2130 self.Execute(SCons.Defaults.Mkdir(sconsign_dir))
2131 SCons.SConsign.File(name, dbm_module)
2132
2134 """Tell scons that side_effects are built as side
2135 effects of building targets."""
2136 side_effects = self.arg2nodes(side_effect, self.fs.Entry)
2137 targets = self.arg2nodes(target, self.fs.Entry)
2138
2139 for side_effect in side_effects:
2140 if side_effect.multiple_side_effect_has_builder():
2141 raise SCons.Errors.UserError("Multiple ways to build the same target were specified for: %s" % str(side_effect))
2142 side_effect.add_source(targets)
2143 side_effect.side_effect = 1
2144 self.Precious(side_effect)
2145 for target in targets:
2146 target.side_effects.append(side_effect)
2147 return side_effects
2148
2158
2176
2178 """This function converts a string or list into a list of strings
2179 or Nodes. This makes things easier for users by allowing files to
2180 be specified as a white-space separated list to be split.
2181 The input rules are:
2182 - A single string containing names separated by spaces. These will be
2183 split apart at the spaces.
2184 - A single Node instance
2185 - A list containing either strings or Node instances. Any strings
2186 in the list are not split at spaces.
2187 In all cases, the function returns a list of Nodes and strings."""
2188 if SCons.Util.is_List(arg):
2189 return list(map(self.subst, arg))
2190 elif SCons.Util.is_String(arg):
2191 return self.subst(arg).split()
2192 else:
2193 return [self.subst(arg)]
2194
2216
2217 - def Value(self, value, built_value=None):
2221
2222 - def VariantDir(self, variant_dir, src_dir, duplicate=1):
2226
2241 build_source(node.all_children())
2242
2243 def final_source(node):
2244 while (node != node.srcnode()):
2245 node = node.srcnode()
2246 return node
2247 sources = map( final_source, sources );
2248
2249 return list(set(sources))
2250
2252 """ returns the list of all targets of the Install and InstallAs Builder.
2253 """
2254 from SCons.Tool import install
2255 if install._UNIQUE_INSTALLED_FILES is None:
2256 install._UNIQUE_INSTALLED_FILES = SCons.Util.uniquer_hashables(install._INSTALLED_FILES)
2257 return install._UNIQUE_INSTALLED_FILES
2258
2259
2261 """A proxy that overrides variables in a wrapped construction
2262 environment by returning values from an overrides dictionary in
2263 preference to values from the underlying subject environment.
2264
2265 This is a lightweight (I hope) proxy that passes through most use of
2266 attributes to the underlying Environment.Base class, but has just
2267 enough additional methods defined to act like a real construction
2268 environment with overridden values. It can wrap either a Base
2269 construction environment, or another OverrideEnvironment, which
2270 can in turn nest arbitrary OverrideEnvironments...
2271
2272 Note that we do *not* call the underlying base class
2273 (SubsitutionEnvironment) initialization, because we get most of those
2274 from proxying the attributes of the subject construction environment.
2275 But because we subclass SubstitutionEnvironment, this class also
2276 has inherited arg2nodes() and subst*() methods; those methods can't
2277 be proxied because they need *this* object's methods to fetch the
2278 values from the overrides dictionary.
2279 """
2280
2281 - def __init__(self, subject, overrides={}):
2285
2286
2288 return getattr(self.__dict__['__subject'], name)
2290 setattr(self.__dict__['__subject'], name, value)
2291
2292
2294 try:
2295 return self.__dict__['overrides'][key]
2296 except KeyError:
2297 return self.__dict__['__subject'].__getitem__(key)
2303 try:
2304 del self.__dict__['overrides'][key]
2305 except KeyError:
2306 deleted = 0
2307 else:
2308 deleted = 1
2309 try:
2310 result = self.__dict__['__subject'].__delitem__(key)
2311 except KeyError:
2312 if not deleted:
2313 raise
2314 result = None
2315 return result
2316 - def get(self, key, default=None):
2317 """Emulates the get() method of dictionaries."""
2318 try:
2319 return self.__dict__['overrides'][key]
2320 except KeyError:
2321 return self.__dict__['__subject'].get(key, default)
2323 try:
2324 self.__dict__['overrides'][key]
2325 return 1
2326 except KeyError:
2327 return key in self.__dict__['__subject']
2329 if self.__dict__['overrides'].__contains__(key):
2330 return 1
2331 return self.__dict__['__subject'].__contains__(key)
2333 """Emulates the items() method of dictionaries."""
2334 d = self.__dict__['__subject'].Dictionary().copy()
2335 d.update(self.__dict__['overrides'])
2336 return d
2338 """Emulates the items() method of dictionaries."""
2339 return list(self.Dictionary().items())
2340
2341
2343 """Update an environment's values directly, bypassing the normal
2344 checks that occur when users try to set items.
2345 """
2346 self.__dict__['overrides'].update(dict)
2347
2349 return self.__dict__['__subject'].gvars()
2350
2355
2356
2360
2361
2362
2363
2364
2365
2366
2367 Environment = Base
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2382 class _NoSubstitutionProxy(Environment):
2383 def __init__(self, subject):
2384 self.__dict__['__subject'] = subject
2385 def __getattr__(self, name):
2386 return getattr(self.__dict__['__subject'], name)
2387 def __setattr__(self, name, value):
2388 return setattr(self.__dict__['__subject'], name, value)
2389 def executor_to_lvars(self, kwdict):
2390 if kwdict.has_key('executor'):
2391 kwdict['lvars'] = kwdict['executor'].get_lvars()
2392 del kwdict['executor']
2393 else:
2394 kwdict['lvars'] = {}
2395 def raw_to_mode(self, dict):
2396 try:
2397 raw = dict['raw']
2398 except KeyError:
2399 pass
2400 else:
2401 del dict['raw']
2402 dict['mode'] = raw
2403 def subst(self, string, *args, **kwargs):
2404 return string
2405 def subst_kw(self, kw, *args, **kwargs):
2406 return kw
2407 def subst_list(self, string, *args, **kwargs):
2408 nargs = (string, self,) + args
2409 nkw = kwargs.copy()
2410 nkw['gvars'] = {}
2411 self.executor_to_lvars(nkw)
2412 self.raw_to_mode(nkw)
2413 return SCons.Subst.scons_subst_list(*nargs, **nkw)
2414 def subst_target_source(self, string, *args, **kwargs):
2415 nargs = (string, self,) + args
2416 nkw = kwargs.copy()
2417 nkw['gvars'] = {}
2418 self.executor_to_lvars(nkw)
2419 self.raw_to_mode(nkw)
2420 return SCons.Subst.scons_subst(*nargs, **nkw)
2421 return _NoSubstitutionProxy(subject)
2422
2423
2424
2425
2426
2427
2428