Chromium Code Reviews| Index: build/toolchain/mac/linker_driver.py |
| diff --git a/build/toolchain/mac/linker_driver.py b/build/toolchain/mac/linker_driver.py |
| new file mode 100755 |
| index 0000000000000000000000000000000000000000..a2f7a075323f263df7f8e8e9870ce56b71dde878 |
| --- /dev/null |
| +++ b/build/toolchain/mac/linker_driver.py |
| @@ -0,0 +1,164 @@ |
| +#!/usr/bin/env python |
| + |
| +# Copyright 2016 The Chromium Authors. All rights reserved. |
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
| + |
| +import os |
| +import os.path |
| +import subprocess |
| +import sys |
| + |
| +# The linker_driver.py is responsible for forwarding a linker invocation to |
| +# the compiler driver, while processing special arguments itself. |
| +# |
| +# On Mac, the logical step of linking is handled by three discrete tools to |
| +# perform the image link, debug info link, and strip. The linker_driver.py |
| +# combines these three steps into a single tool. |
| +# |
| +# The command passed to the linker_driver.py is first invoked unaltered (except |
| +# for the removal of the special driver arguments, described below). Then the |
| +# driver performs additional actions, based on these arguments: |
| +# |
| +# -Wcrl,dsym,<dsym_path_prefix> |
| +# After invoking the linker, this will run `dsymutil` on the linker's |
| +# output, producing a dSYM bundle, stored at dsym_path_prefix. |
| +# |
| +# -Wcrl,strip,<strip_arguments> |
| +# After invoking the linker, and optionally dsymutil, this will run |
| +# the strip command on the linker's output. strip_arguments are |
| +# comma-separated arguments to be passed to the strip command. |
| + |
| +_LINKER_DRIVER_ARG_PREFIX = '-Wcrl,' |
| + |
| +def Main(args): |
| + """Main function for the linker driver. Separates out the arguments for |
| + the main compiler driver and the linker driver, then invokes all the |
| + required tools. |
| + |
| + Args: |
| + args: list of string, Arguments to the script. |
| + """ |
| + |
| + if len(args) < 2: |
| + raise RuntimeError("Usage: linker_driver.py [linker-invocation]") |
| + |
| + # Collect arguments to the linker driver (this script) and remove them from |
| + # the arguments being passed to the compiler driver. |
| + linker_driver_actions = {} |
| + compiler_driver_args = [] |
| + for arg in args[1:]: |
| + if arg.startswith(_LINKER_DRIVER_ARG_PREFIX): |
| + # Convert driver actions into a map of name => lambda to invoke. |
| + driver_action = ProcessLinkerDriverArg(arg) |
| + linker_driver_actions[driver_action[0]] = driver_action[1] |
| + else: |
| + compiler_driver_args.append(arg) |
| + |
| + # Run the linker by invoking the compiler driver. |
| + subprocess.check_call(compiler_driver_args) |
| + |
| + # Run the linker driver actions, in the order specified by the actions list. |
| + try: |
|
Mark Mentovai
2016/05/20 15:42:42
I’d move the try up to include the call of the com
Robert Sesek
2016/05/20 19:09:55
Done.
|
| + for action in _LINKER_DRIVER_ACTIONS: |
| + name = action[0] |
| + if name in linker_driver_actions: |
| + linker_driver_actions[name](args) |
| + except Exception, e: |
| + # If a linker driver action failed, remove the linker output to make the |
| + # build step atomic. |
| + try: |
| + os.unlink(_FindLinkerOutput(compiler_driver_args)) |
| + except RuntimeError: |
|
Mark Mentovai
2016/05/20 15:42:42
Why isn’t this just “except:”?
os.unlink is most
Robert Sesek
2016/05/20 19:09:55
This was to only capture the exception from _FindL
|
| + # Re-raise the original exception, since it may be more interesting than |
| + # failing to find the output flag. |
| + raise e |
| + return |
| + |
| + # Re-report the original failure. |
|
Mark Mentovai
2016/05/20 15:42:42
Actually, since this is what you want to do no mat
|
| + raise |
| + |
| + |
| +def ProcessLinkerDriverArg(arg): |
| + """Processes a linker driver argument and returns a tuple containing the |
| + name and unary lambda to invoke for that linker driver action. |
| + |
| + Args: |
| + arg: string, The linker driver argument. |
| + |
| + Returns: |
| + A 2-tuple: |
| + 0: The driver action name, as in _LINKER_DRIVER_ACTIONS. |
| + 1: An 1-ary lambda that takes the full list of arguments passed to |
| + Main(). The lambda should call the linker driver action that |
| + corresponds to the argument. |
| + """ |
| + if not arg.startswith(_LINKER_DRIVER_ARG_PREFIX): |
| + raise ValueError('%s is not a linker driver argument' % (arg,)) |
| + |
| + sub_arg = arg[len(_LINKER_DRIVER_ARG_PREFIX):] |
| + |
| + for driver_action in _LINKER_DRIVER_ACTIONS: |
| + (name, action) = driver_action |
| + if sub_arg.startswith(name): |
| + return (name, |
| + lambda full_args: action(sub_arg[len(name):], full_args)) |
| + |
| + raise ValueError('Unknown linker driver argument: %s' % (arg,)) |
| + |
| + |
| +def RunDsymUtil(dsym_path_prefix, full_args): |
| + """Linker driver action for -Wcrl,dsym,<dsym-path-prefix>. Invokes dsymutil |
| + on the linker's output and produces a dsym file at |dsym_file| path. |
| + |
| + Args: |
| + dsym_path_prefix: string, The path at which the dsymutil output should be |
| + located. |
| + full_args: list of string, Full argument list for the linker driver. |
| + """ |
| + if not len(dsym_path_prefix): |
| + raise ValueError('Unspecified dSYM output file') |
| + |
| + linker_out = _FindLinkerOutput(full_args) |
| + (head, tail) = os.path.split(linker_out) |
| + dsym_out = os.path.join(dsym_path_prefix, tail + '.dSYM') |
| + subprocess.check_call(['xcrun', 'dsymutil', '-o', dsym_out, linker_out]) |
| + |
| + |
| +def RunStrip(strip_args_string, full_args): |
| + """Linker driver action for -Wcrl,strip,<strip_arguments>. |
| + |
| + Args: |
| + strip_args_string: string, Comma-separated arguments for `strip`. |
| + full_args: list of string, Full arguments for the linker driver. |
| + """ |
| + strip_args_list = strip_args_string.split(',') |
| + strip_command = ['xcrun', 'strip'] + strip_args_list |
| + strip_command.append(_FindLinkerOutput(full_args)) |
| + subprocess.check_call(strip_command) |
| + |
| + |
| +def _FindLinkerOutput(full_args): |
| + """Finds the output of the linker by looking for the output flag in its |
| + argument list. As this is a required linker argument, raises an error if it |
|
Mark Mentovai
2016/05/20 15:42:42
Not true.
% echo 'int main(int argc, char* argv[]
Robert Sesek
2016/05/20 19:09:55
This comment is true for our build.
Mark Mentovai
2016/05/20 19:41:11
Robert Sesek wrote:
|
| + cannot be found. |
| + """ |
| + for (i, arg) in enumerate(full_args): |
| + if arg == '-o': |
| + return full_args[i+1] |
| + raise RuntimeError('Unable to locate linker output file') |
| + |
| + |
| +"""List of linker driver actions. The sort order of this list affects the |
| +order in which the actions are invoked. The first item in the tuple is the |
| +argument's -Wcrl,<sub_argument> and the second is the function to invoke. |
| +""" |
| +_LINKER_DRIVER_ACTIONS = [ |
| + ('dsym,', RunDsymUtil), |
| + ('strip,', RunStrip), |
| +] |
| + |
| + |
| +if __name__ == '__main__': |
| + Main(sys.argv) |
| + sys.exit(0) |