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