Index: build/scan_sources.py |
diff --git a/build/scan_sources.py b/build/scan_sources.py |
deleted file mode 100755 |
index 2c2fe41d276a0d321e61c4df14ee64e882e72880..0000000000000000000000000000000000000000 |
--- a/build/scan_sources.py |
+++ /dev/null |
@@ -1,308 +0,0 @@ |
-#!/usr/bin/python |
-# Copyright (c) 2012 The Native Client Authors. All rights reserved. |
-# Use of this source code is governed by a BSD-style license that can be |
-# found in the LICENSE file. |
- |
-import os |
-import re |
-import sys |
- |
-"""Header Scanner. |
- |
-This module will scan a set of input sources for include dependencies. Use |
-the command-line switch -Ixxxx to add include paths. All filenames and paths |
-are expected and returned with POSIX separators. |
-""" |
- |
- |
-debug = False |
- |
- |
-def DebugPrint(txt): |
- if debug: print txt |
- |
- |
-class PathConverter(object): |
- """PathConverter does path manipulates using Posix style pathnames. |
- |
- Regardless of the native path type, all inputs and outputs to the path |
- functions are with POSIX style separators. |
- """ |
- def ToNativePath(self, pathname): |
- return os.path.sep.join(pathname.split('/')) |
- |
- def ToPosixPath(self, pathname): |
- return '/'.join(pathname.split(os.path.sep)) |
- |
- def isfile(self, pathname): |
- ospath = self.ToNativePath(pathname) |
- return os.path.isfile(ospath) |
- |
- def getcwd(self): |
- return self.ToPosixPath(os.getcwd()) |
- |
- def isabs(self, pathname): |
- ospath = self.ToNativePath(pathname) |
- return os.path.isabs(ospath) |
- |
- def isdir(self, pathname): |
- ospath = self.ToNativePath(pathname) |
- return os.path.isdir(ospath) |
- |
- def open(self, pathname): |
- ospath = self.ToNativePath(pathname) |
- return open(ospath) |
- |
- def abspath(self, pathname): |
- ospath = self.ToNativePath(pathname) |
- ospath = os.path.abspath(ospath) |
- return self.ToPosixPath(ospath) |
- |
- def dirname(self, pathname): |
- ospath = self.ToNativePath(pathname) |
- ospath = os.path.dirname(ospath) |
- return self.ToPosixPath(ospath) |
- |
- |
-filename_to_relative_cache = {} # (filepath, basepath) -> relpath |
-findfile_cache = {} # (tuple(searchdirs), cwd, file) -> filename/None |
-pathisfile_cache = {} # abspath -> boolean, works because fs is static |
- # during a run. |
- |
- |
-class Resolver(object): |
- """Resolver finds and generates relative paths for include files. |
- |
- The Resolver object provides a mechanism to to find and convert a source or |
- include filename into a relative path based on provided search paths. All |
- paths use POSIX style separator. |
- """ |
- def __init__(self, pathobj=PathConverter()): |
- self.search_dirs = [] |
- self.pathobj = pathobj |
- self.cwd = self.pathobj.getcwd() |
- self.offs = len(self.cwd) |
- |
- def AddOneDirectory(self, pathname): |
- """Add an include search path.""" |
- pathname = self.pathobj.abspath(pathname) |
- DebugPrint('Adding DIR: %s' % pathname) |
- if pathname not in self.search_dirs: |
- if self.pathobj.isdir(pathname): |
- self.search_dirs.append(pathname) |
- else: |
- # We can end up here when using the gyp generator analyzer. To avoid |
- # spamming only log if debug enabled. |
- DebugPrint('Not a directory: %s\n' % pathname) |
- return False |
- return True |
- |
- def RemoveOneDirectory(self, pathname): |
- """Remove an include search path.""" |
- pathname = self.pathobj.abspath(pathname) |
- DebugPrint('Removing DIR: %s' % pathname) |
- if pathname in self.search_dirs: |
- self.search_dirs.remove(pathname) |
- return True |
- |
- def AddDirectories(self, pathlist): |
- """Add list of space separated directories.""" |
- failed = False |
- dirlist = ' '.join(pathlist) |
- for dirname in dirlist.split(' '): |
- if not self.AddOneDirectory(dirname): |
- failed = True |
- return not failed |
- |
- def GetDirectories(self): |
- return self.search_dirs |
- |
- def RealToRelative(self, filepath, basepath): |
- """Returns a relative path from an absolute basepath and filepath.""" |
- cache_key = (filepath, basepath) |
- cache_result = None |
- if cache_key in filename_to_relative_cache: |
- cache_result = filename_to_relative_cache[cache_key] |
- return cache_result |
- def SlowRealToRelative(filepath, basepath): |
- path_parts = filepath.split('/') |
- base_parts = basepath.split('/') |
- while path_parts and base_parts and path_parts[0] == base_parts[0]: |
- path_parts = path_parts[1:] |
- base_parts = base_parts[1:] |
- rel_parts = ['..'] * len(base_parts) + path_parts |
- rel_path = '/'.join(rel_parts) |
- return rel_path |
- rel_path = SlowRealToRelative(filepath, basepath) |
- filename_to_relative_cache[cache_key] = rel_path |
- return rel_path |
- |
- def FilenameToRelative(self, filepath): |
- """Returns a relative path from CWD to filepath.""" |
- filepath = self.pathobj.abspath(filepath) |
- basepath = self.cwd |
- return self.RealToRelative(filepath, basepath) |
- |
- def FindFile(self, filename): |
- """Search for <filename> across the search directories, if the path is not |
- absolute. Return the filepath relative to the CWD or None. """ |
- cache_key = (tuple(self.search_dirs), self.cwd, filename) |
- if cache_key in findfile_cache: |
- cache_result = findfile_cache[cache_key] |
- return cache_result |
- result = None |
- def isfile(absname): |
- res = pathisfile_cache.get(absname) |
- if res is None: |
- res = self.pathobj.isfile(absname) |
- pathisfile_cache[absname] = res |
- return res |
- |
- if self.pathobj.isabs(filename): |
- if isfile(filename): |
- result = self.FilenameToRelative(filename) |
- else: |
- for pathname in self.search_dirs: |
- fullname = '%s/%s' % (pathname, filename) |
- if isfile(fullname): |
- result = self.FilenameToRelative(fullname) |
- break |
- findfile_cache[cache_key] = result |
- return result |
- |
- |
-def LoadFile(filename): |
- # Catch cases where the file does not exist |
- try: |
- fd = PathConverter().open(filename) |
- except IOError: |
- DebugPrint('Exception on file: %s' % filename) |
- return '' |
- # Go ahead and throw if you fail to read |
- return fd.read() |
- |
- |
-scan_cache = {} # cache (abs_filename -> include_list) |
- |
- |
-class Scanner(object): |
- """Scanner searches for '#include' to find dependencies.""" |
- |
- def __init__(self, loader=None): |
- regex = r'^\s*\#[ \t]*include[ \t]*[<"]([^>"]+)[>"]' |
- self.parser = re.compile(regex, re.M) |
- self.loader = loader |
- if not loader: |
- self.loader = LoadFile |
- |
- def ScanData(self, data): |
- """Generate a list of includes from this text block.""" |
- return self.parser.findall(data) |
- |
- def ScanFile(self, filename): |
- """Generate a list of includes from this filename.""" |
- abs_filename = os.path.abspath(filename) |
- if abs_filename in scan_cache: |
- return scan_cache[abs_filename] |
- includes = self.ScanData(self.loader(filename)) |
- scan_cache[abs_filename] = includes |
- DebugPrint('Source %s contains:\n\t%s' % (filename, '\n\t'.join(includes))) |
- return includes |
- |
- |
-class WorkQueue(object): |
- """WorkQueue contains the list of files to be scanned. |
- |
- WorkQueue contains provides a queue of files to be processed. The scanner |
- will attempt to push new items into the queue, which will be ignored if the |
- item is already in the queue. If the item is new, it will be added to the |
- work list, which is drained by the scanner. |
- """ |
- def __init__(self, resolver, scanner=Scanner()): |
- self.added_set = set() |
- self.todo_list = list() |
- self.scanner = scanner |
- self.resolver = resolver |
- |
- def PushIfNew(self, filename): |
- """Add this dependency to the list of not already there.""" |
- DebugPrint('Adding %s' % filename) |
- resolved_name = self.resolver.FindFile(filename) |
- if not resolved_name: |
- DebugPrint('Failed to resolve %s' % filename) |
- return |
- DebugPrint('Resolvd as %s' % resolved_name) |
- if resolved_name in self.added_set: |
- return |
- self.todo_list.append(resolved_name) |
- self.added_set.add(resolved_name) |
- |
- def PopIfAvail(self): |
- """Fetch the next dependency to search.""" |
- if not self.todo_list: |
- return None |
- return self.todo_list.pop() |
- |
- def Run(self): |
- """Search through the available dependencies until the list becomes empty. |
- The list must be primed with one or more source files to search.""" |
- scan_name = self.PopIfAvail() |
- while scan_name: |
- includes = self.scanner.ScanFile(scan_name) |
- # Add the directory of the current scanned file for resolving includes |
- # while processing includes for this file. |
- scan_dir = PathConverter().dirname(scan_name) |
- added_dir = not self.resolver.AddOneDirectory(scan_dir) |
- for include_file in includes: |
- self.PushIfNew(include_file) |
- if added_dir: |
- self.resolver.RemoveOneDirectory(scan_dir) |
- scan_name = self.PopIfAvail() |
- return self.added_set |
- |
- |
-def DoMain(argv): |
- """Entry point used by gyp's pymod_do_main feature.""" |
- global debug |
- |
- resolver = Resolver() |
- files = [] |
- |
- arg_type = '' |
- for arg in argv: |
- if arg in ['-I', '-S']: |
- arg_type = arg |
- elif arg == '-D': |
- debug = True |
- elif arg_type == '-I': |
- # Skip generated include directories. These files may not exist and |
- # there should be explicit dependency on the target that generates |
- # these files. |
- if arg.startswith('$!PRODUCT_DIR'): |
- continue |
- resolver.AddDirectories([arg]) |
- elif arg_type == '-S': |
- files.append(arg) |
- |
- workQ = WorkQueue(resolver) |
- for filename in files: |
- workQ.PushIfNew(filename) |
- |
- sources_set = workQ.Run() |
- |
- # If any of the original files requested aren't found, add them anyway. |
- # This is so that source files that will be generated are still returned in |
- # the program output. |
- sources_set = sources_set.union(set(files)) |
- |
- sorted_list = sorted(sources_set) |
- return '\n'.join(sorted_list) + '\n' |
- |
- |
-def Main(): |
- result = DoMain(sys.argv[1:]) |
- sys.stdout.write(result) |
- |
- |
-if __name__ == '__main__': |
- Main() |