Chromium Code Reviews| Index: pylib/gyp/generator/ninja.py |
| diff --git a/pylib/gyp/generator/ninja.py b/pylib/gyp/generator/ninja.py |
| index b13affe0a172392ae115201874d5f44223b38c38..95aca57d3bdd188291a1f01bd9af3e48f09a4ad8 100644 |
| --- a/pylib/gyp/generator/ninja.py |
| +++ b/pylib/gyp/generator/ninja.py |
| @@ -69,6 +69,9 @@ def StripPrefix(arg, prefix): |
| return arg[len(prefix):] |
| return arg |
| +def OrderDeterministically(l, **kwargs): |
| + """ Sorts l so that it is ordered deterministically. """ |
| + return sorted(l, **kwargs) |
|
mithro-old
2015/12/10 03:15:27
I think this should be in gyp.common with OrderedS
Zachary Forman
2015/12/30 02:18:43
Yeah, you caught me mid refactor. Good spot for it
|
| def QuoteShellArgument(arg, flavor): |
| """Quote a string such that it will be interpreted as a single argument |
| @@ -421,10 +424,10 @@ class NinjaWriter(object): |
| compile_depends.append(target.PreCompileInput()) |
| actions_depends = filter(None, actions_depends) |
| compile_depends = filter(None, compile_depends) |
| - actions_depends = self.WriteCollapsedDependencies('actions_depends', |
| - actions_depends) |
| - compile_depends = self.WriteCollapsedDependencies('compile_depends', |
| - compile_depends) |
| + actions_depends = self.WriteCollapsedDependencies( |
| + 'actions_depends', OrderDeterministically(actions_depends)) |
| + compile_depends = self.WriteCollapsedDependencies( |
| + 'compile_depends', OrderDeterministically(compile_depends)) |
| self.target.preaction_stamp = actions_depends |
| self.target.precompile_stamp = compile_depends |
| @@ -559,7 +562,8 @@ class NinjaWriter(object): |
| if 'sources' in spec and self.flavor == 'win': |
| outputs += self.WriteWinIdlFiles(spec, prebuild) |
| - stamp = self.WriteCollapsedDependencies('actions_rules_copies', outputs) |
| + stamp = self.WriteCollapsedDependencies('actions_rules_copies', |
| + OrderDeterministically(outputs)) |
| if self.is_mac_bundle: |
| xcassets = self.WriteMacBundleResources( |
| @@ -657,6 +661,8 @@ class NinjaWriter(object): |
| if '${%s}' % var in argument: |
| needed_variables.add(var) |
| + needed_variables = OrderDeterministically(needed_variables) |
| + |
| def cygwin_munge(path): |
| # pylint: disable=cell-var-from-loop |
| if is_cygwin: |
| @@ -674,7 +680,7 @@ class NinjaWriter(object): |
| num_inputs += 1 |
| if num_inputs > 2 and len(sources) > 2: |
| inputs = [self.WriteCollapsedDependencies( |
| - rule['rule_name'], inputs, order_only=prebuild)] |
| + rule['rule_name'], OrderDeterministically(inputs), order_only=prebuild)] |
| prebuild = [] |
| # For each source file, write an edge that generates all the outputs. |
| @@ -729,6 +735,8 @@ class NinjaWriter(object): |
| # WriteNewNinjaRule uses unique_name for creating an rsp file on win. |
| extra_bindings.append(('unique_name', |
| hashlib.md5(outputs[0]).hexdigest())) |
| + |
| + # Make sure we sort extra_bindings so that output is deterministic. |
| self.ninja.build(outputs, rule_name, self.GypPathToNinja(source), |
| implicit=inputs, |
| order_only=prebuild, |
| @@ -1134,6 +1142,8 @@ class NinjaWriter(object): |
| if not linkable or final_output != target.binary: |
| implicit_deps.add(final_output) |
| + link_deps = OrderDeterministically(link_deps) |
| + |
| extra_bindings = [] |
| if self.uses_cpp and self.flavor != 'win': |
| extra_bindings.append(('ld', '$ldxx')) |
| @@ -1250,13 +1260,13 @@ class NinjaWriter(object): |
| if pdbname: |
| output = [output, pdbname] |
| - |
| if len(solibs): |
| - extra_bindings.append(('solibs', gyp.common.EncodePOSIXShellList(solibs))) |
| + extra_bindings.append(('solibs', |
| + gyp.common.EncodePOSIXShellList(OrderDeterministically(solibs)))) |
| ninja_file.build(output, command + command_suffix, link_deps, |
| - implicit=list(implicit_deps), |
| - order_only=list(order_deps), |
| + implicit=OrderDeterministically(implicit_deps), |
| + order_only=order_deps, |
| variables=extra_bindings) |
| return linked_binary |
| @@ -2337,9 +2347,10 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params, |
| # able to run actions and build libraries by their short name. |
| master_ninja.newline() |
| master_ninja.comment('Short names for targets.') |
| - for short_name in target_short_names: |
| - master_ninja.build(short_name, 'phony', [x.FinalOutput() for x in |
| - target_short_names[short_name]]) |
| + |
| + for short_name in OrderDeterministically(target_short_names): |
| + master_ninja.build(short_name, 'phony', ([x.FinalOutput() for x in |
| + target_short_names[short_name]])) |
| # Write phony targets for any empty targets that weren't written yet. As |
| # short names are not necessarily unique only do this for short names that |
| @@ -2348,12 +2359,14 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params, |
| if empty_target_names: |
| master_ninja.newline() |
| master_ninja.comment('Empty targets (output for completeness).') |
| - for name in sorted(empty_target_names): |
| + |
| + # Iterate over empty target names in a deterministic order by sorting. |
| + for name in OrderDeterministically(empty_target_names): |
| master_ninja.build(name, 'phony') |
| if all_outputs: |
| master_ninja.newline() |
| - master_ninja.build('all', 'phony', list(all_outputs)) |
| + master_ninja.build('all', 'phony', OrderDeterministically(all_outputs)) |
| master_ninja.default(generator_flags.get('default_target', 'all')) |
| master_ninja_file.close() |