1342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch#!/usr/bin/env python 2342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch# Copyright 2015 The Chromium Authors. All rights reserved. 3342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch# Use of this source code is governed by a BSD-style license that can be 4342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch# found in the LICENSE file. 5342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch 6342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch"""Runs 'ld -shared' and generates a .TOC file that's untouched when unchanged. 7342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch 8342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen MurdochThis script exists to avoid using complex shell commands in 9342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochgcc_toolchain.gni's tool("solink"), in case the host running the compiler 10342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochdoes not have a POSIX-like shell (e.g. Windows). 11342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch""" 12342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch 13342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochimport argparse 14342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochimport os 15342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochimport re 16342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochimport subprocess 17342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochimport sys 18342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch 19342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch 20342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch# When running on a Windows host and using a toolchain whose tools are 21342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch# actually wrapper scripts (i.e. .bat files on Windows) rather than binary 22342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch# executables, the "command" to run has to be prefixed with this magic. 23342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch# The GN toolchain definitions take care of that for when GN/Ninja is 24342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch# running the tool directly. When that command is passed in to this 25342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch# script, it appears as a unitary string but needs to be split up so that 26342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch# just 'cmd' is the actual command given to Python's subprocess module. 27342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen MurdochBAT_PREFIX = 'cmd /c call ' 28342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch 29342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochdef CommandToRun(command): 30342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch if command[0].startswith(BAT_PREFIX): 31342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch command = command[0].split(None, 3) + command[1:] 32342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch return command 33342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch 34342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch 35342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochdef CollectSONAME(args): 36342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch """Replaces: readelf -d $sofile | grep SONAME""" 37342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch toc = '' 38342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch readelf = subprocess.Popen(CommandToRun([args.readelf, '-d', args.sofile]), 39342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch stdout=subprocess.PIPE, bufsize=-1) 40342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch for line in readelf.stdout: 41342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch if 'SONAME' in line: 42342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch toc += line 43342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch return readelf.wait(), toc 44342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch 45342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch 46342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochdef CollectDynSym(args): 47342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch """Replaces: nm --format=posix -g -D $sofile | cut -f1-2 -d' '""" 48342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch toc = '' 49342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch nm = subprocess.Popen(CommandToRun([ 50342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch args.nm, '--format=posix', '-g', '-D', args.sofile]), 51342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch stdout=subprocess.PIPE, bufsize=-1) 52342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch for line in nm.stdout: 53342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch toc += ' '.join(line.split(' ', 2)[:2]) + '\n' 54342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch return nm.wait(), toc 55342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch 56342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch 57342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochdef CollectTOC(args): 58342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch result, toc = CollectSONAME(args) 59342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch if result == 0: 60342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch result, dynsym = CollectDynSym(args) 61342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch toc += dynsym 62342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch return result, toc 63342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch 64342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch 65342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochdef UpdateTOC(tocfile, toc): 66342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch if os.path.exists(tocfile): 67342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch old_toc = open(tocfile, 'r').read() 68342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch else: 69342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch old_toc = None 70342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch if toc != old_toc: 71342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch open(tocfile, 'w').write(toc) 72342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch 73342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch 74342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochdef main(): 75342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch parser = argparse.ArgumentParser(description=__doc__) 76342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch parser.add_argument('--readelf', 77342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch required=True, 78342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch help='The readelf binary to run', 79342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch metavar='PATH') 80342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch parser.add_argument('--nm', 81342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch required=True, 82342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch help='The nm binary to run', 83342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch metavar='PATH') 84342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch parser.add_argument('--strip', 85342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch help='The strip binary to run', 86342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch metavar='PATH') 87342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch parser.add_argument('--sofile', 88342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch required=True, 89342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch help='Shared object file produced by linking command', 90342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch metavar='FILE') 91342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch parser.add_argument('--tocfile', 92342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch required=True, 93342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch help='Output table-of-contents file', 94342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch metavar='FILE') 95342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch parser.add_argument('--output', 96342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch required=True, 97342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch help='Final output shared object file', 98342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch metavar='FILE') 99342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch parser.add_argument('command', nargs='+', 100342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch help='Linking command') 101342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch args = parser.parse_args() 102342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch 103342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch # First, run the actual link. 104342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch result = subprocess.call(CommandToRun(args.command)) 105342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch if result != 0: 106342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch return result 107342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch 108342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch # Next, generate the contents of the TOC file. 109342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch result, toc = CollectTOC(args) 110342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch if result != 0: 111342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch return result 112342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch 113342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch # If there is an existing TOC file with identical contents, leave it alone. 114342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch # Otherwise, write out the TOC file. 115342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch UpdateTOC(args.tocfile, toc) 116342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch 117342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch # Finally, strip the linked shared object file (if desired). 118342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch if args.strip: 119342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch result = subprocess.call(CommandToRun([args.strip, '--strip-unneeded', 120342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch '-o', args.output, args.sofile])) 121342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch 122342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch return result 123342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch 124342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch 125342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochif __name__ == "__main__": 126342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch sys.exit(main()) 127