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):
output_api,
unit_tests=[
J('.', 'emma_coverage_stats_test.py'),
J('gyp', 'util', 'build_utils_test.py'),
J('gyp', 'util', 'md5_check_test.py'),
J('play_services', 'update_test.py'),
J('pylib', 'gtest', 'gtest_test_instance_test.py'),
......
......@@ -3,6 +3,7 @@
# found in the LICENSE file.
import ast
import collections
import contextlib
import fnmatch
import json
......@@ -395,37 +396,28 @@ def PrintBigWarning(message):
def GetSortedTransitiveDependencies(top, deps_func):
"""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:
top: a list of the top level nodes
deps_func: A function that takes a node and returns its direct dependencies.
top: A list of the top level nodes
deps_func: A function that takes a node and returns a list of its direct
dependencies.
Returns:
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).
"""
def Node(dep):
return (dep, deps_func(dep))
# First: find all deps
unchecked_deps = list(top)
all_deps = set(top)
while unchecked_deps:
dep = unchecked_deps.pop()
new_deps = deps_func(dep).difference(all_deps)
unchecked_deps.extend(new_deps)
all_deps = all_deps.union(new_deps)
# 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
# Find all deps depth-first, maintaining original order in the case of ties.
deps_map = collections.OrderedDict()
def discover(nodes):
for node in nodes:
if node in deps_map:
continue
deps = deps_func(node)
discover(deps)
deps_map[node] = deps
discover(top)
return deps_map.keys()
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):
def GetAllDepsConfigsInOrder(deps_config_paths):
def GetDeps(path):
return set(GetDepConfig(path)['deps_configs'])
return GetDepConfig(path)['deps_configs']
return build_utils.GetSortedTransitiveDependencies(deps_config_paths, GetDeps)
......
......@@ -48,11 +48,11 @@ def CallReadElf(library_or_executable):
def GetDependencies(library_or_executable):
elf = CallReadElf(library_or_executable)
deps = set()
deps = []
for l in _library_re.findall(elf):
p = _library_path_map.get(l)
if p is not None:
deps.add(p)
deps.append(p)
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