Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(384)

Side by Side Diff: build/toolchain/mac/linker_driver.py

Issue 1999513002: [Mac/GN] Implement dSYM generation and stripping. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Comment++ Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « build/toolchain/mac/BUILD.gn ('k') | chrome/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 # Usage: linker_driver.py clang++ main.o -L. -llib -o prog -Wcrl,dsym,out
17 #
18 # On Mac, the logical step of linking is handled by three discrete tools to
19 # perform the image link, debug info link, and strip. The linker_driver.py
20 # combines these three steps into a single tool.
21 #
22 # The command passed to the linker_driver.py should be the compiler driver
23 # invocation for the linker. It is first invoked unaltered (except for the
24 # removal of the special driver arguments, described below). Then the driver
25 # performs additional actions, based on these arguments:
26 #
27 # -Wcrl,dsym,<dsym_path_prefix>
28 # After invoking the linker, this will run `dsymutil` on the linker's
29 # output, producing a dSYM bundle, stored at dsym_path_prefix. As an
30 # example, if the linker driver were invoked with:
31 # "... -o out/gn/obj/foo/libbar.dylib ... -Wcrl,dsym,out/gn ..."
32 # The resulting dSYM would be out/gn/libbar.dylib.dSYM/.
33 #
34 # -Wcrl,strip,<strip_arguments>
35 # After invoking the linker, and optionally dsymutil, this will run
36 # the strip command on the linker's output. strip_arguments are
37 # comma-separated arguments to be passed to the strip command.
38
39 def Main(args):
40 """Main function for the linker driver. Separates out the arguments for
41 the main compiler driver and the linker driver, then invokes all the
42 required tools.
43
44 Args:
45 args: list of string, Arguments to the script.
46 """
47
48 if len(args) < 2:
49 raise RuntimeError("Usage: linker_driver.py [linker-invocation]")
50
51 # Collect arguments to the linker driver (this script) and remove them from
52 # the arguments being passed to the compiler driver.
53 linker_driver_actions = {}
54 compiler_driver_args = []
55 for arg in args[1:]:
56 if arg.startswith(_LINKER_DRIVER_ARG_PREFIX):
57 # Convert driver actions into a map of name => lambda to invoke.
58 driver_action = ProcessLinkerDriverArg(arg)
59 assert driver_action[0] not in linker_driver_actions
60 linker_driver_actions[driver_action[0]] = driver_action[1]
61 else:
62 compiler_driver_args.append(arg)
63
64 linker_driver_outputs = [_FindLinkerOutput(compiler_driver_args)]
65
66 try:
67 # Run the linker by invoking the compiler driver.
68 subprocess.check_call(compiler_driver_args)
69
70 # Run the linker driver actions, in the order specified by the actions list.
71 for action in _LINKER_DRIVER_ACTIONS:
72 name = action[0]
73 if name in linker_driver_actions:
74 linker_driver_outputs += linker_driver_actions[name](args)
75 except:
76 # If a linker driver action failed, remove all the outputs to make the
77 # build step atomic.
78 map(_RemovePath, linker_driver_outputs)
79
80 # Re-report the original failure.
81 raise
82
83
84 def ProcessLinkerDriverArg(arg):
85 """Processes a linker driver argument and returns a tuple containing the
86 name and unary lambda to invoke for that linker driver action.
87
88 Args:
89 arg: string, The linker driver argument.
90
91 Returns:
92 A 2-tuple:
93 0: The driver action name, as in _LINKER_DRIVER_ACTIONS.
94 1: An 1-ary lambda that takes the full list of arguments passed to
95 Main(). The lambda should call the linker driver action that
96 corresponds to the argument and return a list of outputs from the
97 action.
98 """
99 if not arg.startswith(_LINKER_DRIVER_ARG_PREFIX):
100 raise ValueError('%s is not a linker driver argument' % (arg,))
101
102 sub_arg = arg[len(_LINKER_DRIVER_ARG_PREFIX):]
103
104 for driver_action in _LINKER_DRIVER_ACTIONS:
105 (name, action) = driver_action
106 if sub_arg.startswith(name):
107 return (name,
108 lambda full_args: action(sub_arg[len(name):], full_args))
109
110 raise ValueError('Unknown linker driver argument: %s' % (arg,))
111
112
113 def RunDsymUtil(dsym_path_prefix, full_args):
114 """Linker driver action for -Wcrl,dsym,<dsym-path-prefix>. Invokes dsymutil
115 on the linker's output and produces a dsym file at |dsym_file| path.
116
117 Args:
118 dsym_path_prefix: string, The path at which the dsymutil output should be
119 located.
120 full_args: list of string, Full argument list for the linker driver.
121
122 Returns:
123 list of string, Build step outputs.
124 """
125 if not len(dsym_path_prefix):
126 raise ValueError('Unspecified dSYM output file')
127
128 linker_out = _FindLinkerOutput(full_args)
129 (head, tail) = os.path.split(linker_out)
130 dsym_out = os.path.join(dsym_path_prefix, tail + '.dSYM')
131
132 # Remove old dSYMs before invoking dsymutil.
133 _RemovePath(dsym_out)
134 subprocess.check_call(['xcrun', 'dsymutil', '-o', dsym_out, linker_out])
135 return [dsym_out]
136
137
138 def RunStrip(strip_args_string, full_args):
139 """Linker driver action for -Wcrl,strip,<strip_arguments>.
140
141 Args:
142 strip_args_string: string, Comma-separated arguments for `strip`.
143 full_args: list of string, Full arguments for the linker driver.
144
145 Returns:
146 list of string, Build step outputs.
147 """
148 strip_command = ['xcrun', 'strip']
149 if len(strip_args_string) > 0:
150 strip_command += strip_args_string.split(',')
151 strip_command.append(_FindLinkerOutput(full_args))
152 subprocess.check_call(strip_command)
153 return []
154
155
156 def _FindLinkerOutput(full_args):
157 """Finds the output of the linker by looking for the output flag in its
158 argument list. As this is a required linker argument, raises an error if it
159 cannot be found.
160 """
161 return full_args[full_args.index('-o') + 1]
162
163
164 def _RemovePath(path):
165 """Removes the file or directory at |path| if it exists."""
166 if os.path.exists(path):
167 if os.path.isdir(path):
168 shutil.rmtree(path)
169 else:
170 os.unlink(path)
171
172
173 _LINKER_DRIVER_ARG_PREFIX = '-Wcrl,'
174
175 """List of linker driver actions. The sort order of this list affects the
176 order in which the actions are invoked. The first item in the tuple is the
177 argument's -Wcrl,<sub_argument> and the second is the function to invoke.
178 """
179 _LINKER_DRIVER_ACTIONS = [
180 ('dsym,', RunDsymUtil),
181 ('strip,', RunStrip),
182 ]
183
184
185 if __name__ == '__main__':
186 Main(sys.argv)
187 sys.exit(0)
OLDNEW
« no previous file with comments | « build/toolchain/mac/BUILD.gn ('k') | chrome/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698