OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2015 The Chromium Authors. All rights reserved. | 2 # Copyright 2015 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Runs 'ld -shared' and generates a .TOC file that's untouched when unchanged. | 6 """Runs 'ld -shared' and generates a .TOC file that's untouched when unchanged. |
7 | 7 |
8 This script exists to avoid using complex shell commands in | 8 This script exists to avoid using complex shell commands in |
9 gcc_toolchain.gni's tool("solink"), in case the host running the compiler | 9 gcc_toolchain.gni's tool("solink"), in case the host running the compiler |
10 does not have a POSIX-like shell (e.g. Windows). | 10 does not have a POSIX-like shell (e.g. Windows). |
11 """ | 11 """ |
12 | 12 |
13 import argparse | 13 import argparse |
14 import os | 14 import os |
| 15 import re |
15 import subprocess | 16 import subprocess |
16 import sys | 17 import sys |
17 | 18 |
18 import wrapper_utils | 19 |
| 20 # When running on a Windows host and using a toolchain whose tools are |
| 21 # actually wrapper scripts (i.e. .bat files on Windows) rather than binary |
| 22 # executables, the "command" to run has to be prefixed with this magic. |
| 23 # The GN toolchain definitions take care of that for when GN/Ninja is |
| 24 # running the tool directly. When that command is passed in to this |
| 25 # script, it appears as a unitary string but needs to be split up so that |
| 26 # just 'cmd' is the actual command given to Python's subprocess module. |
| 27 BAT_PREFIX = 'cmd /c call ' |
| 28 |
| 29 def CommandToRun(command): |
| 30 if command[0].startswith(BAT_PREFIX): |
| 31 command = command[0].split(None, 3) + command[1:] |
| 32 return command |
19 | 33 |
20 | 34 |
21 def CollectSONAME(args): | 35 def CollectSONAME(args): |
22 """Replaces: readelf -d $sofile | grep SONAME""" | 36 """Replaces: readelf -d $sofile | grep SONAME""" |
23 toc = '' | 37 toc = '' |
24 readelf = subprocess.Popen(wrapper_utils.CommandToRun( | 38 readelf = subprocess.Popen(CommandToRun([args.readelf, '-d', args.sofile]), |
25 [args.readelf, '-d', args.sofile]), stdout=subprocess.PIPE, bufsize=-1) | 39 stdout=subprocess.PIPE, bufsize=-1) |
26 for line in readelf.stdout: | 40 for line in readelf.stdout: |
27 if 'SONAME' in line: | 41 if 'SONAME' in line: |
28 toc += line | 42 toc += line |
29 return readelf.wait(), toc | 43 return readelf.wait(), toc |
30 | 44 |
31 | 45 |
32 def CollectDynSym(args): | 46 def CollectDynSym(args): |
33 """Replaces: nm --format=posix -g -D $sofile | cut -f1-2 -d' '""" | 47 """Replaces: nm --format=posix -g -D $sofile | cut -f1-2 -d' '""" |
34 toc = '' | 48 toc = '' |
35 nm = subprocess.Popen(wrapper_utils.CommandToRun([ | 49 nm = subprocess.Popen(CommandToRun([ |
36 args.nm, '--format=posix', '-g', '-D', args.sofile]), | 50 args.nm, '--format=posix', '-g', '-D', args.sofile]), |
37 stdout=subprocess.PIPE, bufsize=-1) | 51 stdout=subprocess.PIPE, bufsize=-1) |
38 for line in nm.stdout: | 52 for line in nm.stdout: |
39 toc += ' '.join(line.split(' ', 2)[:2]) + '\n' | 53 toc += ' '.join(line.split(' ', 2)[:2]) + '\n' |
40 return nm.wait(), toc | 54 return nm.wait(), toc |
41 | 55 |
42 | 56 |
43 def CollectTOC(args): | 57 def CollectTOC(args): |
44 result, toc = CollectSONAME(args) | 58 result, toc = CollectSONAME(args) |
45 if result == 0: | 59 if result == 0: |
(...skipping 29 matching lines...) Expand all Loading... |
75 help='Shared object file produced by linking command', | 89 help='Shared object file produced by linking command', |
76 metavar='FILE') | 90 metavar='FILE') |
77 parser.add_argument('--tocfile', | 91 parser.add_argument('--tocfile', |
78 required=True, | 92 required=True, |
79 help='Output table-of-contents file', | 93 help='Output table-of-contents file', |
80 metavar='FILE') | 94 metavar='FILE') |
81 parser.add_argument('--output', | 95 parser.add_argument('--output', |
82 required=True, | 96 required=True, |
83 help='Final output shared object file', | 97 help='Final output shared object file', |
84 metavar='FILE') | 98 metavar='FILE') |
85 parser.add_argument('--resource-whitelist', | |
86 help='Merge all resource whitelists into a single file.', | |
87 metavar='PATH') | |
88 parser.add_argument('command', nargs='+', | 99 parser.add_argument('command', nargs='+', |
89 help='Linking command') | 100 help='Linking command') |
90 args = parser.parse_args() | 101 args = parser.parse_args() |
91 | 102 |
92 # Work-around for gold being slow-by-default. http://crbug.com/632230 | 103 # Work-around for gold being slow-by-default. http://crbug.com/632230 |
93 fast_env = dict(os.environ) | 104 fast_env = dict(os.environ) |
94 fast_env['LC_ALL'] = 'C' | 105 fast_env['LC_ALL'] = 'C' |
95 | 106 |
96 if args.resource_whitelist: | |
97 whitelist_candidates = wrapper_utils.ResolveRspLinks(args.command) | |
98 wrapper_utils.CombineResourceWhitelists( | |
99 whitelist_candidates, args.resource_whitelist) | |
100 | |
101 # First, run the actual link. | 107 # First, run the actual link. |
102 result = subprocess.call( | 108 result = subprocess.call(CommandToRun(args.command), env=fast_env) |
103 wrapper_utils.CommandToRun(args.command), env=fast_env) | |
104 if result != 0: | 109 if result != 0: |
105 return result | 110 return result |
106 | 111 |
107 # Next, generate the contents of the TOC file. | 112 # Next, generate the contents of the TOC file. |
108 result, toc = CollectTOC(args) | 113 result, toc = CollectTOC(args) |
109 if result != 0: | 114 if result != 0: |
110 return result | 115 return result |
111 | 116 |
112 # If there is an existing TOC file with identical contents, leave it alone. | 117 # If there is an existing TOC file with identical contents, leave it alone. |
113 # Otherwise, write out the TOC file. | 118 # Otherwise, write out the TOC file. |
114 UpdateTOC(args.tocfile, toc) | 119 UpdateTOC(args.tocfile, toc) |
115 | 120 |
116 # Finally, strip the linked shared object file (if desired). | 121 # Finally, strip the linked shared object file (if desired). |
117 if args.strip: | 122 if args.strip: |
118 result = subprocess.call(wrapper_utils.CommandToRun( | 123 result = subprocess.call(CommandToRun([args.strip, '--strip-unneeded', |
119 [args.strip, '--strip-unneeded', '-o', args.output, args.sofile])) | 124 '-o', args.output, args.sofile])) |
120 | 125 |
121 return result | 126 return result |
122 | 127 |
123 | 128 |
124 if __name__ == "__main__": | 129 if __name__ == "__main__": |
125 sys.exit(main()) | 130 sys.exit(main()) |
OLD | NEW |