| # Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """ |
| Tool module for adding, to a construction environment, Chromium-specific |
| wrappers around SCons builders. This gives us a central place for any |
| customization we need to make to the different things we build. |
| """ |
| |
| import sys |
| |
| from SCons.Script import * |
| |
| import SCons.Node |
| import SCons.Util |
| |
| class Null(object): |
| def __new__(cls, *args, **kwargs): |
| if '_inst' not in vars(cls): |
| cls._inst = super(type, cls).__new__(cls, *args, **kwargs) |
| return cls._inst |
| def __init__(self, *args, **kwargs): pass |
| def __call__(self, *args, **kwargs): return self |
| def __repr__(self): return "Null()" |
| def __nonzero__(self): return False |
| def __getattr__(self, name): return self |
| def __setattr__(self, name, val): return self |
| def __delattr__(self, name): return self |
| def __getitem__(self, name): return self |
| |
| class FileList(object): |
| def __init__(self, entries=None): |
| if isinstance(entries, FileList): |
| entries = entries.entries |
| self.entries = entries or [] |
| def __getitem__(self, i): |
| return self.entries[i] |
| def __setitem__(self, i, item): |
| self.entries[i] = item |
| def __delitem__(self, i): |
| del self.entries[i] |
| def __add__(self, other): |
| if isinstance(other, FileList): |
| return self.__class__(self.entries + other.entries) |
| elif isinstance(other, type(self.entries)): |
| return self.__class__(self.entries + other) |
| else: |
| return self.__class__(self.entries + list(other)) |
| def __radd__(self, other): |
| if isinstance(other, FileList): |
| return self.__class__(other.entries + self.entries) |
| elif isinstance(other, type(self.entries)): |
| return self.__class__(other + self.entries) |
| else: |
| return self.__class__(list(other) + self.entries) |
| def __iadd__(self, other): |
| if isinstance(other, FileList): |
| self.entries += other.entries |
| elif isinstance(other, type(self.entries)): |
| self.entries += other |
| else: |
| self.entries += list(other) |
| return self |
| def append(self, item): |
| return self.entries.append(item) |
| def extend(self, item): |
| return self.entries.extend(item) |
| def index(self, item, *args): |
| return self.entries.index(item, *args) |
| def remove(self, item): |
| return self.entries.remove(item) |
| |
| def FileListWalk(top, topdown=True, onerror=None): |
| """ |
| """ |
| try: |
| entries = top.entries |
| except AttributeError, err: |
| if onerror is not None: |
| onerror(err) |
| return |
| |
| dirs, nondirs = [], [] |
| for entry in entries: |
| if hasattr(entry, 'entries'): |
| dirs.append(entry) |
| else: |
| nondirs.append(entry) |
| |
| if topdown: |
| yield top, dirs, nondirs |
| for entry in dirs: |
| for x in FileListWalk(entry, topdown, onerror): |
| yield x |
| if not topdown: |
| yield top, dirs, nondirs |
| |
| class ChromeFileList(FileList): |
| def Append(self, *args): |
| for element in args: |
| self.append(element) |
| def Extend(self, *args): |
| for element in args: |
| self.extend(element) |
| def Remove(self, *args): |
| for top, lists, nonlists in FileListWalk(self, topdown=False): |
| for element in args: |
| try: |
| top.remove(element) |
| except ValueError: |
| pass |
| def Replace(self, old, new): |
| for top, lists, nonlists in FileListWalk(self, topdown=False): |
| try: |
| i = top.index(old) |
| except ValueError: |
| pass |
| else: |
| if SCons.Util.is_List(new): |
| top[i:i+1] = new |
| else: |
| top[i] = new |
| |
| |
| def FilterOut(self, **kw): |
| """Removes values from existing construction variables in an Environment. |
| |
| The values to remove should be a list. For example: |
| |
| self.FilterOut(CPPDEFINES=['REMOVE_ME', 'ME_TOO']) |
| |
| Args: |
| self: Environment to alter. |
| kw: (Any other named arguments are values to remove). |
| """ |
| |
| kw = SCons.Environment.copy_non_reserved_keywords(kw) |
| for key, val in kw.items(): |
| envval = self.get(key, None) |
| if envval is None: |
| # No existing variable in the environment, so nothing to delete. |
| continue |
| |
| for vremove in val: |
| # Use while not if, so we can handle duplicates. |
| while vremove in envval: |
| envval.remove(vremove) |
| |
| self[key] = envval |
| |
| # TODO(sgk): SCons.Environment.Append() has much more logic to deal |
| # with various types of values. We should handle all those cases in here |
| # too. (If variable is a dict, etc.) |
| |
| |
| import __builtin__ |
| __builtin__.ChromeFileList = ChromeFileList |
| |
| non_compilable_suffixes = { |
| 'LINUX' : set([ |
| '.bdic', |
| '.css', |
| '.dat', |
| '.fragment', |
| '.gperf', |
| '.h', |
| '.html', |
| '.hxx', |
| '.idl', |
| '.js', |
| '.mk', |
| '.rc', |
| '.sigs', |
| ]), |
| 'WINDOWS' : set([ |
| '.h', |
| '.dat', |
| '.idl', |
| ]), |
| } |
| |
| def compilable(env, file): |
| base, ext = os.path.splitext(str(file)) |
| if ext in non_compilable_suffixes[env['TARGET_PLATFORM']]: |
| return False |
| return True |
| |
| def compilable_files(env, sources): |
| if not hasattr(sources, 'entries'): |
| return [x for x in sources if compilable(env, x)] |
| result = [] |
| for top, folders, nonfolders in FileListWalk(sources): |
| result.extend([x for x in nonfolders if compilable(env, x)]) |
| return result |
| |
| def ChromeProgram(env, target, source, *args, **kw): |
| source = compilable_files(env, source) |
| result = env.Program('$TOP_BUILDDIR/' + str(target), source, *args, **kw) |
| if env.get('INCREMENTAL'): |
| env.Precious(result) |
| return result |
| |
| def ChromeTestProgram(env, target, source, *args, **kw): |
| source = compilable_files(env, source) |
| result = env.Program('$TOP_BUILDDIR/' + str(target), source, *args, **kw) |
| if env.get('INCREMENTAL'): |
| env.Precious(*result) |
| return result |
| |
| def ChromeLibrary(env, target, source, *args, **kw): |
| source = compilable_files(env, source) |
| result = env.Library('$LIB_DIR/' + str(target), source, *args, **kw) |
| return result |
| |
| def ChromeLoadableModule(env, target, source, *args, **kw): |
| source = compilable_files(env, source) |
| if env.get('_GYP'): |
| result = env.LoadableModule(target, source, *args, **kw) |
| else: |
| kw['COMPONENT_STATIC'] = True |
| result = env.LoadableModule(target, source, *args, **kw) |
| return result |
| |
| def ChromeStaticLibrary(env, target, source, *args, **kw): |
| source = compilable_files(env, source) |
| if env.get('_GYP'): |
| result = env.StaticLibrary('$LIB_DIR/' + str(target), source, *args, **kw) |
| else: |
| kw['COMPONENT_STATIC'] = True |
| result = env.ComponentLibrary(target, source, *args, **kw) |
| return result |
| |
| def ChromeSharedLibrary(env, target, source, *args, **kw): |
| source = compilable_files(env, source) |
| if env.get('_GYP'): |
| result = env.SharedLibrary('$LIB_DIR/' + str(target), source, *args, **kw) |
| else: |
| kw['COMPONENT_STATIC'] = False |
| result = [env.ComponentLibrary(target, source, *args, **kw)[0]] |
| if env.get('INCREMENTAL'): |
| env.Precious(result) |
| return result |
| |
| def ChromeObject(env, *args, **kw): |
| if env.get('_GYP'): |
| result = env.Object(target, source, *args, **kw) |
| else: |
| result = env.ComponentObject(*args, **kw) |
| return result |
| |
| def generate(env): |
| env.AddMethod(ChromeProgram) |
| env.AddMethod(ChromeTestProgram) |
| env.AddMethod(ChromeLibrary) |
| env.AddMethod(ChromeLoadableModule) |
| env.AddMethod(ChromeStaticLibrary) |
| env.AddMethod(ChromeSharedLibrary) |
| env.AddMethod(ChromeObject) |
| |
| env.AddMethod(FilterOut) |
| |
| # Add the grit tool to the base environment because we use this a lot. |
| sys.path.append(env.Dir('$SRC_DIR/tools/grit').abspath) |
| env.Tool('scons', toolpath=[env.Dir('$SRC_DIR/tools/grit/grit')]) |
| |
| # Add the repack python script tool that we use in multiple places. |
| sys.path.append(env.Dir('$SRC_DIR/tools/data_pack').abspath) |
| env.Tool('scons', toolpath=[env.Dir('$SRC_DIR/tools/data_pack/')]) |
| |
| def exists(env): |
| return True |