Better error message for multiple defined symbols.
Test: nose2
Test: m ndk
Bug: http://b/116629622
Change-Id: I30719eaf29d63d8c6595bbab4e5214a1ce6189ca
diff --git a/cc/gen_stub_libs.py b/cc/gen_stub_libs.py
index 32765a7..c49d197 100755
--- a/cc/gen_stub_libs.py
+++ b/cc/gen_stub_libs.py
@@ -20,6 +20,7 @@
import logging
import os
import re
+import sys
ALL_ARCHITECTURES = (
@@ -107,22 +108,33 @@
return version.endswith('_PRIVATE') or version.endswith('_PLATFORM')
-def should_omit_version(name, tags, arch, api, vndk):
+def should_omit_version(version, arch, api, vndk):
"""Returns True if the version section should be ommitted.
We want to omit any sections that do not have any symbols we'll have in the
stub library. Sections that contain entirely future symbols or only symbols
for certain architectures.
"""
- if version_is_private(name):
+ if version_is_private(version.name):
return True
- if 'platform-only' in tags:
+ if 'platform-only' in version.tags:
return True
- if 'vndk' in tags and not vndk:
+ if 'vndk' in version.tags and not vndk:
return True
- if not symbol_in_arch(tags, arch):
+ if not symbol_in_arch(version.tags, arch):
return True
- if not symbol_in_api(tags, arch, api):
+ if not symbol_in_api(version.tags, arch, api):
+ return True
+ return False
+
+
+def should_omit_symbol(symbol, arch, api, vndk):
+ """Returns True if the symbol should be omitted."""
+ if not vndk and 'vndk' in symbol.tags:
+ return True
+ if not symbol_in_arch(symbol.tags, arch):
+ return True
+ if not symbol_in_api(symbol.tags, arch, api):
return True
return False
@@ -189,6 +201,15 @@
pass
+class MultiplyDefinedSymbolError(RuntimeError):
+ """A symbol name was multiply defined."""
+ def __init__(self, multiply_defined_symbols):
+ super(MultiplyDefinedSymbolError, self).__init__(
+ 'Version script contains multiple definitions for: {}'.format(
+ ', '.join(multiply_defined_symbols)))
+ self.multiply_defined_symbols = multiply_defined_symbols
+
+
class Version(object):
"""A version block of a symbol file."""
def __init__(self, name, base, tags, symbols):
@@ -221,9 +242,12 @@
class SymbolFileParser(object):
"""Parses NDK symbol files."""
- def __init__(self, input_file, api_map):
+ def __init__(self, input_file, api_map, arch, api, vndk):
self.input_file = input_file
self.api_map = api_map
+ self.arch = arch
+ self.api = api
+ self.vndk = vndk
self.current_line = None
def parse(self):
@@ -235,8 +259,36 @@
else:
raise ParseError(
'Unexpected contents at top level: ' + self.current_line)
+
+ self.check_no_duplicate_symbols(versions)
return versions
+ def check_no_duplicate_symbols(self, versions):
+ """Raises errors for multiply defined symbols.
+
+ This situation is the normal case when symbol versioning is actually
+ used, but this script doesn't currently handle that. The error message
+ will be a not necessarily obvious "error: redefition of 'foo'" from
+ stub.c, so it's better for us to catch this situation and raise a
+ better error.
+ """
+ symbol_names = set()
+ multiply_defined_symbols = set()
+ for version in versions:
+ if should_omit_version(version, self.arch, self.api, self.vndk):
+ continue
+
+ for symbol in version.symbols:
+ if should_omit_symbol(symbol, self.arch, self.api, self.vndk):
+ continue
+
+ if symbol.name in symbol_names:
+ multiply_defined_symbols.add(symbol.name)
+ symbol_names.add(symbol.name)
+ if multiply_defined_symbols:
+ raise MultiplyDefinedSymbolError(
+ sorted(list(multiply_defined_symbols)))
+
def parse_version(self):
"""Parses a single version section and returns a Version object."""
name = self.current_line.split('{')[0].strip()
@@ -325,20 +377,14 @@
def write_version(self, version):
"""Writes a single version block's data to the output files."""
- name = version.name
- tags = version.tags
- if should_omit_version(name, tags, self.arch, self.api, self.vndk):
+ if should_omit_version(version, self.arch, self.api, self.vndk):
return
- section_versioned = symbol_versioned_in_api(tags, self.api)
+ section_versioned = symbol_versioned_in_api(version.tags, self.api)
version_empty = True
pruned_symbols = []
for symbol in version.symbols:
- if not self.vndk and 'vndk' in symbol.tags:
- continue
- if not symbol_in_arch(symbol.tags, self.arch):
- continue
- if not symbol_in_api(symbol.tags, self.arch, self.api):
+ if should_omit_symbol(symbol, self.arch, self.api, self.vndk):
continue
if symbol_versioned_in_api(symbol.tags, self.api):
@@ -433,7 +479,11 @@
logging.basicConfig(level=verbose_map[verbosity])
with open(args.symbol_file) as symbol_file:
- versions = SymbolFileParser(symbol_file, api_map).parse()
+ try:
+ versions = SymbolFileParser(symbol_file, api_map, args.arch, api,
+ args.vndk).parse()
+ except MultiplyDefinedSymbolError as ex:
+ sys.exit('{}: error: {}'.format(args.symbol_file, ex))
with open(args.stub_src, 'w') as src_file:
with open(args.version_script, 'w') as version_file: