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 subprocess | |
10 import sys | |
11 | |
12 # The linker_driver.py is responsible for forwarding a linker invocation to | |
13 # the compiler driver, while processing special arguments itself. | |
14 # | |
15 # On Mac, the logical step of linking is handled by three discrete tools to | |
16 # perform the image link, debug info link, and strip. The linker_driver.py | |
17 # combines these three steps into a single tool. | |
Mark Mentovai
2016/05/20 15:42:41
Ask Nico whether there’s any chance of adding thes
Robert Sesek
2016/05/20 19:09:55
Acknowledged. Per offline chat, clang, when drivin
| |
18 # | |
19 # The invocation of the linker_driver.py is first passed unaltered, except for | |
20 # the removal of the special driver arguments, described below. The driver | |
21 # arguments control what other steps occur after the image link. | |
22 # | |
23 # -Wcrl,dsym,<dsym_path_prefix> | |
24 # After invoking the linker, this will run `dsymutil` on the linker's | |
25 # output, producing a dSYM bundle, stored at dsym_path_prefix. | |
Mark Mentovai
2016/05/20 15:42:41
dsym_path_prefix is a directory, and the name + .d
Robert Sesek
2016/05/20 19:09:55
Done.
| |
26 # | |
27 # -Wcrl,strip,<strip_arguments> | |
28 # After invoking the linker, and optionally dsymutil, this will run | |
29 # the strip command on the linker's output. strip_arguments are | |
30 # comma-separated arguments to be passed to the strip command. | |
31 | |
32 _LINKER_DRIVER_ARG_PREFIX = '-Wcrl,' | |
33 | |
34 def Main(args): | |
35 """Main function for the linker driver. Separates out the arguments for | |
36 the main compiler driver and the linker driver, then invokes all the | |
37 required tools. | |
38 | |
39 Args: | |
40 args: list of string, Arguments to the script. | |
41 """ | |
42 | |
43 if len(args) < 2: | |
44 raise RuntimeError("Usage: linker_driver.py [linker-invocation]") | |
45 | |
46 # Collect arguments to the linker driver (this script) and remove them from | |
47 # the arguments being passed to the compiler driver. | |
48 linker_driver_actions = {} | |
49 compiler_driver_args = [] | |
50 for arg in args[1:]: | |
51 if arg.startswith(_LINKER_DRIVER_ARG_PREFIX): | |
52 # Convert driver actions into a map of name => lambda to invoke. | |
53 driver_action = ProcessLinkerDriverArg(arg) | |
54 linker_driver_actions[driver_action[0]] = driver_action[1] | |
55 else: | |
56 compiler_driver_args.append(arg) | |
57 | |
58 # Run the linker by invoking the compiler driver. | |
59 subprocess.check_call(compiler_driver_args) | |
60 | |
61 # Run the linker driver actions, in the order specified by the actions list. | |
62 for action in _LINKER_DRIVER_ACTIONS: | |
Dirk Pranke
2016/05/20 01:47:19
this should probably be wrapped in a try: ... fina
Robert Sesek
2016/05/20 15:15:36
Done.
| |
63 name = action[0] | |
64 if name in linker_driver_actions: | |
65 linker_driver_actions[name](args) | |
66 | |
67 | |
68 def ProcessLinkerDriverArg(arg): | |
69 """Processes a linker driver argument and returns a tuple containing the | |
70 name and unary lambda to invoke for that linker driver action. | |
71 | |
72 Args: | |
73 arg: string, The linker driver argument. | |
74 | |
75 Returns: | |
76 A 2-tuple: | |
77 0: The driver action name, as in _LINKER_DRIVER_ACTIONS. | |
78 1: An 1-ary lambda that takes the full list of arguments passed to | |
79 Main(). The lambda should call the linker driver action that | |
80 corresponds to the argument. | |
81 """ | |
82 if not arg.startswith(_LINKER_DRIVER_ARG_PREFIX): | |
83 raise ValueError('%s is not a linker driver argument' % (arg,)) | |
84 | |
85 sub_arg = arg[len(_LINKER_DRIVER_ARG_PREFIX):] | |
86 | |
87 for driver_action in _LINKER_DRIVER_ACTIONS: | |
88 (name, action) = driver_action | |
89 if sub_arg.startswith(name): | |
90 return (name, | |
91 lambda full_args: action(sub_arg[len(name):], full_args)) | |
92 | |
93 raise ValueError('Unknown linker driver argument: %s' % (arg,)) | |
94 | |
95 | |
96 def RunDsymUtil(dsym_path_prefix, full_args): | |
97 """Linker driver action for -Wcrl,dsym,<dsym-path-prefix>. Invokes dsymutil | |
98 on the linker's output and produces a dsym file at |dsym_file| path. | |
99 | |
100 Args: | |
101 dsym_path_prefix: string, The path at which the dsymutil output should be | |
102 located. | |
103 full_args: list of string, Full argument list for the linker driver. | |
104 """ | |
105 if not len(dsym_path_prefix): | |
106 raise ValueError('Unspecified dSYM output file') | |
107 | |
108 linker_out = _FindLinkerOutput(full_args) | |
109 (head, tail) = os.path.split(linker_out) | |
110 dsym_out = os.path.join(dsym_path_prefix, tail + '.dSYM') | |
Mark Mentovai
2016/05/20 15:42:41
Does dsymutil trash the .dSYM before writing a new
Robert Sesek
2016/05/20 19:09:55
It "kind of" does. If you put extra things in the
| |
111 subprocess.check_call(['xcrun', 'dsymutil', '-o', dsym_out, linker_out]) | |
Mark Mentovai
2016/05/20 15:42:42
If (this or) a later step fails, the .dSYM that yo
Robert Sesek
2016/05/20 19:09:55
Yeah, this was on my mind when writing it. At the
| |
112 | |
113 | |
114 def RunStrip(strip_args_string, full_args): | |
Mark Mentovai
2016/05/20 15:42:41
We may at some point want an option to save the or
Robert Sesek
2016/05/20 19:09:55
Acknowledged.
| |
115 """Linker driver action for -Wcrl,strip,<strip_arguments>. | |
116 | |
117 Args: | |
118 strip_args_string: string, Comma-separated arguments for `strip`. | |
119 full_args: list of string, Full arguments for the linker driver. | |
120 """ | |
121 strip_args_list = strip_args_string.split(',') | |
122 strip_command = ['xcrun', 'strip'] + strip_args_list | |
123 strip_command.append(_FindLinkerOutput(full_args)) | |
124 subprocess.check_call(strip_command) | |
125 | |
126 | |
127 def _FindLinkerOutput(full_args): | |
128 """Finds the output of the linker by looking for the output flag in its | |
129 argument list. As this is a required linker argument, raises an error if it | |
130 cannot be found. | |
131 """ | |
132 for (i, arg) in enumerate(full_args): | |
133 if arg == '-o': | |
134 return full_args[i+1] | |
135 raise RuntimeError('Unable to locate linker output file') | |
136 | |
137 | |
138 """List of linker driver actions. The sort order of this list affects the | |
139 order in which the actions are invoked. The first item in the tuple is the | |
140 argument's -Wcrl,<sub_argument> and the second is the function to invoke. | |
141 """ | |
142 _LINKER_DRIVER_ACTIONS = [ | |
Mark Mentovai
2016/05/20 15:42:41
Can you move this up so that it’s after _LINKER_DR
Robert Sesek
2016/05/20 19:09:55
No because they reference functions declared later
| |
143 ('dsym,', RunDsymUtil), | |
144 ('strip,', RunStrip), | |
145 ] | |
146 | |
147 | |
148 if __name__ == '__main__': | |
149 Main(sys.argv) | |
150 sys.exit(0) | |
OLD | NEW |