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