blob: 7dc3962933df5f1fd83cfa24cfac9c77390261bb [file] [log] [blame]
#!/usr/bin/env python
# Copyright 2014 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.
#
# Tool to make a table of contents file of a shared library in a build rule.
# The output file contains the list of all external symbols of the shared
# library. So dependants that is linked dynamically to the shared library
# needs to be relink only when the contents of the output file is modified.
#
# This script updates the timestamp of the output file only when its content
# is updated. So that the build system can stop re-building a dependant that is
# dynamically linked to the shared library.
#
import errno
import subprocess
import sys
from build_options import OPTIONS
import toolchain
from util import file_util
def make_table_of_contents(target, input_so_path):
# List only external dynamic symbol as implied by '-g' and '-D'.
# Use posix format of output that implied by '-f','p' as it is easiest to
# parse for our usage.
external_symbols = subprocess.check_output([
toolchain.get_tool(target, 'nm'), '-gD', '-f', 'p', input_so_path
])
symbols = []
for line in external_symbols.splitlines():
# |line| should contain:
# <symbol name> <symbol type> <address>
# Put symbol names and symbol types into the TOC file.
# Drop address part since its modification does not require relinking for
# binaries that are dynamically linked agaist |input_so_path|.
symbols.append(' '.join(line.split(' ')[:2]))
return '\n'.join(symbols)
def should_update_toc_file(toc, output_toc_path):
"""Returns True if |output_toc_path| needs to be updated with |toc|."""
# Update |output_toc_path| unless |output_toc_path| exists and its content is
# exactly the same as |toc|.
try:
with open(output_toc_path, 'r') as f:
return f.read() != toc
except IOError as (error, _):
# The output file is not found. The output file should be created in this
# case, since this is the first invocation of the script after the shared
# library is created.
if error == errno.ENOENT:
return True
raise
def main(args):
OPTIONS.parse_configure_file()
if len(args) != 3:
return -1
target = args[0]
input_so_path = args[1]
output_toc_path = args[2]
toc = make_table_of_contents(target, input_so_path)
if should_update_toc_file(toc, output_toc_path):
file_util.write_atomically(output_toc_path, toc)
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))