Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #!/usr/bin/env python | |
| 2 | |
| 3 # Copyright 2016 The Chromium Authors. All rights reserved. | |
| 4 # Use of this source code is governed by a BSD-style license that can be | |
| 5 # found in the LICENSE file. | |
| 6 | |
| 7 import os | |
| 8 import os.path | |
| 9 import shutil | |
| 10 import subprocess | |
| 11 import sys | |
| 12 | |
| 13 # The linker_driver.py is responsible for forwarding a linker invocation to | |
| 14 # the compiler driver, while processing special arguments itself. | |
| 15 # | |
| 16 # On Mac, the logical step of linking is handled by three discrete tools to | |
| 17 # perform the image link, debug info link, and strip. The linker_driver.py | |
| 18 # combines these three steps into a single tool. | |
| 19 # | |
| 20 # The command passed to the linker_driver.py is first invoked unaltered (except | |
| 21 # for the removal of the special driver arguments, described below). Then the | |
| 22 # driver performs additional actions, based on these arguments: | |
|
Mark Mentovai
2016/05/20 19:41:11
Specify (perhaps by implication if you provide a s
Robert Sesek
2016/05/24 15:05:33
Done.
| |
| 23 # | |
| 24 # -Wcrl,dsym,<dsym_path_prefix> | |
| 25 # After invoking the linker, this will run `dsymutil` on the linker's | |
| 26 # output, producing a dSYM bundle, stored at dsym_path_prefix. As an | |
| 27 # example, if the linker driver were invoked with: | |
| 28 # "... -o out/gn/obj/foo/libbar.dylib ... -Wcrl,dsym,out/gn/ ..." | |
|
Mark Mentovai
2016/05/20 19:41:11
If the trailing / isn’t necessary, don’t include i
Robert Sesek
2016/05/24 15:05:33
Done.
| |
| 29 # The resulting dSYM would be out/gn/libbar.dylib.dSYM/. | |
| 30 # | |
| 31 # -Wcrl,strip,<strip_arguments> | |
| 32 # After invoking the linker, and optionally dsymutil, this will run | |
| 33 # the strip command on the linker's output. strip_arguments are | |
| 34 # comma-separated arguments to be passed to the strip command. | |
| 35 | |
| 36 def Main(args): | |
| 37 """Main function for the linker driver. Separates out the arguments for | |
| 38 the main compiler driver and the linker driver, then invokes all the | |
| 39 required tools. | |
| 40 | |
| 41 Args: | |
| 42 args: list of string, Arguments to the script. | |
| 43 """ | |
| 44 | |
| 45 if len(args) < 2: | |
| 46 raise RuntimeError("Usage: linker_driver.py [linker-invocation]") | |
| 47 | |
| 48 # Collect arguments to the linker driver (this script) and remove them from | |
| 49 # the arguments being passed to the compiler driver. | |
| 50 linker_driver_actions = {} | |
| 51 compiler_driver_args = [] | |
| 52 for arg in args[1:]: | |
| 53 if arg.startswith(_LINKER_DRIVER_ARG_PREFIX): | |
| 54 # Convert driver actions into a map of name => lambda to invoke. | |
| 55 driver_action = ProcessLinkerDriverArg(arg) | |
| 56 linker_driver_actions[driver_action[0]] = driver_action[1] | |
|
Mark Mentovai
2016/05/20 19:41:11
assert (or raise if not) driver_action[0] in linke
Robert Sesek
2016/05/24 15:05:33
Done.
| |
| 57 else: | |
| 58 compiler_driver_args.append(arg) | |
| 59 | |
| 60 linker_driver_outputs = [_FindLinkerOutput(compiler_driver_args)] | |
| 61 | |
| 62 try: | |
| 63 # Run the linker by invoking the compiler driver. | |
| 64 subprocess.check_call(compiler_driver_args) | |
| 65 | |
| 66 # Run the linker driver actions, in the order specified by the actions list. | |
| 67 for action in _LINKER_DRIVER_ACTIONS: | |
| 68 name = action[0] | |
| 69 if name in linker_driver_actions: | |
| 70 linker_driver_outputs += linker_driver_actions[name](args) | |
|
Mark Mentovai
2016/05/20 19:41:11
I’m not going to force you to fix this because it’
Robert Sesek
2016/05/24 15:05:33
Acknowledged.
| |
| 71 except: | |
| 72 # If a linker driver action failed, remove all the outputs to make the | |
| 73 # build step atomic. | |
| 74 map(_RemovePath, linker_driver_outputs) | |
| 75 | |
| 76 # Re-report the original failure. | |
| 77 raise | |
| 78 | |
| 79 | |
| 80 def ProcessLinkerDriverArg(arg): | |
| 81 """Processes a linker driver argument and returns a tuple containing the | |
| 82 name and unary lambda to invoke for that linker driver action. | |
| 83 | |
| 84 Args: | |
| 85 arg: string, The linker driver argument. | |
| 86 | |
| 87 Returns: | |
| 88 A 2-tuple: | |
| 89 0: The driver action name, as in _LINKER_DRIVER_ACTIONS. | |
| 90 1: An 1-ary lambda that takes the full list of arguments passed to | |
| 91 Main(). The lambda should call the linker driver action that | |
| 92 corresponds to the argument. | |
|
Mark Mentovai
2016/05/20 19:41:11
and return blah blah blah
Robert Sesek
2016/05/24 15:05:33
Done.
| |
| 93 """ | |
| 94 if not arg.startswith(_LINKER_DRIVER_ARG_PREFIX): | |
| 95 raise ValueError('%s is not a linker driver argument' % (arg,)) | |
| 96 | |
| 97 sub_arg = arg[len(_LINKER_DRIVER_ARG_PREFIX):] | |
| 98 | |
| 99 for driver_action in _LINKER_DRIVER_ACTIONS: | |
| 100 (name, action) = driver_action | |
| 101 if sub_arg.startswith(name): | |
| 102 return (name, | |
| 103 lambda full_args: action(sub_arg[len(name):], full_args)) | |
| 104 | |
| 105 raise ValueError('Unknown linker driver argument: %s' % (arg,)) | |
| 106 | |
| 107 | |
| 108 def RunDsymUtil(dsym_path_prefix, full_args): | |
| 109 """Linker driver action for -Wcrl,dsym,<dsym-path-prefix>. Invokes dsymutil | |
| 110 on the linker's output and produces a dsym file at |dsym_file| path. | |
| 111 | |
| 112 Args: | |
| 113 dsym_path_prefix: string, The path at which the dsymutil output should be | |
| 114 located. | |
| 115 full_args: list of string, Full argument list for the linker driver. | |
| 116 | |
| 117 Returns: | |
| 118 list of string, Build step outputs. | |
| 119 """ | |
| 120 if not len(dsym_path_prefix): | |
| 121 raise ValueError('Unspecified dSYM output file') | |
| 122 | |
| 123 linker_out = _FindLinkerOutput(full_args) | |
| 124 (head, tail) = os.path.split(linker_out) | |
| 125 dsym_out = os.path.join(dsym_path_prefix, tail + '.dSYM') | |
| 126 | |
| 127 # Remove old dSYMs before invoking dsymutil. | |
| 128 _RemovePath(dsym_out) | |
| 129 subprocess.check_call(['xcrun', 'dsymutil', '-o', dsym_out, linker_out]) | |
| 130 return [dsym_out] | |
|
Mark Mentovai
2016/05/20 19:41:11
This and RunStrip can return a (tuple) instead of
Robert Sesek
2016/05/24 15:05:33
Returning tuple means having a (turd,). These seem
| |
| 131 | |
| 132 | |
| 133 def RunStrip(strip_args_string, full_args): | |
| 134 """Linker driver action for -Wcrl,strip,<strip_arguments>. | |
| 135 | |
| 136 Args: | |
| 137 strip_args_string: string, Comma-separated arguments for `strip`. | |
| 138 full_args: list of string, Full arguments for the linker driver. | |
| 139 | |
| 140 Returns: | |
| 141 list of string, Build step outputs. | |
| 142 """ | |
| 143 strip_args_list = strip_args_string.split(',') | |
|
Mark Mentovai
2016/05/20 19:41:11
If you get “-Wcrl,strip,”, then you want to run “s
Robert Sesek
2016/05/24 15:05:33
Done.
| |
| 144 strip_command = ['xcrun', 'strip'] + strip_args_list | |
| 145 strip_command.append(_FindLinkerOutput(full_args)) | |
| 146 subprocess.check_call(strip_command) | |
|
Mark Mentovai
2016/05/20 19:41:11
TODO(maybe?): swallow that bogus strip deprecation
Robert Sesek
2016/05/24 15:05:33
Gonna skip this for now.
| |
| 147 return [] | |
| 148 | |
| 149 | |
| 150 def _FindLinkerOutput(full_args): | |
| 151 """Finds the output of the linker by looking for the output flag in its | |
| 152 argument list. As this is a required linker argument, raises an error if it | |
| 153 cannot be found. | |
| 154 """ | |
| 155 for (i, arg) in enumerate(full_args): | |
|
Mark Mentovai
2016/05/20 19:41:11
Why not just this:
return full_args[full_args.ind
Robert Sesek
2016/05/24 15:05:33
Done.
| |
| 156 if arg == '-o': | |
| 157 return full_args[i+1] | |
| 158 raise RuntimeError('Unable to locate linker output file (no -o flag)') | |
| 159 | |
| 160 | |
| 161 def _RemovePath(path): | |
| 162 """Removes the file or directory at |path| if it exists.""" | |
| 163 if os.path.exists(path): | |
| 164 if os.path.isdir(path): | |
| 165 shutil.rmtree(path) | |
| 166 else: | |
| 167 os.unlink(path) | |
| 168 | |
| 169 | |
| 170 _LINKER_DRIVER_ARG_PREFIX = '-Wcrl,' | |
| 171 | |
| 172 """List of linker driver actions. The sort order of this list affects the | |
| 173 order in which the actions are invoked. The first item in the tuple is the | |
| 174 argument's -Wcrl,<sub_argument> and the second is the function to invoke. | |
| 175 """ | |
| 176 _LINKER_DRIVER_ACTIONS = [ | |
| 177 ('dsym,', RunDsymUtil), | |
| 178 ('strip,', RunStrip), | |
| 179 ] | |
| 180 | |
| 181 | |
| 182 if __name__ == '__main__': | |
| 183 Main(sys.argv) | |
| 184 sys.exit(0) | |
| OLD | NEW |