From de6e9c18e3a4ee418cff8338400668f9b6b7cf3e Mon Sep 17 00:00:00 2001 From: Andrew Morrow Date: Thu, 23 Apr 2020 15:04:37 -0400 Subject: SERVER-47721 Make generated ninja file deterministic --- site_scons/site_tools/ninja_next.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) (limited to 'site_scons/site_tools/ninja_next.py') diff --git a/site_scons/site_tools/ninja_next.py b/site_scons/site_tools/ninja_next.py index 9f38562e8ed..ca733abf449 100644 --- a/site_scons/site_tools/ninja_next.py +++ b/site_scons/site_tools/ninja_next.py @@ -167,6 +167,7 @@ def get_outputs(node): outputs = [node] outputs = [get_path(o) for o in outputs] + return outputs @@ -354,7 +355,7 @@ class NinjaState: self.generated_suffixes = env.get("NINJA_GENERATED_SOURCE_SUFFIXES", []) # List of generated builds that will be written at a later stage - self.builds = list() + self.builds = dict() # List of targets for which we have generated a build. This # allows us to take multiple Alias nodes as sources and to not @@ -515,7 +516,10 @@ class NinjaState: if build is None: return False - self.builds.append(build) + node_string = str(node) + if node_string in self.builds: + raise Exception("Node {} added to ninja build state more than once".format(node_string)) + self.builds[node_string] = build self.built.update(build["outputs"]) return True @@ -560,10 +564,10 @@ class NinjaState: for rule, kwargs in self.rules.items(): ninja.rule(rule, **kwargs) - generated_source_files = { + generated_source_files = sorted({ output # First find builds which have header files in their outputs. - for build in self.builds + for build in self.builds.values() if self.has_generated_sources(build["outputs"]) for output in build["outputs"] # Collect only the header files from the builds with them @@ -572,25 +576,25 @@ class NinjaState: # here we need to filter so we only have the headers and # not the other outputs. if self.is_generated_source(output) - } + }) if generated_source_files: ninja.build( outputs="_generated_sources", rule="phony", - implicit=list(generated_source_files), + implicit=generated_source_files ) template_builders = [] - for build in self.builds: + for build in [self.builds[key] for key in sorted(self.builds.keys())]: if build["rule"] == "TEMPLATE": template_builders.append(build) continue implicit = build.get("implicit", []) implicit.append(ninja_file) - build["implicit"] = implicit + build["implicit"] = sorted(implicit) # Don't make generated sources depend on each other. We # have to check that none of the outputs are generated @@ -613,6 +617,8 @@ class NinjaState: order_only = build.get("order_only", []) order_only.append("_generated_sources") build["order_only"] = order_only + if "order_only" in build: + build["order_only"].sort() # When using a depfile Ninja can only have a single output # but SCons will usually have emitted an output for every @@ -636,6 +642,7 @@ class NinjaState: # use for the "real" builder and multiple phony targets that # match the file names of the remaining outputs. This way any # build can depend on any output from any build. + build["outputs"].sort() if rule is not None and (rule.get("deps") or rule.get("rspfile")): first_output, remaining_outputs = ( build["outputs"][0], @@ -649,6 +656,9 @@ class NinjaState: build["outputs"] = first_output + if "inputs" in build: + build["inputs"].sort() + ninja.build(**build) template_builds = dict() -- cgit v1.2.1