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 72ae09dc35ac2626f8ff711d8c4b30b6138e08e3 2019-08-08 14:50:06 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 '-fmerge-all-constants',
787 '-fopenmp']:
788 dict['CCFLAGS'].append(arg)
789 dict['LINKFLAGS'].append(arg)
790 elif arg == '-mwindows':
791 dict['LINKFLAGS'].append(arg)
792 elif arg[:5] == '-std=':
793 if arg[5:].find('++')!=-1:
794 key='CXXFLAGS'
795 else:
796 key='CFLAGS'
797 dict[key].append(arg)
798 elif arg[0] == '+':
799 dict['CCFLAGS'].append(arg)
800 dict['LINKFLAGS'].append(arg)
801 elif arg in ['-include', '-isysroot', '-isystem', '-iquote', '-idirafter', '-arch']:
802 append_next_arg_to = arg
803 else:
804 dict['CCFLAGS'].append(arg)
805
806 for arg in flags:
807 do_parse(arg)
808 return dict
809
811 """
812 Merge the dict in args into the construction variables of this
813 env, or the passed-in dict. If args is not a dict, it is
814 converted into a dict using ParseFlags. If unique is not set,
815 the flags are appended rather than merged.
816 """
817
818 if dict is None:
819 dict = self
820 if not SCons.Util.is_Dict(args):
821 args = self.ParseFlags(args)
822 if not unique:
823 self.Append(**args)
824 return self
825 for key, value in args.items():
826 if not value:
827 continue
828 try:
829 orig = self[key]
830 except KeyError:
831 orig = value
832 else:
833 if not orig:
834 orig = value
835 elif value:
836
837
838
839
840
841
842 try:
843 orig = orig + value
844 except (KeyError, TypeError):
845 try:
846 add_to_orig = orig.append
847 except AttributeError:
848 value.insert(0, orig)
849 orig = value
850 else:
851 add_to_orig(value)
852 t = []
853 if key[-4:] == 'PATH':
854
855 for v in orig:
856 if v not in t:
857 t.append(v)
858 else:
859
860 orig.reverse()
861 for v in orig:
862 if v not in t:
863 t.insert(0, v)
864 self[key] = t
865 return self
866
869 f = SCons.Defaults.DefaultEnvironment().decide_source
870 return f(dependency, target, prev_ni, repo_node)
871
874 f = SCons.Defaults.DefaultEnvironment().decide_target
875 return f(dependency, target, prev_ni, repo_node)
876
879 f = SCons.Defaults.DefaultEnvironment().copy_from_cache
880 return f(src, dst)
881
882
883 -class Base(SubstitutionEnvironment):
884 """Base class for "real" construction Environments. These are the
885 primary objects used to communicate dependency and construction
886 information to the build engine.
887
888 Keyword arguments supplied when the construction Environment
889 is created are construction variables used to initialize the
890 Environment.
891 """
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907 - def __init__(self,
908 platform=None,
909 tools=None,
910 toolpath=None,
911 variables=None,
912 parse_flags = None,
913 **kw):
914 """
915 Initialization of a basic SCons construction environment,
916 including setting up special construction variables like BUILDER,
917 PLATFORM, etc., and searching for and applying available Tools.
918
919 Note that we do *not* call the underlying base class
920 (SubsitutionEnvironment) initialization, because we need to
921 initialize things in a very specific order that doesn't work
922 with the much simpler base class initialization.
923 """
924 if SCons.Debug.track_instances: logInstanceCreation(self, 'Environment.Base')
925 self._memo = {}
926 self.fs = SCons.Node.FS.get_default_fs()
927 self.ans = SCons.Node.Alias.default_ans
928 self.lookup_list = SCons.Node.arg2nodes_lookups
929 self._dict = semi_deepcopy(SCons.Defaults.ConstructionEnvironment)
930 self._init_special()
931 self.added_methods = []
932
933
934
935
936
937
938
939 self.decide_target = default_decide_target
940 self.decide_source = default_decide_source
941
942 self.copy_from_cache = default_copy_from_cache
943
944 self._dict['BUILDERS'] = BuilderDict(self._dict['BUILDERS'], self)
945
946 if platform is None:
947 platform = self._dict.get('PLATFORM', None)
948 if platform is None:
949 platform = SCons.Platform.Platform()
950 if SCons.Util.is_String(platform):
951 platform = SCons.Platform.Platform(platform)
952 self._dict['PLATFORM'] = str(platform)
953 platform(self)
954
955 self._dict['HOST_OS'] = self._dict.get('HOST_OS',None)
956 self._dict['HOST_ARCH'] = self._dict.get('HOST_ARCH',None)
957
958
959 self._dict['TARGET_OS'] = self._dict.get('TARGET_OS',None)
960 self._dict['TARGET_ARCH'] = self._dict.get('TARGET_ARCH',None)
961
962
963
964
965
966 if 'options' in kw:
967
968
969 variables = kw['options']
970 del kw['options']
971 self.Replace(**kw)
972 keys = list(kw.keys())
973 if variables:
974 keys = keys + list(variables.keys())
975 variables.Update(self)
976
977 save = {}
978 for k in keys:
979 try:
980 save[k] = self._dict[k]
981 except KeyError:
982
983
984 pass
985
986 SCons.Tool.Initializers(self)
987
988 if tools is None:
989 tools = self._dict.get('TOOLS', None)
990 if tools is None:
991 tools = ['default']
992 apply_tools(self, tools, toolpath)
993
994
995
996
997 for key, val in save.items():
998 self._dict[key] = val
999
1000
1001 if parse_flags: self.MergeFlags(parse_flags)
1002
1003
1004
1005
1006
1007
1009 """Fetch the builder with the specified name from the environment.
1010 """
1011 try:
1012 return self._dict['BUILDERS'][name]
1013 except KeyError:
1014 return None
1015
1030
1032 """Return a factory function for creating Nodes for this
1033 construction environment.
1034 """
1035 name = default
1036 try:
1037 is_node = issubclass(factory, SCons.Node.FS.Base)
1038 except TypeError:
1039
1040
1041 pass
1042 else:
1043 if is_node:
1044
1045
1046
1047
1048 try: name = factory.__name__
1049 except AttributeError: pass
1050 else: factory = None
1051 if not factory:
1052
1053
1054
1055
1056
1057 factory = getattr(self.fs, name)
1058 return factory
1059
1060 @SCons.Memoize.CountMethodCall
1062 try:
1063 return self._memo['_gsm']
1064 except KeyError:
1065 pass
1066
1067 result = {}
1068
1069 try:
1070 scanners = self._dict['SCANNERS']
1071 except KeyError:
1072 pass
1073 else:
1074
1075
1076
1077
1078 if not SCons.Util.is_List(scanners):
1079 scanners = [scanners]
1080 else:
1081 scanners = scanners[:]
1082 scanners.reverse()
1083 for scanner in scanners:
1084 for k in scanner.get_skeys(self):
1085 if k and self['PLATFORM'] == 'win32':
1086 k = k.lower()
1087 result[k] = scanner
1088
1089 self._memo['_gsm'] = result
1090
1091 return result
1092
1094 """Find the appropriate scanner given a key (usually a file suffix).
1095 """
1096 if skey and self['PLATFORM'] == 'win32':
1097 skey = skey.lower()
1098 return self._gsm().get(skey)
1099
1101 """Delete the cached scanner map (if we need to).
1102 """
1103 try:
1104 del self._memo['_gsm']
1105 except KeyError:
1106 pass
1107
1109 """Update an environment's values directly, bypassing the normal
1110 checks that occur when users try to set items.
1111 """
1112 self._dict.update(dict)
1113
1115 try:
1116 return self.src_sig_type
1117 except AttributeError:
1118 t = SCons.Defaults.DefaultEnvironment().src_sig_type
1119 self.src_sig_type = t
1120 return t
1121
1123 try:
1124 return self.tgt_sig_type
1125 except AttributeError:
1126 t = SCons.Defaults.DefaultEnvironment().tgt_sig_type
1127 self.tgt_sig_type = t
1128 return t
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1140 """Append values to existing construction variables
1141 in an Environment.
1142 """
1143 kw = copy_non_reserved_keywords(kw)
1144 for key, val in kw.items():
1145
1146
1147
1148
1149 try:
1150 if key == 'CPPDEFINES' and SCons.Util.is_String(self._dict[key]):
1151 self._dict[key] = [self._dict[key]]
1152 orig = self._dict[key]
1153 except KeyError:
1154
1155
1156 if key == 'CPPDEFINES' and SCons.Util.is_String(val):
1157 self._dict[key] = [val]
1158 else:
1159 self._dict[key] = val
1160 else:
1161 try:
1162
1163
1164
1165
1166
1167 update_dict = orig.update
1168 except AttributeError:
1169 try:
1170
1171
1172
1173 self._dict[key] = orig + val
1174 except (KeyError, TypeError):
1175 try:
1176
1177 add_to_orig = orig.append
1178 except AttributeError:
1179
1180
1181
1182
1183
1184 if orig:
1185 val.insert(0, orig)
1186 self._dict[key] = val
1187 else:
1188
1189
1190 if val:
1191 add_to_orig(val)
1192 else:
1193
1194
1195 if SCons.Util.is_List(val):
1196 if key == 'CPPDEFINES':
1197 tmp = []
1198 for (k, v) in orig.items():
1199 if v is not None:
1200 tmp.append((k, v))
1201 else:
1202 tmp.append((k,))
1203 orig = tmp
1204 orig += val
1205 self._dict[key] = orig
1206 else:
1207 for v in val:
1208 orig[v] = None
1209 else:
1210 try:
1211 update_dict(val)
1212 except (AttributeError, TypeError, ValueError):
1213 if SCons.Util.is_Dict(val):
1214 for k, v in val.items():
1215 orig[k] = v
1216 else:
1217 orig[val] = None
1218 self.scanner_map_delete(kw)
1219
1220
1221
1228
1229 - def AppendENVPath(self, name, newpath, envname = 'ENV',
1230 sep = os.pathsep, delete_existing=0):
1231 """Append path elements to the path 'name' in the 'ENV'
1232 dictionary for this environment. Will only add any particular
1233 path once, and will normpath and normcase all paths to help
1234 assure this. This can also handle the case where the env
1235 variable is a list instead of a string.
1236
1237 If delete_existing is 0, a newpath which is already in the path
1238 will not be moved to the end (it will be left where it is).
1239 """
1240
1241 orig = ''
1242 if envname in self._dict and name in self._dict[envname]:
1243 orig = self._dict[envname][name]
1244
1245 nv = SCons.Util.AppendPath(orig, newpath, sep, delete_existing,
1246 canonicalize=self._canonicalize)
1247
1248 if envname not in self._dict:
1249 self._dict[envname] = {}
1250
1251 self._dict[envname][name] = nv
1252
1254 """Append values to existing construction variables
1255 in an Environment, if they're not already there.
1256 If delete_existing is 1, removes existing values first, so
1257 values move to end.
1258 """
1259 kw = copy_non_reserved_keywords(kw)
1260 for key, val in kw.items():
1261 if SCons.Util.is_List(val):
1262 val = _delete_duplicates(val, delete_existing)
1263 if key not in self._dict or self._dict[key] in ('', None):
1264 self._dict[key] = val
1265 elif SCons.Util.is_Dict(self._dict[key]) and \
1266 SCons.Util.is_Dict(val):
1267 self._dict[key].update(val)
1268 elif SCons.Util.is_List(val):
1269 dk = self._dict[key]
1270 if key == 'CPPDEFINES':
1271 tmp = []
1272 for i in val:
1273 if SCons.Util.is_List(i):
1274 if len(i) >= 2:
1275 tmp.append((i[0], i[1]))
1276 else:
1277 tmp.append((i[0],))
1278 elif SCons.Util.is_Tuple(i):
1279 tmp.append(i)
1280 else:
1281 tmp.append((i,))
1282 val = tmp
1283
1284 if SCons.Util.is_Dict(dk):
1285 tmp = []
1286 for (k, v) in dk.items():
1287 if v is not None:
1288 tmp.append((k, v))
1289 else:
1290 tmp.append((k,))
1291 dk = tmp
1292 elif SCons.Util.is_String(dk):
1293 dk = [(dk,)]
1294 else:
1295 tmp = []
1296 for i in dk:
1297 if SCons.Util.is_List(i):
1298 if len(i) >= 2:
1299 tmp.append((i[0], i[1]))
1300 else:
1301 tmp.append((i[0],))
1302 elif SCons.Util.is_Tuple(i):
1303 tmp.append(i)
1304 else:
1305 tmp.append((i,))
1306 dk = tmp
1307 else:
1308 if not SCons.Util.is_List(dk):
1309 dk = [dk]
1310 if delete_existing:
1311 dk = [x for x in dk if x not in val]
1312 else:
1313 val = [x for x in val if x not in dk]
1314 self._dict[key] = dk + val
1315 else:
1316 dk = self._dict[key]
1317 if SCons.Util.is_List(dk):
1318 if key == 'CPPDEFINES':
1319 tmp = []
1320 for i in dk:
1321 if SCons.Util.is_List(i):
1322 if len(i) >= 2:
1323 tmp.append((i[0], i[1]))
1324 else:
1325 tmp.append((i[0],))
1326 elif SCons.Util.is_Tuple(i):
1327 tmp.append(i)
1328 else:
1329 tmp.append((i,))
1330 dk = tmp
1331
1332 if SCons.Util.is_Dict(val):
1333 tmp = []
1334 for (k, v) in val.items():
1335 if v is not None:
1336 tmp.append((k, v))
1337 else:
1338 tmp.append((k,))
1339 val = tmp
1340 elif SCons.Util.is_String(val):
1341 val = [(val,)]
1342 if delete_existing:
1343 dk = list(filter(lambda x, val=val: x not in val, dk))
1344 self._dict[key] = dk + val
1345 else:
1346 dk = [x for x in dk if x not in val]
1347 self._dict[key] = dk + val
1348 else:
1349
1350
1351 if delete_existing:
1352 dk = list(filter(lambda x, val=val: x not in val, dk))
1353 self._dict[key] = dk + [val]
1354 else:
1355 if val not in dk:
1356 self._dict[key] = dk + [val]
1357 else:
1358 if key == 'CPPDEFINES':
1359 if SCons.Util.is_String(dk):
1360 dk = [dk]
1361 elif SCons.Util.is_Dict(dk):
1362 tmp = []
1363 for (k, v) in dk.items():
1364 if v is not None:
1365 tmp.append((k, v))
1366 else:
1367 tmp.append((k,))
1368 dk = tmp
1369 if SCons.Util.is_String(val):
1370 if val in dk:
1371 val = []
1372 else:
1373 val = [val]
1374 elif SCons.Util.is_Dict(val):
1375 tmp = []
1376 for i,j in val.items():
1377 if j is not None:
1378 tmp.append((i,j))
1379 else:
1380 tmp.append(i)
1381 val = tmp
1382 if delete_existing:
1383 dk = [x for x in dk if x not in val]
1384 self._dict[key] = dk + val
1385 self.scanner_map_delete(kw)
1386
1387 - def Clone(self, tools=[], toolpath=None, parse_flags = None, **kw):
1388 """Return a copy of a construction Environment. The
1389 copy is like a Python "deep copy"--that is, independent
1390 copies are made recursively of each objects--except that
1391 a reference is copied when an object is not deep-copyable
1392 (like a function). There are no references to any mutable
1393 objects in the original Environment.
1394 """
1395
1396 builders = self._dict.get('BUILDERS', {})
1397
1398 clone = copy.copy(self)
1399
1400 clone._dict = semi_deepcopy_dict(self._dict, ['BUILDERS'])
1401 clone._dict['BUILDERS'] = BuilderDict(builders, clone)
1402
1403
1404
1405
1406
1407 clone.added_methods = []
1408 for mw in self.added_methods:
1409 if mw == getattr(self, mw.name):
1410 clone.added_methods.append(mw.clone(clone))
1411
1412 clone._memo = {}
1413
1414
1415
1416 kw = copy_non_reserved_keywords(kw)
1417 new = {}
1418 for key, value in kw.items():
1419 new[key] = SCons.Subst.scons_subst_once(value, self, key)
1420 clone.Replace(**new)
1421
1422 apply_tools(clone, tools, toolpath)
1423
1424
1425 clone.Replace(**new)
1426
1427
1428 if parse_flags: clone.MergeFlags(parse_flags)
1429
1430 if SCons.Debug.track_instances: logInstanceCreation(self, 'Environment.EnvironmentClone')
1431 return clone
1432
1433 - def Copy(self, *args, **kw):
1440
1441 - def _changed_build(self, dependency, target, prev_ni, repo_node=None):
1442 if dependency.changed_state(target, prev_ni, repo_node):
1443 return 1
1444 return self.decide_source(dependency, target, prev_ni, repo_node)
1445
1446 - def _changed_content(self, dependency, target, prev_ni, repo_node=None):
1447 return dependency.changed_content(target, prev_ni, repo_node)
1448
1450 target_env = dependency.get_build_env()
1451 type = target_env.get_tgt_sig_type()
1452 if type == 'source':
1453 return target_env.decide_source(dependency, target, prev_ni, repo_node)
1454 else:
1455 return target_env.decide_target(dependency, target, prev_ni, repo_node)
1456
1457 - def _changed_timestamp_then_content(self, dependency, target, prev_ni, repo_node=None):
1458 return dependency.changed_timestamp_then_content(target, prev_ni, repo_node)
1459
1462
1465
1467 return self.fs.copy(src, dst)
1468
1470 return self.fs.copy2(src, dst)
1471
1495
1497 """Return the first available program in progs.
1498 """
1499 if not SCons.Util.is_List(progs):
1500 progs = [ progs ]
1501 for prog in progs:
1502 path = self.WhereIs(prog)
1503 if path: return prog
1504 return None
1505
1507 if not args:
1508 return self._dict
1509 dlist = [self._dict[x] for x in args]
1510 if len(dlist) == 1:
1511 dlist = dlist[0]
1512 return dlist
1513
1514 - def Dump(self, key = None):
1515 """
1516 Using the standard Python pretty printer, return the contents of the
1517 scons build environment as a string.
1518
1519 If the key passed in is anything other than None, then that will
1520 be used as an index into the build environment dictionary and
1521 whatever is found there will be fed into the pretty printer. Note
1522 that this key is case sensitive.
1523 """
1524 import pprint
1525 pp = pprint.PrettyPrinter(indent=2)
1526 if key:
1527 dict = self.Dictionary(key)
1528 else:
1529 dict = self.Dictionary()
1530 return pp.pformat(dict)
1531
1532 - def FindIxes(self, paths, prefix, suffix):
1533 """
1534 Search a list of paths for something that matches the prefix and suffix.
1535
1536 paths - the list of paths or nodes.
1537 prefix - construction variable for the prefix.
1538 suffix - construction variable for the suffix.
1539 """
1540
1541 suffix = self.subst('$'+suffix)
1542 prefix = self.subst('$'+prefix)
1543
1544 for path in paths:
1545 dir,name = os.path.split(str(path))
1546 if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix:
1547 return path
1548
1549 - def ParseConfig(self, command, function=None, unique=1):
1550 """
1551 Use the specified function to parse the output of the command
1552 in order to modify the current environment. The 'command' can
1553 be a string or a list of strings representing a command and
1554 its arguments. 'Function' is an optional argument that takes
1555 the environment, the output of the command, and the unique flag.
1556 If no function is specified, MergeFlags, which treats the output
1557 as the result of a typical 'X-config' command (i.e. gtk-config),
1558 will merge the output into the appropriate variables.
1559 """
1560 if function is None:
1561 def parse_conf(env, cmd, unique=unique):
1562 return env.MergeFlags(cmd, unique)
1563 function = parse_conf
1564 if SCons.Util.is_List(command):
1565 command = ' '.join(command)
1566 command = self.subst(command)
1567 return function(self, self.backtick(command))
1568
1569 - def ParseDepends(self, filename, must_exist=None, only_one=0):
1570 """
1571 Parse a mkdep-style file for explicit dependencies. This is
1572 completely abusable, and should be unnecessary in the "normal"
1573 case of proper SCons configuration, but it may help make
1574 the transition from a Make hierarchy easier for some people
1575 to swallow. It can also be genuinely useful when using a tool
1576 that can write a .d file, but for which writing a scanner would
1577 be too complicated.
1578 """
1579 filename = self.subst(filename)
1580 try:
1581 with open(filename, 'r') as fp:
1582 lines = SCons.Util.LogicalLines(fp).readlines()
1583 except IOError:
1584 if must_exist:
1585 raise
1586 return
1587 lines = [l for l in lines if l[0] != '#']
1588 tdlist = []
1589 for line in lines:
1590 try:
1591 target, depends = line.split(':', 1)
1592 except (AttributeError, ValueError):
1593
1594
1595 pass
1596 else:
1597 tdlist.append((target.split(), depends.split()))
1598 if only_one:
1599 targets = []
1600 for td in tdlist:
1601 targets.extend(td[0])
1602 if len(targets) > 1:
1603 raise SCons.Errors.UserError(
1604 "More than one dependency target found in `%s': %s"
1605 % (filename, targets))
1606 for target, depends in tdlist:
1607 self.Depends(target, depends)
1608
1612
1614 """Prepend values to existing construction variables
1615 in an Environment.
1616 """
1617 kw = copy_non_reserved_keywords(kw)
1618 for key, val in kw.items():
1619
1620
1621
1622
1623 try:
1624 orig = self._dict[key]
1625 except KeyError:
1626
1627
1628 self._dict[key] = val
1629 else:
1630 try:
1631
1632
1633
1634
1635
1636 update_dict = orig.update
1637 except AttributeError:
1638 try:
1639
1640
1641
1642 self._dict[key] = val + orig
1643 except (KeyError, TypeError):
1644 try:
1645
1646 add_to_val = val.append
1647 except AttributeError:
1648
1649
1650
1651
1652 if val:
1653 orig.insert(0, val)
1654 else:
1655
1656
1657
1658 if orig:
1659 add_to_val(orig)
1660 self._dict[key] = val
1661 else:
1662
1663
1664 if SCons.Util.is_List(val):
1665 for v in val:
1666 orig[v] = None
1667 else:
1668 try:
1669 update_dict(val)
1670 except (AttributeError, TypeError, ValueError):
1671 if SCons.Util.is_Dict(val):
1672 for k, v in val.items():
1673 orig[k] = v
1674 else:
1675 orig[val] = None
1676 self.scanner_map_delete(kw)
1677
1678 - def PrependENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep,
1679 delete_existing=1):
1680 """Prepend path elements to the path 'name' in the 'ENV'
1681 dictionary for this environment. Will only add any particular
1682 path once, and will normpath and normcase all paths to help
1683 assure this. This can also handle the case where the env
1684 variable is a list instead of a string.
1685
1686 If delete_existing is 0, a newpath which is already in the path
1687 will not be moved to the front (it will be left where it is).
1688 """
1689
1690 orig = ''
1691 if envname in self._dict and name in self._dict[envname]:
1692 orig = self._dict[envname][name]
1693
1694 nv = SCons.Util.PrependPath(orig, newpath, sep, delete_existing,
1695 canonicalize=self._canonicalize)
1696
1697 if envname not in self._dict:
1698 self._dict[envname] = {}
1699
1700 self._dict[envname][name] = nv
1701
1703 """Prepend values to existing construction variables
1704 in an Environment, if they're not already there.
1705 If delete_existing is 1, removes existing values first, so
1706 values move to front.
1707 """
1708 kw = copy_non_reserved_keywords(kw)
1709 for key, val in kw.items():
1710 if SCons.Util.is_List(val):
1711 val = _delete_duplicates(val, not delete_existing)
1712 if key not in self._dict or self._dict[key] in ('', None):
1713 self._dict[key] = val
1714 elif SCons.Util.is_Dict(self._dict[key]) and \
1715 SCons.Util.is_Dict(val):
1716 self._dict[key].update(val)
1717 elif SCons.Util.is_List(val):
1718 dk = self._dict[key]
1719 if not SCons.Util.is_List(dk):
1720 dk = [dk]
1721 if delete_existing:
1722 dk = [x for x in dk if x not in val]
1723 else:
1724 val = [x for x in val if x not in dk]
1725 self._dict[key] = val + dk
1726 else:
1727 dk = self._dict[key]
1728 if SCons.Util.is_List(dk):
1729
1730
1731 if delete_existing:
1732 dk = [x for x in dk if x not in val]
1733 self._dict[key] = [val] + dk
1734 else:
1735 if val not in dk:
1736 self._dict[key] = [val] + dk
1737 else:
1738 if delete_existing:
1739 dk = [x for x in dk if x not in val]
1740 self._dict[key] = val + dk
1741 self.scanner_map_delete(kw)
1742
1744 """Replace existing construction variables in an Environment
1745 with new construction variables and/or values.
1746 """
1747 try:
1748 kwbd = kw['BUILDERS']
1749 except KeyError:
1750 pass
1751 else:
1752 kwbd = BuilderDict(kwbd,self)
1753 del kw['BUILDERS']
1754 self.__setitem__('BUILDERS', kwbd)
1755 kw = copy_non_reserved_keywords(kw)
1756 self._update(semi_deepcopy(kw))
1757 self.scanner_map_delete(kw)
1758
1759 - def ReplaceIxes(self, path, old_prefix, old_suffix, new_prefix, new_suffix):
1760 """
1761 Replace old_prefix with new_prefix and old_suffix with new_suffix.
1762
1763 env - Environment used to interpolate variables.
1764 path - the path that will be modified.
1765 old_prefix - construction variable for the old prefix.
1766 old_suffix - construction variable for the old suffix.
1767 new_prefix - construction variable for the new prefix.
1768 new_suffix - construction variable for the new suffix.
1769 """
1770 old_prefix = self.subst('$'+old_prefix)
1771 old_suffix = self.subst('$'+old_suffix)
1772
1773 new_prefix = self.subst('$'+new_prefix)
1774 new_suffix = self.subst('$'+new_suffix)
1775
1776 dir,name = os.path.split(str(path))
1777 if name[:len(old_prefix)] == old_prefix:
1778 name = name[len(old_prefix):]
1779 if name[-len(old_suffix):] == old_suffix:
1780 name = name[:-len(old_suffix)]
1781 return os.path.join(dir, new_prefix+name+new_suffix)
1782
1784 for k in list(kw.keys()):
1785 if k in self._dict:
1786 del kw[k]
1787 self.Replace(**kw)
1788
1791
1800
1801 - def WhereIs(self, prog, path=None, pathext=None, reject=[]):
1802 """Find prog in the path.
1803 """
1804 if path is None:
1805 try:
1806 path = self['ENV']['PATH']
1807 except KeyError:
1808 pass
1809 elif SCons.Util.is_String(path):
1810 path = self.subst(path)
1811 if pathext is None:
1812 try:
1813 pathext = self['ENV']['PATHEXT']
1814 except KeyError:
1815 pass
1816 elif SCons.Util.is_String(pathext):
1817 pathext = self.subst(pathext)
1818 prog = SCons.Util.CLVar(self.subst(prog))
1819 path = SCons.Util.WhereIs(prog[0], path, pathext, reject)
1820 if path: return path
1821 return None
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831 - def Action(self, *args, **kw):
1832 def subst_string(a, self=self):
1833 if SCons.Util.is_String(a):
1834 a = self.subst(a)
1835 return a
1836 nargs = list(map(subst_string, args))
1837 nkw = self.subst_kw(kw)
1838 return SCons.Action.Action(*nargs, **nkw)
1839
1849
1850 - def AddPostAction(self, files, action):
1851 nodes = self.arg2nodes(files, self.fs.Entry)
1852 action = SCons.Action.Action(action)
1853 uniq = {}
1854 for executor in [n.get_executor() for n in nodes]:
1855 uniq[executor] = 1
1856 for executor in list(uniq.keys()):
1857 executor.add_post_action(action)
1858 return nodes
1859
1860 - def Alias(self, target, source=[], action=None, **kw):
1912
1920
1922 msg = """BuildDir() and the build_dir keyword have been deprecated;\n\tuse VariantDir() and the variant_dir keyword instead."""
1923 SCons.Warnings.warn(SCons.Warnings.DeprecatedBuildDirWarning, msg)
1924 if 'build_dir' in kw:
1925 kw['variant_dir'] = kw['build_dir']
1926 del kw['build_dir']
1927 return self.VariantDir(*args, **kw)
1928
1932
1938
1939 - def Clean(self, targets, files):
1948
1960
1961 - def Command(self, target, source, action, **kw):
1962 """Builds the supplied target files from the supplied
1963 source files using the supplied action. Action may
1964 be any type that the Builder constructor will accept
1965 for an action."""
1966 bkw = {
1967 'action' : action,
1968 'target_factory' : self.fs.Entry,
1969 'source_factory' : self.fs.Entry,
1970 }
1971 try: bkw['source_scanner'] = kw['source_scanner']
1972 except KeyError: pass
1973 else: del kw['source_scanner']
1974 bld = SCons.Builder.Builder(**bkw)
1975 return bld(self, target, source, **kw)
1976
1977 - def Depends(self, target, dependency):
1978 """Explicity specify that 'target's depend on 'dependency'."""
1979 tlist = self.arg2nodes(target, self.fs.Entry)
1980 dlist = self.arg2nodes(dependency, self.fs.Entry)
1981 for t in tlist:
1982 t.add_dependency(dlist)
1983 return tlist
1984
1985 - def Dir(self, name, *args, **kw):
1995
2004
2006 """Tags a target so that it will not be cleaned by -c"""
2007 tlist = []
2008 for t in targets:
2009 tlist.extend(self.arg2nodes(t, self.fs.Entry))
2010 for t in tlist:
2011 t.set_noclean()
2012 return tlist
2013
2015 """Tags a target so that it will not be cached"""
2016 tlist = []
2017 for t in targets:
2018 tlist.extend(self.arg2nodes(t, self.fs.Entry))
2019 for t in tlist:
2020 t.set_nocache()
2021 return tlist
2022
2023 - def Entry(self, name, *args, **kw):
2024 """
2025 """
2026 s = self.subst(name)
2027 if SCons.Util.is_Sequence(s):
2028 result=[]
2029 for e in s:
2030 result.append(self.fs.Entry(e, *args, **kw))
2031 return result
2032 return self.fs.Entry(s, *args, **kw)
2033
2036
2037 - def Execute(self, action, *args, **kw):
2038 """Directly execute an action through an Environment
2039 """
2040 action = self.Action(action, *args, **kw)
2041 result = action([], [], self)
2042 if isinstance(result, SCons.Errors.BuildError):
2043 errstr = result.errstr
2044 if result.filename:
2045 errstr = result.filename + ': ' + errstr
2046 sys.stderr.write("scons: *** %s\n" % errstr)
2047 return result.status
2048 else:
2049 return result
2050
2051 - def File(self, name, *args, **kw):
2061
2066
2069
2076
2077 - def Glob(self, pattern, ondisk=True, source=False, strings=False, exclude=None):
2078 return self.fs.Glob(self.subst(pattern), ondisk, source, strings, exclude)
2079
2080 - def Ignore(self, target, dependency):
2087
2090
2091 - def Local(self, *targets):
2102
2110
2118
2122
2123 - def Requires(self, target, prerequisite):
2124 """Specify that 'prerequisite' must be built before 'target',
2125 (but 'target' does not actually depend on 'prerequisite'
2126 and need not be rebuilt if it changes)."""
2127 tlist = self.arg2nodes(target, self.fs.Entry)
2128 plist = self.arg2nodes(prerequisite, self.fs.Entry)
2129 for t in tlist:
2130 t.add_prerequisite(plist)
2131 return tlist
2132
2141
2142 - def SConsignFile(self, name=".sconsign", dbm_module=None):
2153
2169
2179
2197
2199 """This function converts a string or list into a list of strings
2200 or Nodes. This makes things easier for users by allowing files to
2201 be specified as a white-space separated list to be split.
2202
2203 The input rules are:
2204 - A single string containing names separated by spaces. These will be
2205 split apart at the spaces.
2206 - A single Node instance
2207 - A list containing either strings or Node instances. Any strings
2208 in the list are not split at spaces.
2209
2210 In all cases, the function returns a list of Nodes and strings."""
2211
2212 if SCons.Util.is_List(arg):
2213 return list(map(self.subst, arg))
2214 elif SCons.Util.is_String(arg):
2215 return self.subst(arg).split()
2216 else:
2217 return [self.subst(arg)]
2218
2240
2241 - def Value(self, value, built_value=None):
2245
2246 - def VariantDir(self, variant_dir, src_dir, duplicate=1):
2250
2265 build_source(node.all_children())
2266
2267 def final_source(node):
2268 while (node != node.srcnode()):
2269 node = node.srcnode()
2270 return node
2271 sources = list(map(final_source, sources))
2272
2273 return list(set(sources))
2274
2276 """ returns the list of all targets of the Install and InstallAs Builder.
2277 """
2278 from SCons.Tool import install
2279 if install._UNIQUE_INSTALLED_FILES is None:
2280 install._UNIQUE_INSTALLED_FILES = SCons.Util.uniquer_hashables(install._INSTALLED_FILES)
2281 return install._UNIQUE_INSTALLED_FILES
2282
2285 """A proxy that overrides variables in a wrapped construction
2286 environment by returning values from an overrides dictionary in
2287 preference to values from the underlying subject environment.
2288
2289 This is a lightweight (I hope) proxy that passes through most use of
2290 attributes to the underlying Environment.Base class, but has just
2291 enough additional methods defined to act like a real construction
2292 environment with overridden values. It can wrap either a Base
2293 construction environment, or another OverrideEnvironment, which
2294 can in turn nest arbitrary OverrideEnvironments...
2295
2296 Note that we do *not* call the underlying base class
2297 (SubsitutionEnvironment) initialization, because we get most of those
2298 from proxying the attributes of the subject construction environment.
2299 But because we subclass SubstitutionEnvironment, this class also
2300 has inherited arg2nodes() and subst*() methods; those methods can't
2301 be proxied because they need *this* object's methods to fetch the
2302 values from the overrides dictionary.
2303 """
2304
2305 - def __init__(self, subject, overrides={}):
2309
2310
2312 attr = getattr(self.__dict__['__subject'], name)
2313
2314
2315
2316
2317
2318
2319
2320
2321 if isinstance(attr, (MethodWrapper, BuilderWrapper)):
2322 return attr.clone(self)
2323 else:
2324 return attr
2325
2327 setattr(self.__dict__['__subject'], name, value)
2328
2329
2331 try:
2332 return self.__dict__['overrides'][key]
2333 except KeyError:
2334 return self.__dict__['__subject'].__getitem__(key)
2340 try:
2341 del self.__dict__['overrides'][key]
2342 except KeyError:
2343 deleted = 0
2344 else:
2345 deleted = 1
2346 try:
2347 result = self.__dict__['__subject'].__delitem__(key)
2348 except KeyError:
2349 if not deleted:
2350 raise
2351 result = None
2352 return result
2353 - def get(self, key, default=None):
2354 """Emulates the get() method of dictionaries."""
2355 try:
2356 return self.__dict__['overrides'][key]
2357 except KeyError:
2358 return self.__dict__['__subject'].get(key, default)
2360 try:
2361 self.__dict__['overrides'][key]
2362 return 1
2363 except KeyError:
2364 return key in self.__dict__['__subject']
2370 """Emulates the items() method of dictionaries."""
2371 d = self.__dict__['__subject'].Dictionary().copy()
2372 d.update(self.__dict__['overrides'])
2373 return d
2375 """Emulates the items() method of dictionaries."""
2376 return list(self.Dictionary().items())
2377
2378
2380 """Update an environment's values directly, bypassing the normal
2381 checks that occur when users try to set items.
2382 """
2383 self.__dict__['overrides'].update(dict)
2384
2386 return self.__dict__['__subject'].gvars()
2387
2392
2393
2397
2398
2399
2400
2401
2402
2403
2404
2405 Environment = Base
2409 """
2410 An entry point for returning a proxy subclass instance that overrides
2411 the subst*() methods so they don't actually perform construction
2412 variable substitution. This is specifically intended to be the shim
2413 layer in between global function calls (which don't want construction
2414 variable substitution) and the DefaultEnvironment() (which would
2415 substitute variables if left to its own devices).
2416
2417 We have to wrap this in a function that allows us to delay definition of
2418 the class until it's necessary, so that when it subclasses Environment
2419 it will pick up whatever Environment subclass the wrapper interface
2420 might have assigned to SCons.Environment.Environment.
2421 """
2422 class _NoSubstitutionProxy(Environment):
2423 def __init__(self, subject):
2424 self.__dict__['__subject'] = subject
2425 def __getattr__(self, name):
2426 return getattr(self.__dict__['__subject'], name)
2427 def __setattr__(self, name, value):
2428 return setattr(self.__dict__['__subject'], name, value)
2429 def executor_to_lvars(self, kwdict):
2430 if 'executor' in kwdict:
2431 kwdict['lvars'] = kwdict['executor'].get_lvars()
2432 del kwdict['executor']
2433 else:
2434 kwdict['lvars'] = {}
2435 def raw_to_mode(self, dict):
2436 try:
2437 raw = dict['raw']
2438 except KeyError:
2439 pass
2440 else:
2441 del dict['raw']
2442 dict['mode'] = raw
2443 def subst(self, string, *args, **kwargs):
2444 return string
2445 def subst_kw(self, kw, *args, **kwargs):
2446 return kw
2447 def subst_list(self, string, *args, **kwargs):
2448 nargs = (string, self,) + args
2449 nkw = kwargs.copy()
2450 nkw['gvars'] = {}
2451 self.executor_to_lvars(nkw)
2452 self.raw_to_mode(nkw)
2453 return SCons.Subst.scons_subst_list(*nargs, **nkw)
2454 def subst_target_source(self, string, *args, **kwargs):
2455 nargs = (string, self,) + args
2456 nkw = kwargs.copy()
2457 nkw['gvars'] = {}
2458 self.executor_to_lvars(nkw)
2459 self.raw_to_mode(nkw)
2460 return SCons.Subst.scons_subst(*nargs, **nkw)
2461 return _NoSubstitutionProxy(subject)
2462
2463
2464
2465
2466
2467
2468