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