Commit 081ead71 authored by Andrew Grieve's avatar Andrew Grieve Committed by Commit Bot

Android: Maintain original order of sibling deps within .build_configs

This reduces randomness in the build by making our dependency
sorting a stable sort.

Bug: 828528, 828508
Change-Id: Ibf0f1de0d77333cdee575560912728e47b8f292e
Reviewed-on: https://chromium-review.googlesource.com/994545
Commit-Queue: agrieve <agrieve@chromium.org>
Reviewed-by: default avatarSamuel Huang <huangs@chromium.org>
Cr-Commit-Position: refs/heads/master@{#548131}
parent a1179dbf
...@@ -58,6 +58,7 @@ def CommonChecks(input_api, output_api): ...@@ -58,6 +58,7 @@ def CommonChecks(input_api, output_api):
output_api, output_api,
unit_tests=[ unit_tests=[
J('.', 'emma_coverage_stats_test.py'), J('.', 'emma_coverage_stats_test.py'),
J('gyp', 'util', 'build_utils_test.py'),
J('gyp', 'util', 'md5_check_test.py'), J('gyp', 'util', 'md5_check_test.py'),
J('play_services', 'update_test.py'), J('play_services', 'update_test.py'),
J('pylib', 'gtest', 'gtest_test_instance_test.py'), J('pylib', 'gtest', 'gtest_test_instance_test.py'),
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
# found in the LICENSE file. # found in the LICENSE file.
import ast import ast
import collections
import contextlib import contextlib
import fnmatch import fnmatch
import json import json
...@@ -395,37 +396,28 @@ def PrintBigWarning(message): ...@@ -395,37 +396,28 @@ def PrintBigWarning(message):
def GetSortedTransitiveDependencies(top, deps_func): def GetSortedTransitiveDependencies(top, deps_func):
"""Gets the list of all transitive dependencies in sorted order. """Gets the list of all transitive dependencies in sorted order.
There should be no cycles in the dependency graph. There should be no cycles in the dependency graph (crashes if cycles exist).
Args: Args:
top: a list of the top level nodes top: A list of the top level nodes
deps_func: A function that takes a node and returns its direct dependencies. deps_func: A function that takes a node and returns a list of its direct
dependencies.
Returns: Returns:
A list of all transitive dependencies of nodes in top, in order (a node will A list of all transitive dependencies of nodes in top, in order (a node will
appear in the list at a higher index than all of its dependencies). appear in the list at a higher index than all of its dependencies).
""" """
def Node(dep): # Find all deps depth-first, maintaining original order in the case of ties.
return (dep, deps_func(dep)) deps_map = collections.OrderedDict()
def discover(nodes):
# First: find all deps for node in nodes:
unchecked_deps = list(top) if node in deps_map:
all_deps = set(top) continue
while unchecked_deps: deps = deps_func(node)
dep = unchecked_deps.pop() discover(deps)
new_deps = deps_func(dep).difference(all_deps) deps_map[node] = deps
unchecked_deps.extend(new_deps)
all_deps = all_deps.union(new_deps) discover(top)
return deps_map.keys()
# Then: simple, slow topological sort.
sorted_deps = []
unsorted_deps = dict(map(Node, all_deps))
while unsorted_deps:
for library, dependencies in unsorted_deps.items():
if not dependencies.intersection(unsorted_deps.keys()):
sorted_deps.append(library)
del unsorted_deps[library]
return sorted_deps
def GetPythonDependencies(): def GetPythonDependencies():
......
#!/usr/bin/env python
# Copyright 2018 The Chromium 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 collections
import unittest
import build_utils # pylint: disable=W0403
_DEPS = collections.OrderedDict()
_DEPS['a'] = []
_DEPS['b'] = []
_DEPS['c'] = ['a']
_DEPS['d'] = ['a']
_DEPS['e'] = ['f']
_DEPS['f'] = ['a', 'd']
_DEPS['g'] = []
_DEPS['h'] = ['d', 'b', 'f']
_DEPS['i'] = ['f']
class BuildUtilsTest(unittest.TestCase):
def testGetSortedTransitiveDependencies_all(self):
TOP = _DEPS.keys()
EXPECTED = ['a', 'b', 'c', 'd', 'f', 'e', 'g', 'h', 'i']
actual = build_utils.GetSortedTransitiveDependencies(TOP, _DEPS.get)
self.assertEqual(EXPECTED, actual)
def testGetSortedTransitiveDependencies_leaves(self):
TOP = ['c', 'e', 'g', 'h', 'i']
EXPECTED = ['a', 'c', 'd', 'f', 'e', 'g', 'b', 'h', 'i']
actual = build_utils.GetSortedTransitiveDependencies(TOP, _DEPS.get)
self.assertEqual(EXPECTED, actual)
def testGetSortedTransitiveDependencies_leavesReverse(self):
TOP = ['i', 'h', 'g', 'e', 'c']
EXPECTED = ['a', 'd', 'f', 'i', 'b', 'h', 'g', 'e', 'c']
actual = build_utils.GetSortedTransitiveDependencies(TOP, _DEPS.get)
self.assertEqual(EXPECTED, actual)
if __name__ == '__main__':
unittest.main()
...@@ -562,7 +562,7 @@ def DepsOfType(wanted_type, configs): ...@@ -562,7 +562,7 @@ def DepsOfType(wanted_type, configs):
def GetAllDepsConfigsInOrder(deps_config_paths): def GetAllDepsConfigsInOrder(deps_config_paths):
def GetDeps(path): def GetDeps(path):
return set(GetDepConfig(path)['deps_configs']) return GetDepConfig(path)['deps_configs']
return build_utils.GetSortedTransitiveDependencies(deps_config_paths, GetDeps) return build_utils.GetSortedTransitiveDependencies(deps_config_paths, GetDeps)
......
...@@ -48,11 +48,11 @@ def CallReadElf(library_or_executable): ...@@ -48,11 +48,11 @@ def CallReadElf(library_or_executable):
def GetDependencies(library_or_executable): def GetDependencies(library_or_executable):
elf = CallReadElf(library_or_executable) elf = CallReadElf(library_or_executable)
deps = set() deps = []
for l in _library_re.findall(elf): for l in _library_re.findall(elf):
p = _library_path_map.get(l) p = _library_path_map.get(l)
if p is not None: if p is not None:
deps.add(p) deps.append(p)
return deps return deps
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment