| Index: pylib/gyp/input.py
|
| diff --git a/pylib/gyp/input.py b/pylib/gyp/input.py
|
| index 004b7dfa47ab037063911720f111018dbf659b13..34fbc54711923ca53def6cb3a86e5acc2680237d 100644
|
| --- a/pylib/gyp/input.py
|
| +++ b/pylib/gyp/input.py
|
| @@ -48,6 +48,11 @@ base_path_sections = [
|
| ]
|
| path_sections = set()
|
|
|
| +# These per-process dictionaries are used to cache build file data when loading
|
| +# in parallel mode.
|
| +per_process_data = {}
|
| +per_process_aux_data = {}
|
| +
|
| def IsPathSection(section):
|
| # If section ends in one of the '=+?!' characters, it's applied to a section
|
| # without the trailing characters. '/' is notably absent from this list,
|
| @@ -362,10 +367,17 @@ def LoadTargetBuildFile(build_file_path, data, aux_data, variables, includes,
|
| else:
|
| variables['DEPTH'] = d.replace('\\', '/')
|
|
|
| - if build_file_path in data['target_build_files']:
|
| - # Already loaded.
|
| - return False
|
| - data['target_build_files'].add(build_file_path)
|
| + # The 'target_build_files' key is only set when loading target build files in
|
| + # the non-parallel code path, where LoadTargetBuildFile is called
|
| + # recursively. In the parallel code path, we don't need to check whether the
|
| + # |build_file_path| has already been loaded, because the 'scheduled' set in
|
| + # ParallelState guarantees that we never load the same |build_file_path|
|
| + # twice.
|
| + if 'target_build_files' in data:
|
| + if build_file_path in data['target_build_files']:
|
| + # Already loaded.
|
| + return False
|
| + data['target_build_files'].add(build_file_path)
|
|
|
| gyp.DebugOutput(gyp.DEBUG_INCLUDES,
|
| "Loading Target Build File '%s'", build_file_path)
|
| @@ -456,10 +468,8 @@ def LoadTargetBuildFile(build_file_path, data, aux_data, variables, includes,
|
| else:
|
| return (build_file_path, dependencies)
|
|
|
| -
|
| def CallLoadTargetBuildFile(global_flags,
|
| - build_file_path, data,
|
| - aux_data, variables,
|
| + build_file_path, variables,
|
| includes, depth, check,
|
| generator_input_info):
|
| """Wrapper around LoadTargetBuildFile for parallel processing.
|
| @@ -475,35 +485,24 @@ def CallLoadTargetBuildFile(global_flags,
|
| for key, value in global_flags.iteritems():
|
| globals()[key] = value
|
|
|
| - # Save the keys so we can return data that changed.
|
| - data_keys = set(data)
|
| - aux_data_keys = set(aux_data)
|
| -
|
| SetGeneratorGlobals(generator_input_info)
|
| - result = LoadTargetBuildFile(build_file_path, data,
|
| - aux_data, variables,
|
| + result = LoadTargetBuildFile(build_file_path, per_process_data,
|
| + per_process_aux_data, variables,
|
| includes, depth, check, False)
|
| if not result:
|
| return result
|
|
|
| (build_file_path, dependencies) = result
|
|
|
| - data_out = {}
|
| - for key in data:
|
| - if key == 'target_build_files':
|
| - continue
|
| - if key not in data_keys:
|
| - data_out[key] = data[key]
|
| - aux_data_out = {}
|
| - for key in aux_data:
|
| - if key not in aux_data_keys:
|
| - aux_data_out[key] = aux_data[key]
|
| + # We can safely pop the build_file_data from per_process_data because it
|
| + # will never be referenced by this process again, so we don't need to keep
|
| + # it in the cache.
|
| + build_file_data = per_process_data.pop(build_file_path)
|
|
|
| # This gets serialized and sent back to the main process via a pipe.
|
| # It's handled in LoadTargetBuildFileCallback.
|
| return (build_file_path,
|
| - data_out,
|
| - aux_data_out,
|
| + build_file_data,
|
| dependencies)
|
| except GypError, e:
|
| sys.stderr.write("gyp: %s\n" % e)
|
| @@ -534,8 +533,6 @@ class ParallelState(object):
|
| self.condition = None
|
| # The "data" dict that was passed to LoadTargetBuildFileParallel
|
| self.data = None
|
| - # The "aux_data" dict that was passed to LoadTargetBuildFileParallel
|
| - self.aux_data = None
|
| # The number of parallel calls outstanding; decremented when a response
|
| # was received.
|
| self.pending = 0
|
| @@ -556,12 +553,9 @@ class ParallelState(object):
|
| self.condition.notify()
|
| self.condition.release()
|
| return
|
| - (build_file_path0, data0, aux_data0, dependencies0) = result
|
| + (build_file_path0, build_file_data0, dependencies0) = result
|
| + self.data[build_file_path0] = build_file_data0
|
| self.data['target_build_files'].add(build_file_path0)
|
| - for key in data0:
|
| - self.data[key] = data0[key]
|
| - for key in aux_data0:
|
| - self.aux_data[key] = aux_data0[key]
|
| for new_dependency in dependencies0:
|
| if new_dependency not in self.scheduled:
|
| self.scheduled.add(new_dependency)
|
| @@ -571,9 +565,8 @@ class ParallelState(object):
|
| self.condition.release()
|
|
|
|
|
| -def LoadTargetBuildFilesParallel(build_files, data, aux_data,
|
| - variables, includes, depth, check,
|
| - generator_input_info):
|
| +def LoadTargetBuildFilesParallel(build_files, data, variables, includes, depth,
|
| + check, generator_input_info):
|
| parallel_state = ParallelState()
|
| parallel_state.condition = threading.Condition()
|
| # Make copies of the build_files argument that we can modify while working.
|
| @@ -581,7 +574,6 @@ def LoadTargetBuildFilesParallel(build_files, data, aux_data,
|
| parallel_state.scheduled = set(build_files)
|
| parallel_state.pending = 0
|
| parallel_state.data = data
|
| - parallel_state.aux_data = aux_data
|
|
|
| try:
|
| parallel_state.condition.acquire()
|
| @@ -595,9 +587,6 @@ def LoadTargetBuildFilesParallel(build_files, data, aux_data,
|
| dependency = parallel_state.dependencies.pop()
|
|
|
| parallel_state.pending += 1
|
| - data_in = {}
|
| - data_in['target_build_files'] = data['target_build_files']
|
| - aux_data_in = {}
|
| global_flags = {
|
| 'path_sections': globals()['path_sections'],
|
| 'non_configuration_keys': globals()['non_configuration_keys'],
|
| @@ -608,7 +597,6 @@ def LoadTargetBuildFilesParallel(build_files, data, aux_data,
|
| parallel_state.pool.apply_async(
|
| CallLoadTargetBuildFile,
|
| args = (global_flags, dependency,
|
| - data_in, aux_data_in,
|
| variables, includes, depth, check, generator_input_info),
|
| callback = parallel_state.LoadTargetBuildFileCallback)
|
| except KeyboardInterrupt, e:
|
| @@ -2734,15 +2722,14 @@ def Load(build_files, variables, includes, depth, generator_input_info, check,
|
| # well as meta-data (e.g. 'included_files' key). 'target_build_files' keeps
|
| # track of the keys corresponding to "target" files.
|
| data = {'target_build_files': set()}
|
| - aux_data = {}
|
| # Normalize paths everywhere. This is important because paths will be
|
| # used as keys to the data dict and for references between input files.
|
| build_files = set(map(os.path.normpath, build_files))
|
| if parallel:
|
| - LoadTargetBuildFilesParallel(build_files, data, aux_data,
|
| - variables, includes, depth, check,
|
| - generator_input_info)
|
| + LoadTargetBuildFilesParallel(build_files, data, variables, includes, depth,
|
| + check, generator_input_info)
|
| else:
|
| + aux_data = {}
|
| for build_file in build_files:
|
| try:
|
| LoadTargetBuildFile(build_file, data, aux_data,
|
|
|