Commit b7be8f9f authored by Christopher Grant's avatar Christopher Grant Committed by Commit Bot

SuperSize: Make ninja parser tolerate rules with no explicit input

Some build rules have a rulename and implicit inputs, but no explicit
inputs. For example:

build libfoo.so: __chrome_android_some_rule | lib_maker.py

Also:

- Add unit tests for the core parser functionality.
- Add a run_tests helper script for quick verification.

Bug: 982334
Change-Id: I7481018ae4ae4ce1bc71a19e73dc241b124bfb6d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1715606
Commit-Queue: Christopher Grant <cjgrant@chromium.org>
Reviewed-by: default avatarSamuel Huang <huangs@chromium.org>
Reviewed-by: default avatarAndrew Grieve <agrieve@chromium.org>
Cr-Commit-Position: refs/heads/master@{#680146}
parent dac521e2
...@@ -16,7 +16,8 @@ import re ...@@ -16,7 +16,8 @@ import re
# build obj/.../foo.o: cxx gen/.../foo.cc || obj/.../foo.inputdeps.stamp # build obj/.../foo.o: cxx gen/.../foo.cc || obj/.../foo.inputdeps.stamp
# build obj/.../libfoo.a: alink obj/.../a.o obj/.../b.o | # build obj/.../libfoo.a: alink obj/.../a.o obj/.../b.o |
# build ./libchrome.so ./lib.unstripped/libchrome.so: solink a.o b.o ... # build ./libchrome.so ./lib.unstripped/libchrome.so: solink a.o b.o ...
_REGEX = re.compile(r'build ([^:]+): \w+ (.*?)(?: \||\n|$)') # build libmonochrome.so: __chrome_android_libmonochrome___rule | ...
_REGEX = re.compile(r'build ([^:]+): \w+ (.*?)(?: *\||\n|$)')
class _SourceMapper(object): class _SourceMapper(object):
...@@ -65,7 +66,7 @@ class _SourceMapper(object): ...@@ -65,7 +66,7 @@ class _SourceMapper(object):
def _ParseNinjaPathList(path_list): def _ParseNinjaPathList(path_list):
ret = path_list.replace('\\ ', '\b') ret = path_list.replace('\\ ', '\b')
return [s.replace('\b', ' ') for s in ret.split(' ')] return [s.replace('\b', ' ') for s in ret.split()]
def _ParseOneFile(lines, dep_map, elf_path): def _ParseOneFile(lines, dep_map, elf_path):
...@@ -94,6 +95,10 @@ def _ParseOneFile(lines, dep_map, elf_path): ...@@ -94,6 +95,10 @@ def _ParseOneFile(lines, dep_map, elf_path):
return sub_ninjas, elf_inputs return sub_ninjas, elf_inputs
def ParseOneFileForTest(lines, dep_map, elf_path):
return _ParseOneFile(lines, dep_map, elf_path)
def Parse(output_directory, elf_path): def Parse(output_directory, elf_path):
"""Parses build.ninja and subninjas. """Parses build.ninja and subninjas.
......
#!/usr/bin/env python
# Copyright 2019 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 unittest
import ninja_parser
class NinjaParserTest(unittest.TestCase):
def _ParseOneFile(self, line, lib, expected_inputs, expected_dep_map):
"""Exercises ninja_parser's ParseOneFile method.
This allows coverage of most parsing capabilities, without having to
synthesize the actual Ninja files expected by the top-level Parse()
method.
"""
dep_map = {}
_, found_inputs = ninja_parser.ParseOneFileForTest([line], dep_map, lib)
self.assertEqual(expected_inputs, found_inputs)
self.assertEqual(expected_dep_map, dep_map)
# These cases cover finding ELF outputs with associated inputs:
def test_ExplicitDep(self):
line = 'build libfoo.so: link a.o'
inputs = ['a.o']
self._ParseOneFile(line, 'libfoo.so', inputs, {})
def test_MultipleExplicitDeps(self):
line = 'build libfoo.so: link a.o b.o'
inputs = ['a.o', 'b.o']
self._ParseOneFile(line, 'libfoo.so', inputs, {})
def test_ExplicitDepWithImplicitDep(self):
line = 'build libfoo.so: link a.o | b.o'
inputs = ['a.o']
self._ParseOneFile(line, 'libfoo.so', inputs, {})
def test_ExplicitDepWithOrderDep(self):
line = 'build libfoo.so: link a.o || b.o'
inputs = ['a.o']
self._ParseOneFile(line, 'libfoo.so', inputs, {})
def test_NoExplicitInput(self):
line = 'build libfoo.so: custom_link | custom.py'
inputs = []
self._ParseOneFile(line, 'libfoo.so', inputs, {})
def test_SpacesInPaths(self):
line = 'build libfoo.so: link a\ a.o b\ b.o'
inputs = ['a a.o', 'b b.o']
self._ParseOneFile(line, 'libfoo.so', inputs, {})
# These cases cover Object file outputs that update a dependency map:
def test_ObjectOutputWithExplicitDep(self):
line = 'build libfoo.o: cxx a.cc'
dep_map = {'libfoo.o': 'a.cc'}
self._ParseOneFile(line, 'libfoo.o', None, dep_map)
def test_ObjectOutputWithExplicitDeps(self):
line = 'build libfoo.o: cxx a.cc b.cc'
dep_map = {'libfoo.o': 'a.cc b.cc'}
self._ParseOneFile(line, 'libfoo.o', None, dep_map)
def test_ObjectOutputWithOrderDep(self):
line = 'build libfoo.o: cxx a.cc || a.inputdeps.stamp'
dep_map = {'libfoo.o': 'a.cc'}
self._ParseOneFile(line, 'libfoo.o', None, dep_map)
def test_ObjectOutputWithExplicitDepsAndOrderDep(self):
line = 'build libfoo.o: cxx a.cc b.cc || a.inputdeps.stamp'
dep_map = {'libfoo.o': 'a.cc b.cc'}
self._ParseOneFile(line, 'libfoo.o', None, dep_map)
if __name__ == '__main__':
unittest.main()
#!/usr/bin/env vpython
# Copyright 2019 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 logging
import os
import sys
import unittest
if __name__ == '__main__':
logging.basicConfig(
level=logging.DEBUG if '-v' in sys.argv else logging.WARNING,
format='%(levelname)5s %(filename)15s(%(lineno)3d): %(message)s')
suite = unittest.TestSuite()
loader = unittest.TestLoader()
suite.addTests(
loader.discover(start_dir=os.path.dirname(__file__), pattern='*_test.py'))
res = unittest.TextTestRunner(verbosity=2).run(suite)
if res.wasSuccessful():
sys.exit(0)
else:
sys.exit(1)
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