diff options
| author | Steven Knight <knight@baldmt.com> | 2003-09-07 04:14:49 (GMT) |
|---|---|---|
| committer | Steven Knight <knight@baldmt.com> | 2003-09-07 04:14:49 (GMT) |
| commit | 61d018dfceac6cb9717caeeea7125d7a55b4b0eb (patch) | |
| tree | a5d6529470d3797256f03ba197dedc1cac1feded /src/engine/SCons/Environment.py | |
| parent | bf221d4e593f803116af76ec3bc16514b666c9f1 (diff) | |
| download | SCons-61d018dfceac6cb9717caeeea7125d7a55b4b0eb.zip SCons-61d018dfceac6cb9717caeeea7125d7a55b4b0eb.tar.gz SCons-61d018dfceac6cb9717caeeea7125d7a55b4b0eb.tar.bz2 | |
Rearrange the Environment methods and tests.
Diffstat (limited to 'src/engine/SCons/Environment.py')
| -rw-r--r-- | src/engine/SCons/Environment.py | 552 |
1 files changed, 292 insertions, 260 deletions
diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py index f72bc95..e7407ee 100644 --- a/src/engine/SCons/Environment.py +++ b/src/engine/SCons/Environment.py @@ -59,6 +59,8 @@ class _Null: _null = _Null +DefaultTargets = None + def installFunc(target, source, env): """Install a source file into a target using the function specified as the INSTALL construction variable.""" @@ -169,6 +171,20 @@ class Environment: Environment. """ + ####################################################################### + # This is THE class for interacting with the SCons build engine, + # and it contains a lot of stuff, so we're going to try to keep this + # a little organized by grouping the methods. + ####################################################################### + + ####################################################################### + # Methods that make an Environment act like a dictionary. These have + # the expected standard names for Python mapping objects. Note that + # we don't actually make an Environment a subclass of UserDict for + # performance reasons. Note also that we only supply methods for + # dictionary functionality that we actually need and use. + ####################################################################### + def __init__(self, platform=None, tools=None, @@ -217,6 +233,46 @@ class Environment: def __cmp__(self, other): return cmp(self._dict, other._dict) + def __getitem__(self, key): + return self._dict[key] + + def __setitem__(self, key, value): + if key in ['TARGET', 'TARGETS', 'SOURCE', 'SOURCES']: + SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, + "Ignoring attempt to set reserved variable `%s'" % key) + elif key == 'BUILDERS': + try: + bd = self._dict[key] + for k in bd.keys(): + del bd[k] + except KeyError: + self._dict[key] = BuilderDict(kwbd, self) + self._dict[key].update(value) + else: + if not SCons.Util.is_valid_construction_var(key): + raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key + self._dict[key] = value + + def __delitem__(self, key): + del self._dict[key] + + def items(self): + "Emulates the items() method of dictionaries.""" + return self._dict.items() + + def has_key(self, key): + return self._dict.has_key(key) + + def get(self, key, default=None): + "Emulates the get() method of dictionaries.""" + return self._dict.get(key, default) + + ####################################################################### + # Utility methods that are primarily for internal use by SCons. + # These begin with lower-case letters. Note that the subst() method + # is actually already out of the closet and used by people. + ####################################################################### + def arg2nodes(self, args, node_factory=_null, lookup_list=_null): if node_factory is _null: node_factory = self.fs.File @@ -251,8 +307,99 @@ class Environment: return nodes - def Builders(self): - pass # XXX + def get_builder(self, name): + """Fetch the builder with the specified name from the environment. + """ + try: + return self._dict['BUILDERS'][name] + except KeyError: + return None + + def get_scanner(self, skey): + """Find the appropriate scanner given a key (usually a file suffix). + Does a linear search. Could be sped up by creating a dictionary if + this proves too slow. + """ + if self._dict['SCANNERS']: + for scanner in self._dict['SCANNERS']: + if skey in scanner.skeys: + return scanner + return None + + def subst(self, string, raw=0, target=None, source=None): + """Recursively interpolates construction variables from the + Environment into the specified string, returning the expanded + result. Construction variables are specified by a $ prefix + in the string and begin with an initial underscore or + alphabetic character followed by any number of underscores + or alphanumeric characters. The construction variable names + may be surrounded by curly braces to separate the name from + trailing characters. + """ + if raw: + mode = SCons.Util.SUBST_RAW + else: + mode = SCons.Util.SUBST_CMD + return SCons.Util.scons_subst(string, self, mode, + target, source) + + def subst_list(self, string, raw=0, target=None, source=None): + """Calls through to SCons.Util.scons_subst_list(). See + the documentation for that function.""" + if raw: + mode = SCons.Util.SUBST_RAW + else: + mode = SCons.Util.SUBST_CMD + return SCons.Util.scons_subst_list(string, self, mode, + target, source) + + ####################################################################### + # Public methods for manipulating an Environment. These begin with + # upper-case letters. The essential characteristic of methods in + # this section is that they do *not* have corresponding same-named + # global functions. For example, a stand-alone Append() function + # makes no sense, because Append() is all about appending values to + # an Environment's construction variables. + ####################################################################### + + def Append(self, **kw): + """Append values to existing construction variables + in an Environment. + """ + kw = our_deepcopy(kw) + for key in kw.keys(): + if not self._dict.has_key(key): + self._dict[key] = kw[key] + elif SCons.Util.is_List(self._dict[key]) and not \ + SCons.Util.is_List(kw[key]): + self._dict[key] = self._dict[key] + [ kw[key] ] + elif SCons.Util.is_List(kw[key]) and not \ + SCons.Util.is_List(self._dict[key]): + self._dict[key] = [ self._dict[key] ] + kw[key] + elif SCons.Util.is_Dict(self._dict[key]) and \ + SCons.Util.is_Dict(kw[key]): + self._dict[key].update(kw[key]) + else: + self._dict[key] = self._dict[key] + kw[key] + + def AppendENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep): + """Append path elements to the path 'name' in the 'ENV' + dictionary for this environment. Will only add any particular + path once, and will normpath and normcase all paths to help + assure this. This can also handle the case where the env + variable is a list instead of a string. + """ + + orig = '' + if self._dict.has_key(envname) and self._dict[envname].has_key(name): + orig = self._dict[envname][name] + + nv = SCons.Util.AppendPath(orig, newpath, sep) + + if not self._dict.has_key(envname): + self._dict[envname] = {} + + self._dict[envname][name] = nv def Copy(self, tools=None, **kw): """Return a copy of a construction Environment. The @@ -276,40 +423,62 @@ class Environment: apply(clone.Replace, (), kw) return clone - def Scanners(self): - pass # XXX + def Detect(self, progs): + """Return the first available program in progs. + """ + if not SCons.Util.is_List(progs): + progs = [ progs ] + for prog in progs: + path = self.WhereIs(prog) + if path: return prog + return None + + def Dictionary(self, *args): + if not args: + return self._dict + dlist = map(lambda x, s=self: s._dict[x], args) + if len(dlist) == 1: + dlist = dlist[0] + return dlist - def Replace(self, **kw): - """Replace existing construction variables in an Environment - with new construction variables and/or values. + def FindIxes(self, paths, prefix, suffix): """ - try: - kwbd = our_deepcopy(kw['BUILDERS']) - del kw['BUILDERS'] - self.__setitem__('BUILDERS', kwbd) - except KeyError: - pass - self._dict.update(our_deepcopy(kw)) + Search a list of paths for something that matches the prefix and suffix. - def Append(self, **kw): - """Append values to existing construction variables - in an Environment. + paths - the list of paths or nodes. + prefix - construction variable for the prefix. + suffix - construction variable for the suffix. """ - kw = our_deepcopy(kw) - for key in kw.keys(): - if not self._dict.has_key(key): - self._dict[key] = kw[key] - elif SCons.Util.is_List(self._dict[key]) and not \ - SCons.Util.is_List(kw[key]): - self._dict[key] = self._dict[key] + [ kw[key] ] - elif SCons.Util.is_List(kw[key]) and not \ - SCons.Util.is_List(self._dict[key]): - self._dict[key] = [ self._dict[key] ] + kw[key] - elif SCons.Util.is_Dict(self._dict[key]) and \ - SCons.Util.is_Dict(kw[key]): - self._dict[key].update(kw[key]) - else: - self._dict[key] = self._dict[key] + kw[key] + + suffix = self.subst('$%s'%suffix) + prefix = self.subst('$%s'%prefix) + + for path in paths: + dir,name = os.path.split(str(path)) + if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix: + return path + + def Override(self, overrides): + """ + Produce a modified environment whose variables + are overriden by the overrides dictionaries. + + overrides - a dictionary that will override + the variables of this environment. + + This function is much more efficient than Copy() + or creating a new Environment because it doesn't do + a deep copy of the dictionary, and doesn't do a copy + at all if there are no overrides. + """ + + if overrides: + env = copy.copy(self) + env._dict = copy.copy(self._dict) + env._dict.update(overrides) + return env + else: + return self def Prepend(self, **kw): """Prepend values to existing construction variables @@ -350,47 +519,63 @@ class Environment: self._dict[envname][name] = nv - def AppendENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep): - """Append path elements to the path 'name' in the 'ENV' - dictionary for this environment. Will only add any particular - path once, and will normpath and normcase all paths to help - assure this. This can also handle the case where the env - variable is a list instead of a string. + def Replace(self, **kw): + """Replace existing construction variables in an Environment + with new construction variables and/or values. """ + try: + kwbd = our_deepcopy(kw['BUILDERS']) + del kw['BUILDERS'] + self.__setitem__('BUILDERS', kwbd) + except KeyError: + pass + self._dict.update(our_deepcopy(kw)) - orig = '' - if self._dict.has_key(envname) and self._dict[envname].has_key(name): - orig = self._dict[envname][name] - - nv = SCons.Util.AppendPath(orig, newpath, sep) - - if not self._dict.has_key(envname): - self._dict[envname] = {} - - self._dict[envname][name] = nv + def ReplaceIxes(self, path, old_prefix, old_suffix, new_prefix, new_suffix): + """ + Replace old_prefix with new_prefix and old_suffix with new_suffix. + env - Environment used to interpolate variables. + path - the path that will be modified. + old_prefix - construction variable for the old prefix. + old_suffix - construction variable for the old suffix. + new_prefix - construction variable for the new prefix. + new_suffix - construction variable for the new suffix. + """ + old_prefix = self.subst('$%s'%old_prefix) + old_suffix = self.subst('$%s'%old_suffix) - def Depends(self, target, dependency): - """Explicity specify that 'target's depend on 'dependency'.""" - tlist = self.arg2nodes(target, self.fs.File) - dlist = self.arg2nodes(dependency, self.fs.File) - for t in tlist: - t.add_dependency(dlist) + new_prefix = self.subst('$%s'%new_prefix) + new_suffix = self.subst('$%s'%new_suffix) - if len(tlist) == 1: - tlist = tlist[0] - return tlist + dir,name = os.path.split(str(path)) + if name[:len(old_prefix)] == old_prefix: + name = name[len(old_prefix):] + if name[-len(old_suffix):] == old_suffix: + name = name[:-len(old_suffix)] + return os.path.join(dir, new_prefix+name+new_suffix) - def Ignore(self, target, dependency): - """Ignore a dependency.""" - tlist = self.arg2nodes(target, self.fs.File) - dlist = self.arg2nodes(dependency, self.fs.File) - for t in tlist: - t.add_ignore(dlist) + def WhereIs(self, prog): + """Find prog in the path. + """ + path = None + pathext = None + if self.has_key('ENV'): + if self['ENV'].has_key('PATH'): + path = self['ENV']['PATH'] + if self['ENV'].has_key('PATHEXT'): + pathext = self['ENV']['PATHEXT'] + path = SCons.Util.WhereIs(prog, path, pathext) + if path: return path + return None - if len(tlist) == 1: - tlist = tlist[0] - return tlist + ####################################################################### + # Public methods for doing real "SCons stuff" (manipulating + # dependencies, setting attributes on targets, etc.). These begin + # with upper-case letters. The essential characteristic of methods + # in this section is that they all *should* have corresponding + # same-named global functions. + ####################################################################### def AlwaysBuild(self, *targets): tlist = [] @@ -404,52 +589,6 @@ class Environment: tlist = tlist[0] return tlist - def Precious(self, *targets): - tlist = [] - for t in targets: - tlist.extend(self.arg2nodes(t, self.fs.File)) - - for t in tlist: - t.set_precious() - - if len(tlist) == 1: - tlist = tlist[0] - return tlist - - def Dictionary(self, *args): - if not args: - return self._dict - dlist = map(lambda x, s=self: s._dict[x], args) - if len(dlist) == 1: - dlist = dlist[0] - return dlist - - def __setitem__(self, key, value): - if key in ['TARGET', 'TARGETS', 'SOURCE', 'SOURCES']: - SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, - "Ignoring attempt to set reserved variable `%s'" % key) - elif key == 'BUILDERS': - try: - bd = self._dict[key] - for k in bd.keys(): - del bd[k] - except KeyError: - self._dict[key] = BuilderDict(kwbd, self) - self._dict[key].update(value) - else: - if not SCons.Util.is_valid_construction_var(key): - raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key - self._dict[key] = value - - def __getitem__(self, key): - return self._dict[key] - - def __delitem__(self, key): - del self._dict[key] - - def has_key(self, key): - return self._dict.has_key(key) - def Command(self, target, source, action): """Builds the supplied target files from the supplied source files using the supplied action. Action may @@ -459,6 +598,28 @@ class Environment: source_factory=SCons.Node.FS.default_fs.Entry) return bld(self, target, source) + def Depends(self, target, dependency): + """Explicity specify that 'target's depend on 'dependency'.""" + tlist = self.arg2nodes(target, self.fs.File) + dlist = self.arg2nodes(dependency, self.fs.File) + for t in tlist: + t.add_dependency(dlist) + + if len(tlist) == 1: + tlist = tlist[0] + return tlist + + def Ignore(self, target, dependency): + """Ignore a dependency.""" + tlist = self.arg2nodes(target, self.fs.File) + dlist = self.arg2nodes(dependency, self.fs.File) + for t in tlist: + t.add_ignore(dlist) + + if len(tlist) == 1: + tlist = tlist[0] + return tlist + def Install(self, dir, source): """Install specified files in the given directory.""" try: @@ -492,14 +653,17 @@ class Environment: ret = ret[0] return ret - def SourceCode(self, entry, builder): - """Arrange for a source code builder for (part of) a tree.""" - entries = self.arg2nodes(entry, self.fs.Entry) - for entry in entries: - entry.set_src_builder(builder) - if len(entries) == 1: - return entries[0] - return entries + def Precious(self, *targets): + tlist = [] + for t in targets: + tlist.extend(self.arg2nodes(t, self.fs.File)) + + for t in tlist: + t.set_precious() + + if len(tlist) == 1: + tlist = tlist[0] + return tlist def SideEffect(self, side_effect, target): """Tell scons that side_effects are built as side @@ -523,143 +687,11 @@ class Environment: else: return side_effects - def subst(self, string, raw=0, target=None, source=None): - """Recursively interpolates construction variables from the - Environment into the specified string, returning the expanded - result. Construction variables are specified by a $ prefix - in the string and begin with an initial underscore or - alphabetic character followed by any number of underscores - or alphanumeric characters. The construction variable names - may be surrounded by curly braces to separate the name from - trailing characters. - """ - if raw: - mode = SCons.Util.SUBST_RAW - else: - mode = SCons.Util.SUBST_CMD - return SCons.Util.scons_subst(string, self, mode, - target, source) - - def subst_list(self, string, raw=0, target=None, source=None): - """Calls through to SCons.Util.scons_subst_list(). See - the documentation for that function.""" - if raw: - mode = SCons.Util.SUBST_RAW - else: - mode = SCons.Util.SUBST_CMD - return SCons.Util.scons_subst_list(string, self, mode, - target, source) - - def get_scanner(self, skey): - """Find the appropriate scanner given a key (usually a file suffix). - Does a linear search. Could be sped up by creating a dictionary if - this proves too slow. - """ - if self._dict['SCANNERS']: - for scanner in self._dict['SCANNERS']: - if skey in scanner.skeys: - return scanner - return None - - def get_builder(self, name): - """Fetch the builder with the specified name from the environment. - """ - try: - return self._dict['BUILDERS'][name] - except KeyError: - return None - - def Detect(self, progs): - """Return the first available program in progs. - """ - if not SCons.Util.is_List(progs): - progs = [ progs ] - for prog in progs: - path = self.WhereIs(prog) - if path: return prog - return None - - def WhereIs(self, prog): - """Find prog in the path. - """ - path = None - pathext = None - if self.has_key('ENV'): - if self['ENV'].has_key('PATH'): - path = self['ENV']['PATH'] - if self['ENV'].has_key('PATHEXT'): - pathext = self['ENV']['PATHEXT'] - path = SCons.Util.WhereIs(prog, path, pathext) - if path: return path - return None - - def Override(self, overrides): - """ - Produce a modified environment whose variables - are overriden by the overrides dictionaries. - - overrides - a dictionary that will override - the variables of this environment. - - This function is much more efficient than Copy() - or creating a new Environment because it doesn't do - a deep copy of the dictionary, and doesn't do a copy - at all if there are no overrides. - """ - - if overrides: - env = copy.copy(self) - env._dict = copy.copy(self._dict) - env._dict.update(overrides) - return env - else: - return self - - def get(self, key, default=None): - "Emulates the get() method of dictionaries.""" - return self._dict.get(key, default) - - def items(self): - "Emulates the items() method of dictionaries.""" - return self._dict.items() - - def FindIxes(self, paths, prefix, suffix): - """ - Search a list of paths for something that matches the prefix and suffix. - - paths - the list of paths or nodes. - prefix - construction variable for the prefix. - suffix - construction variable for the suffix. - """ - - suffix = self.subst('$%s'%suffix) - prefix = self.subst('$%s'%prefix) - - for path in paths: - dir,name = os.path.split(str(path)) - if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix: - return path - - def ReplaceIxes(self, path, old_prefix, old_suffix, new_prefix, new_suffix): - """ - Replace old_prefix with new_prefix and old_suffix with new_suffix. - - env - Environment used to interpolate variables. - path - the path that will be modified. - old_prefix - construction variable for the old prefix. - old_suffix - construction variable for the old suffix. - new_prefix - construction variable for the new prefix. - new_suffix - construction variable for the new suffix. - """ - old_prefix = self.subst('$%s'%old_prefix) - old_suffix = self.subst('$%s'%old_suffix) - - new_prefix = self.subst('$%s'%new_prefix) - new_suffix = self.subst('$%s'%new_suffix) - - dir,name = os.path.split(str(path)) - if name[:len(old_prefix)] == old_prefix: - name = name[len(old_prefix):] - if name[-len(old_suffix):] == old_suffix: - name = name[:-len(old_suffix)] - return os.path.join(dir, new_prefix+name+new_suffix) + def SourceCode(self, entry, builder): + """Arrange for a source code builder for (part of) a tree.""" + entries = self.arg2nodes(entry, self.fs.Entry) + for entry in entries: + entry.set_src_builder(builder) + if len(entries) == 1: + return entries[0] + return entries |
