Chromium Code Reviews| Index: pylib/gyp/generator/msvs.py |
| diff --git a/pylib/gyp/generator/msvs.py b/pylib/gyp/generator/msvs.py |
| index 0287eb19e0671d505f31a7ed2bed0b311096f296..3a1b6105d6ca9a1bd62b62bb86ba71aee19614c8 100644 |
| --- a/pylib/gyp/generator/msvs.py |
| +++ b/pylib/gyp/generator/msvs.py |
| @@ -2,6 +2,7 @@ |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| +import collections |
| import copy |
| import ntpath |
| import os |
| @@ -86,6 +87,46 @@ cached_username = None |
| cached_domain = None |
| +# Based on http://code.activestate.com/recipes/576694/. |
| +class OrderedSet(collections.MutableSet): |
| + def __init__(self, iterable=None): |
| + self.end = end = [] |
| + end += [None, end, end] # sentinel node for doubly linked list |
| + self.map = {} # key --> [key, prev, next] |
| + if iterable is not None: |
| + self |= iterable |
| + |
| + def __len__(self): |
| + return len(self.map) |
| + |
| + def discard(self, key): |
|
Nico
2013/12/06 20:35:54
Is this needed?
scottmg
2013/12/06 20:43:46
Yup: http://docs.python.org/2/library/collections.
|
| + if key in self.map: |
| + key, prev, next = self.map.pop(key) |
| + prev[2] = next |
| + next[1] = prev |
| + |
| + def __contains__(self, key): |
| + return key in self.map |
| + |
| + def add(self, key): |
| + if key not in self.map: |
| + end = self.end |
| + curr = end[1] |
| + curr[2] = end[1] = self.map[key] = [key, curr, end] |
| + |
| + def update(self, iterable): |
| + for i in iterable: |
| + if i not in self: |
| + self.add(i) |
| + |
| + def __iter__(self): |
| + end = self.end |
| + curr = end[2] |
| + while curr is not end: |
| + yield curr[0] |
| + curr = curr[2] |
| + |
| + |
| # TODO(gspencer): Switch the os.environ calls to be |
| # win32api.GetDomainName() and win32api.GetUserName() once the |
| # python version in depot_tools has been updated to work on Vista |
| @@ -415,13 +456,13 @@ def _AddAccumulatedActionsToMSVS(p, spec, actions_dict): |
| dicts describing the actions attached to that input file. |
| """ |
| for primary_input in actions_dict: |
| - inputs = set() |
| - outputs = set() |
| + inputs = OrderedSet() |
| + outputs = OrderedSet() |
| descriptions = [] |
| commands = [] |
| for action in actions_dict[primary_input]: |
| - inputs.update(set(action['inputs'])) |
| - outputs.update(set(action['outputs'])) |
| + inputs.update(OrderedSet(action['inputs'])) |
| + outputs.update(OrderedSet(action['outputs'])) |
| descriptions.append(action['description']) |
| commands.append(action['command']) |
| # Add the custom build step for one input file. |
| @@ -477,8 +518,8 @@ def _RuleInputsAndOutputs(rule, trigger_file): |
| """ |
| raw_inputs = _FixPaths(rule.get('inputs', [])) |
| raw_outputs = _FixPaths(rule.get('outputs', [])) |
| - inputs = set() |
| - outputs = set() |
| + inputs = OrderedSet() |
| + outputs = OrderedSet() |
| inputs.add(trigger_file) |
| for i in raw_inputs: |
| inputs.add(_RuleExpandPath(i, trigger_file)) |
| @@ -549,16 +590,16 @@ def _GenerateExternalRules(rules, output_dir, spec, |
| mk_file.write('OutDirCygwin:=$(shell cygpath -u "$(OutDir)")\n') |
| mk_file.write('IntDirCygwin:=$(shell cygpath -u "$(IntDir)")\n') |
| # Gather stuff needed to emit all: target. |
| - all_inputs = set() |
| - all_outputs = set() |
| - all_output_dirs = set() |
| + all_inputs = OrderedSet() |
| + all_outputs = OrderedSet() |
| + all_output_dirs = OrderedSet() |
| first_outputs = [] |
| for rule in rules: |
| trigger_files = _FindRuleTriggerFiles(rule, sources) |
| for tf in trigger_files: |
| inputs, outputs = _RuleInputsAndOutputs(rule, tf) |
| - all_inputs.update(set(inputs)) |
| - all_outputs.update(set(outputs)) |
| + all_inputs.update(OrderedSet(inputs)) |
| + all_outputs.update(OrderedSet(outputs)) |
| # Only use one target from each rule as the dependency for |
| # 'all' so we don't try to build each rule multiple times. |
| first_outputs.append(list(outputs)[0]) |
| @@ -799,8 +840,8 @@ def _AdjustSourcesForRules(spec, rules, sources, excluded_sources): |
| trigger_files = _FindRuleTriggerFiles(rule, sources) |
| for trigger_file in trigger_files: |
| inputs, outputs = _RuleInputsAndOutputs(rule, trigger_file) |
| - inputs = set(_FixPaths(inputs)) |
| - outputs = set(_FixPaths(outputs)) |
| + inputs = OrderedSet(_FixPaths(inputs)) |
| + outputs = OrderedSet(_FixPaths(outputs)) |
| inputs.remove(_FixPath(trigger_file)) |
| sources.update(inputs) |
| if not spec.get('msvs_external_builder'): |
| @@ -817,7 +858,7 @@ def _FilterActionsFromExcluded(excluded_sources, actions_to_add): |
| Returns: |
| excluded_sources with files that have actions attached removed. |
| """ |
| - must_keep = set(_FixPaths(actions_to_add.keys())) |
| + must_keep = OrderedSet(_FixPaths(actions_to_add.keys())) |
| return [s for s in excluded_sources if s not in must_keep] |
| @@ -965,7 +1006,7 @@ def _GetUniquePlatforms(spec): |
| The MSVSUserFile object created. |
| """ |
| # Gather list of unique platforms. |
| - platforms = set() |
| + platforms = OrderedSet() |
| for configuration in spec['configurations']: |
| platforms.add(_ConfigPlatform(spec['configurations'][configuration])) |
| platforms = list(platforms) |
| @@ -1152,7 +1193,7 @@ def _GetLibraries(spec): |
| # in libraries that are assumed to be in the default library path). |
| # Also remove duplicate entries, leaving only the last duplicate, while |
| # preserving order. |
| - found = set() |
| + found = OrderedSet() |
| unique_libraries_list = [] |
| for entry in reversed(libraries): |
| library = re.sub('^\-l', '', entry) |
| @@ -1331,8 +1372,7 @@ def _GetMSVSAttributes(spec, config, config_type): |
| def _AddNormalizedSources(sources_set, sources_array): |
| - sources = [_NormalizedSource(s) for s in sources_array] |
| - sources_set.update(set(sources)) |
| + sources_set.update(_NormalizedSource(s) for s in sources_array) |
| def _PrepareListOfSources(spec, generator_flags, gyp_file): |
| @@ -1350,9 +1390,9 @@ def _PrepareListOfSources(spec, generator_flags, gyp_file): |
| A pair of (list of sources, list of excluded sources). |
| The sources will be relative to the gyp file. |
| """ |
| - sources = set() |
| + sources = OrderedSet() |
| _AddNormalizedSources(sources, spec.get('sources', [])) |
| - excluded_sources = set() |
| + excluded_sources = OrderedSet() |
| # Add in the gyp file. |
| if not generator_flags.get('standalone'): |
| sources.add(gyp_file) |
| @@ -1362,7 +1402,7 @@ def _PrepareListOfSources(spec, generator_flags, gyp_file): |
| inputs = a['inputs'] |
| inputs = [_NormalizedSource(i) for i in inputs] |
| # Add all inputs to sources and excluded sources. |
| - inputs = set(inputs) |
| + inputs = OrderedSet(inputs) |
| sources.update(inputs) |
| if not spec.get('msvs_external_builder'): |
| excluded_sources.update(inputs) |
| @@ -1391,7 +1431,7 @@ def _AdjustSourcesAndConvertToFilterHierarchy( |
| path of excluded IDL file) |
| """ |
| # Exclude excluded sources coming into the generator. |
| - excluded_sources.update(set(spec.get('sources_excluded', []))) |
| + excluded_sources.update(OrderedSet(spec.get('sources_excluded', []))) |
| # Add excluded sources into sources for good measure. |
| sources.update(excluded_sources) |
| # Convert to proper windows form. |
| @@ -1484,7 +1524,7 @@ def _GetExcludedFilesFromBuild(spec, excluded_sources, excluded_idl): |
| def _AddToolFilesToMSVS(p, spec): |
| # Add in tool files (rules). |
| - tool_files = set() |
| + tool_files = OrderedSet() |
| for _, config in spec['configurations'].iteritems(): |
| for f in config.get('msvs_tool_files', []): |
| tool_files.add(f) |
| @@ -3207,16 +3247,16 @@ def _GenerateActionsForMSBuild(spec, actions_to_add): |
| Returns: |
| A pair of (action specification, the sources handled by this action). |
| """ |
| - sources_handled_by_action = set() |
| + sources_handled_by_action = OrderedSet() |
| actions_spec = [] |
| for primary_input, actions in actions_to_add.iteritems(): |
| - inputs = set() |
| - outputs = set() |
| + inputs = OrderedSet() |
| + outputs = OrderedSet() |
| descriptions = [] |
| commands = [] |
| for action in actions: |
| - inputs.update(set(action['inputs'])) |
| - outputs.update(set(action['outputs'])) |
| + inputs.update(OrderedSet(action['inputs'])) |
| + outputs.update(OrderedSet(action['outputs'])) |
| descriptions.append(action['description']) |
| cmd = action['command'] |
| # For most actions, add 'call' so that actions that invoke batch files |