xref: /aosp_15_r20/external/cronet/build/toolchain/apple/linker_driver.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*6777b538SAndroid Build Coastguard Worker
3*6777b538SAndroid Build Coastguard Worker# Copyright 2016 The Chromium Authors
4*6777b538SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be
5*6777b538SAndroid Build Coastguard Worker# found in the LICENSE file.
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Workerimport os
8*6777b538SAndroid Build Coastguard Workerimport os.path
9*6777b538SAndroid Build Coastguard Workerimport re
10*6777b538SAndroid Build Coastguard Workerimport shutil
11*6777b538SAndroid Build Coastguard Workerimport subprocess
12*6777b538SAndroid Build Coastguard Workerimport sys
13*6777b538SAndroid Build Coastguard Workerimport tempfile
14*6777b538SAndroid Build Coastguard Worker
15*6777b538SAndroid Build Coastguard Worker# The path to `whole_archive`.
16*6777b538SAndroid Build Coastguard Workersys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'))
17*6777b538SAndroid Build Coastguard Worker
18*6777b538SAndroid Build Coastguard Workerimport whole_archive
19*6777b538SAndroid Build Coastguard Worker
20*6777b538SAndroid Build Coastguard Worker# Prefix for all custom linker driver arguments.
21*6777b538SAndroid Build Coastguard WorkerLINKER_DRIVER_ARG_PREFIX = '-Wcrl,'
22*6777b538SAndroid Build Coastguard WorkerLINKER_DRIVER_COMPILER_ARG_PREFIX = '-Wcrl,driver,'
23*6777b538SAndroid Build Coastguard Worker# Linker action to create a directory and pass it to the linker as
24*6777b538SAndroid Build Coastguard Worker# `-object_path_lto`. Special-cased since it has to run before the link.
25*6777b538SAndroid Build Coastguard WorkerOBJECT_PATH_LTO = 'object_path_lto'
26*6777b538SAndroid Build Coastguard Worker
27*6777b538SAndroid Build Coastguard Worker# The linker_driver.py is responsible for forwarding a linker invocation to
28*6777b538SAndroid Build Coastguard Worker# the compiler driver, while processing special arguments itself.
29*6777b538SAndroid Build Coastguard Worker#
30*6777b538SAndroid Build Coastguard Worker# Usage: linker_driver.py -Wcrl,driver,clang++ main.o -L. -llib -o prog \
31*6777b538SAndroid Build Coastguard Worker#            -Wcrl,dsym,out
32*6777b538SAndroid Build Coastguard Worker#
33*6777b538SAndroid Build Coastguard Worker# On Mac, the logical step of linking is handled by three discrete tools to
34*6777b538SAndroid Build Coastguard Worker# perform the image link, debug info link, and strip. The linker_driver.py
35*6777b538SAndroid Build Coastguard Worker# combines these three steps into a single tool.
36*6777b538SAndroid Build Coastguard Worker#
37*6777b538SAndroid Build Coastguard Worker# The compiler driver invocation for the linker is specified by the following
38*6777b538SAndroid Build Coastguard Worker# required argument.
39*6777b538SAndroid Build Coastguard Worker#
40*6777b538SAndroid Build Coastguard Worker# -Wcrl,driver,<path_to_compiler_driver>
41*6777b538SAndroid Build Coastguard Worker#    Specifies the path to the compiler driver.
42*6777b538SAndroid Build Coastguard Worker#
43*6777b538SAndroid Build Coastguard Worker# After running the compiler driver, the script performs additional actions,
44*6777b538SAndroid Build Coastguard Worker# based on these arguments:
45*6777b538SAndroid Build Coastguard Worker#
46*6777b538SAndroid Build Coastguard Worker# -Wcrl,installnametoolpath,<install_name_tool_path>
47*6777b538SAndroid Build Coastguard Worker#    Sets the path to the `install_name_tool` to run with
48*6777b538SAndroid Build Coastguard Worker#    -Wcrl,installnametool, in which case `xcrun` is not used to invoke it.
49*6777b538SAndroid Build Coastguard Worker#
50*6777b538SAndroid Build Coastguard Worker# -Wcrl,installnametool,<arguments,...>
51*6777b538SAndroid Build Coastguard Worker#    After invoking the linker, this will run install_name_tool on the linker's
52*6777b538SAndroid Build Coastguard Worker#    output. |arguments| are comma-separated arguments to be passed to the
53*6777b538SAndroid Build Coastguard Worker#    install_name_tool command.
54*6777b538SAndroid Build Coastguard Worker#
55*6777b538SAndroid Build Coastguard Worker# -Wcrl,dsym,<dsym_path_prefix>
56*6777b538SAndroid Build Coastguard Worker#    After invoking the linker, this will run `dsymutil` on the linker's
57*6777b538SAndroid Build Coastguard Worker#    output, producing a dSYM bundle, stored at dsym_path_prefix. As an
58*6777b538SAndroid Build Coastguard Worker#    example, if the linker driver were invoked with:
59*6777b538SAndroid Build Coastguard Worker#        "... -o out/gn/obj/foo/libbar.dylib ... -Wcrl,dsym,out/gn ..."
60*6777b538SAndroid Build Coastguard Worker#    The resulting dSYM would be out/gn/libbar.dylib.dSYM/.
61*6777b538SAndroid Build Coastguard Worker#
62*6777b538SAndroid Build Coastguard Worker# -Wcrl,dsymutilpath,<dsymutil_path>
63*6777b538SAndroid Build Coastguard Worker#    Sets the path to the dsymutil to run with -Wcrl,dsym, in which case
64*6777b538SAndroid Build Coastguard Worker#    `xcrun` is not used to invoke it.
65*6777b538SAndroid Build Coastguard Worker#
66*6777b538SAndroid Build Coastguard Worker# -Wcrl,unstripped,<unstripped_path_prefix>
67*6777b538SAndroid Build Coastguard Worker#    After invoking the linker, and before strip, this will save a copy of
68*6777b538SAndroid Build Coastguard Worker#    the unstripped linker output in the directory unstripped_path_prefix.
69*6777b538SAndroid Build Coastguard Worker#
70*6777b538SAndroid Build Coastguard Worker# -Wcrl,strip,<strip_arguments>
71*6777b538SAndroid Build Coastguard Worker#    After invoking the linker, and optionally dsymutil, this will run
72*6777b538SAndroid Build Coastguard Worker#    the strip command on the linker's output. strip_arguments are
73*6777b538SAndroid Build Coastguard Worker#    comma-separated arguments to be passed to the strip command.
74*6777b538SAndroid Build Coastguard Worker#
75*6777b538SAndroid Build Coastguard Worker# -Wcrl,strippath,<strip_path>
76*6777b538SAndroid Build Coastguard Worker#    Sets the path to the strip to run with -Wcrl,strip, in which case
77*6777b538SAndroid Build Coastguard Worker#    `xcrun` is not used to invoke it.
78*6777b538SAndroid Build Coastguard Worker# -Wcrl,object_path_lto
79*6777b538SAndroid Build Coastguard Worker#    Creates temporary directory for LTO object files.
80*6777b538SAndroid Build Coastguard Worker
81*6777b538SAndroid Build Coastguard Worker
82*6777b538SAndroid Build Coastguard Workerclass LinkerDriver(object):
83*6777b538SAndroid Build Coastguard Worker    def __init__(self, args):
84*6777b538SAndroid Build Coastguard Worker        """Creates a new linker driver.
85*6777b538SAndroid Build Coastguard Worker
86*6777b538SAndroid Build Coastguard Worker        Args:
87*6777b538SAndroid Build Coastguard Worker            args: list of string, Arguments to the script.
88*6777b538SAndroid Build Coastguard Worker        """
89*6777b538SAndroid Build Coastguard Worker        self._args = args
90*6777b538SAndroid Build Coastguard Worker
91*6777b538SAndroid Build Coastguard Worker        # List of linker driver actions. **The sort order of this list affects
92*6777b538SAndroid Build Coastguard Worker        # the order in which the actions are invoked.**
93*6777b538SAndroid Build Coastguard Worker        # The first item in the tuple is the argument's -Wcrl,<sub_argument>
94*6777b538SAndroid Build Coastguard Worker        # and the second is the function to invoke.
95*6777b538SAndroid Build Coastguard Worker        self._actions = [
96*6777b538SAndroid Build Coastguard Worker            ('installnametoolpath,', self.set_install_name_tool_path),
97*6777b538SAndroid Build Coastguard Worker            ('installnametool,', self.run_install_name_tool),
98*6777b538SAndroid Build Coastguard Worker            ('dsymutilpath,', self.set_dsymutil_path),
99*6777b538SAndroid Build Coastguard Worker            ('dsym,', self.run_dsymutil),
100*6777b538SAndroid Build Coastguard Worker            ('unstripped,', self.run_save_unstripped),
101*6777b538SAndroid Build Coastguard Worker            ('strippath,', self.set_strip_path),
102*6777b538SAndroid Build Coastguard Worker            ('strip,', self.run_strip),
103*6777b538SAndroid Build Coastguard Worker        ]
104*6777b538SAndroid Build Coastguard Worker
105*6777b538SAndroid Build Coastguard Worker        # Linker driver actions can modify the these values.
106*6777b538SAndroid Build Coastguard Worker        self._driver_path = None  # Must be specified on the command line.
107*6777b538SAndroid Build Coastguard Worker        self._install_name_tool_cmd = ['xcrun', 'install_name_tool']
108*6777b538SAndroid Build Coastguard Worker        self._dsymutil_cmd = ['xcrun', 'dsymutil']
109*6777b538SAndroid Build Coastguard Worker        self._strip_cmd = ['xcrun', 'strip']
110*6777b538SAndroid Build Coastguard Worker
111*6777b538SAndroid Build Coastguard Worker        # The linker output file, lazily computed in self._get_linker_output().
112*6777b538SAndroid Build Coastguard Worker        self._linker_output = None
113*6777b538SAndroid Build Coastguard Worker        # The temporary directory for intermediate LTO object files. If it
114*6777b538SAndroid Build Coastguard Worker        # exists, it will clean itself up on script exit.
115*6777b538SAndroid Build Coastguard Worker        self._object_path_lto = None
116*6777b538SAndroid Build Coastguard Worker
117*6777b538SAndroid Build Coastguard Worker    def run(self):
118*6777b538SAndroid Build Coastguard Worker        """Runs the linker driver, separating out the main compiler driver's
119*6777b538SAndroid Build Coastguard Worker        arguments from the ones handled by this class. It then invokes the
120*6777b538SAndroid Build Coastguard Worker        required tools, starting with the compiler driver to produce the linker
121*6777b538SAndroid Build Coastguard Worker        output.
122*6777b538SAndroid Build Coastguard Worker        """
123*6777b538SAndroid Build Coastguard Worker        # Collect arguments to the linker driver (this script) and remove them
124*6777b538SAndroid Build Coastguard Worker        # from the arguments being passed to the compiler driver.
125*6777b538SAndroid Build Coastguard Worker        linker_driver_actions = {}
126*6777b538SAndroid Build Coastguard Worker        compiler_driver_args = []
127*6777b538SAndroid Build Coastguard Worker        for index, arg in enumerate(self._args[1:]):
128*6777b538SAndroid Build Coastguard Worker            if arg.startswith(LINKER_DRIVER_COMPILER_ARG_PREFIX):
129*6777b538SAndroid Build Coastguard Worker                assert not self._driver_path
130*6777b538SAndroid Build Coastguard Worker                self._driver_path = arg[len(LINKER_DRIVER_COMPILER_ARG_PREFIX
131*6777b538SAndroid Build Coastguard Worker                                            ):]
132*6777b538SAndroid Build Coastguard Worker            elif arg.startswith(LINKER_DRIVER_ARG_PREFIX):
133*6777b538SAndroid Build Coastguard Worker                # Convert driver actions into a map of name => lambda to invoke.
134*6777b538SAndroid Build Coastguard Worker                driver_action = self._process_driver_arg(arg)
135*6777b538SAndroid Build Coastguard Worker                assert driver_action[0] not in linker_driver_actions
136*6777b538SAndroid Build Coastguard Worker                linker_driver_actions[driver_action[0]] = driver_action[1]
137*6777b538SAndroid Build Coastguard Worker            else:
138*6777b538SAndroid Build Coastguard Worker                # TODO(crbug.com/1446796): On Apple, the linker command line
139*6777b538SAndroid Build Coastguard Worker                # produced by rustc for LTO includes these arguments, but the
140*6777b538SAndroid Build Coastguard Worker                # Apple linker doesn't accept them.
141*6777b538SAndroid Build Coastguard Worker                # Upstream bug: https://github.com/rust-lang/rust/issues/60059
142*6777b538SAndroid Build Coastguard Worker                BAD_RUSTC_ARGS = '-Wl,-plugin-opt=O[0-9],-plugin-opt=mcpu=.*'
143*6777b538SAndroid Build Coastguard Worker                if not re.match(BAD_RUSTC_ARGS, arg):
144*6777b538SAndroid Build Coastguard Worker                    compiler_driver_args.append(arg)
145*6777b538SAndroid Build Coastguard Worker
146*6777b538SAndroid Build Coastguard Worker        if not self._driver_path:
147*6777b538SAndroid Build Coastguard Worker            raise RuntimeError(
148*6777b538SAndroid Build Coastguard Worker                "Usage: linker_driver.py -Wcrl,driver,<compiler-driver> "
149*6777b538SAndroid Build Coastguard Worker                "[linker-args]...")
150*6777b538SAndroid Build Coastguard Worker
151*6777b538SAndroid Build Coastguard Worker        if self._object_path_lto is not None:
152*6777b538SAndroid Build Coastguard Worker            compiler_driver_args.append('-Wl,-object_path_lto,{}'.format(
153*6777b538SAndroid Build Coastguard Worker                os.path.relpath(self._object_path_lto.name)))
154*6777b538SAndroid Build Coastguard Worker        if self._get_linker_output() is None:
155*6777b538SAndroid Build Coastguard Worker            raise ValueError(
156*6777b538SAndroid Build Coastguard Worker                'Could not find path to linker output (-o or --output)')
157*6777b538SAndroid Build Coastguard Worker
158*6777b538SAndroid Build Coastguard Worker        # We want to link rlibs as --whole-archive if they are part of a unit
159*6777b538SAndroid Build Coastguard Worker        # test target. This is determined by switch
160*6777b538SAndroid Build Coastguard Worker        # `-LinkWrapper,add-whole-archive`.
161*6777b538SAndroid Build Coastguard Worker        compiler_driver_args = whole_archive.wrap_with_whole_archive(
162*6777b538SAndroid Build Coastguard Worker            compiler_driver_args, is_apple=True)
163*6777b538SAndroid Build Coastguard Worker
164*6777b538SAndroid Build Coastguard Worker        linker_driver_outputs = [self._get_linker_output()]
165*6777b538SAndroid Build Coastguard Worker
166*6777b538SAndroid Build Coastguard Worker        try:
167*6777b538SAndroid Build Coastguard Worker            # Zero the mtime in OSO fields for deterministic builds.
168*6777b538SAndroid Build Coastguard Worker            # https://crbug.com/330262.
169*6777b538SAndroid Build Coastguard Worker            env = os.environ.copy()
170*6777b538SAndroid Build Coastguard Worker            env['ZERO_AR_DATE'] = '1'
171*6777b538SAndroid Build Coastguard Worker            # Run the linker by invoking the compiler driver.
172*6777b538SAndroid Build Coastguard Worker            subprocess.check_call([self._driver_path] + compiler_driver_args,
173*6777b538SAndroid Build Coastguard Worker                                  env=env)
174*6777b538SAndroid Build Coastguard Worker
175*6777b538SAndroid Build Coastguard Worker            # Run the linker driver actions, in the order specified by the
176*6777b538SAndroid Build Coastguard Worker            # actions list.
177*6777b538SAndroid Build Coastguard Worker            for action in self._actions:
178*6777b538SAndroid Build Coastguard Worker                name = action[0]
179*6777b538SAndroid Build Coastguard Worker                if name in linker_driver_actions:
180*6777b538SAndroid Build Coastguard Worker                    linker_driver_outputs += linker_driver_actions[name]()
181*6777b538SAndroid Build Coastguard Worker        except:
182*6777b538SAndroid Build Coastguard Worker            # If a linker driver action failed, remove all the outputs to make
183*6777b538SAndroid Build Coastguard Worker            # the build step atomic.
184*6777b538SAndroid Build Coastguard Worker            map(_remove_path, linker_driver_outputs)
185*6777b538SAndroid Build Coastguard Worker
186*6777b538SAndroid Build Coastguard Worker            # Re-report the original failure.
187*6777b538SAndroid Build Coastguard Worker            raise
188*6777b538SAndroid Build Coastguard Worker
189*6777b538SAndroid Build Coastguard Worker    def _get_linker_output(self):
190*6777b538SAndroid Build Coastguard Worker        """Returns the value of the output argument to the linker."""
191*6777b538SAndroid Build Coastguard Worker        if not self._linker_output:
192*6777b538SAndroid Build Coastguard Worker            for index, arg in enumerate(self._args):
193*6777b538SAndroid Build Coastguard Worker                if arg in ('-o', '-output', '--output'):
194*6777b538SAndroid Build Coastguard Worker                    self._linker_output = self._args[index + 1]
195*6777b538SAndroid Build Coastguard Worker                    break
196*6777b538SAndroid Build Coastguard Worker        return self._linker_output
197*6777b538SAndroid Build Coastguard Worker
198*6777b538SAndroid Build Coastguard Worker    def _process_driver_arg(self, arg):
199*6777b538SAndroid Build Coastguard Worker        """Processes a linker driver argument and returns a tuple containing the
200*6777b538SAndroid Build Coastguard Worker        name and unary lambda to invoke for that linker driver action.
201*6777b538SAndroid Build Coastguard Worker
202*6777b538SAndroid Build Coastguard Worker        Args:
203*6777b538SAndroid Build Coastguard Worker            arg: string, The linker driver argument.
204*6777b538SAndroid Build Coastguard Worker
205*6777b538SAndroid Build Coastguard Worker        Returns:
206*6777b538SAndroid Build Coastguard Worker            A 2-tuple:
207*6777b538SAndroid Build Coastguard Worker                0: The driver action name, as in |self._actions|.
208*6777b538SAndroid Build Coastguard Worker                1: A lambda that calls the linker driver action with its direct
209*6777b538SAndroid Build Coastguard Worker                   argument and returns a list of outputs from the action.
210*6777b538SAndroid Build Coastguard Worker        """
211*6777b538SAndroid Build Coastguard Worker        if not arg.startswith(LINKER_DRIVER_ARG_PREFIX):
212*6777b538SAndroid Build Coastguard Worker            raise ValueError('%s is not a linker driver argument' % (arg, ))
213*6777b538SAndroid Build Coastguard Worker
214*6777b538SAndroid Build Coastguard Worker        sub_arg = arg[len(LINKER_DRIVER_ARG_PREFIX):]
215*6777b538SAndroid Build Coastguard Worker        # Special-cased, since it needs to run before the link.
216*6777b538SAndroid Build Coastguard Worker        # TODO(lgrey): Remove if/when we start running `dsymutil`
217*6777b538SAndroid Build Coastguard Worker        # through the clang driver. See https://crbug.com/1324104
218*6777b538SAndroid Build Coastguard Worker        if sub_arg == OBJECT_PATH_LTO:
219*6777b538SAndroid Build Coastguard Worker            self._object_path_lto = tempfile.TemporaryDirectory(
220*6777b538SAndroid Build Coastguard Worker                dir=os.getcwd())
221*6777b538SAndroid Build Coastguard Worker            return (OBJECT_PATH_LTO, lambda: [])
222*6777b538SAndroid Build Coastguard Worker
223*6777b538SAndroid Build Coastguard Worker        for driver_action in self._actions:
224*6777b538SAndroid Build Coastguard Worker            (name, action) = driver_action
225*6777b538SAndroid Build Coastguard Worker            if sub_arg.startswith(name):
226*6777b538SAndroid Build Coastguard Worker                return (name, lambda: action(sub_arg[len(name):]))
227*6777b538SAndroid Build Coastguard Worker
228*6777b538SAndroid Build Coastguard Worker        raise ValueError('Unknown linker driver argument: %s' % (arg, ))
229*6777b538SAndroid Build Coastguard Worker
230*6777b538SAndroid Build Coastguard Worker    def set_install_name_tool_path(self, install_name_tool_path):
231*6777b538SAndroid Build Coastguard Worker        """Linker driver action for -Wcrl,installnametoolpath,<path>.
232*6777b538SAndroid Build Coastguard Worker
233*6777b538SAndroid Build Coastguard Worker        Sets the invocation command for install_name_tool, which allows the
234*6777b538SAndroid Build Coastguard Worker        caller to specify an alternate path. This action is always
235*6777b538SAndroid Build Coastguard Worker        processed before the run_install_name_tool action.
236*6777b538SAndroid Build Coastguard Worker
237*6777b538SAndroid Build Coastguard Worker        Args:
238*6777b538SAndroid Build Coastguard Worker            install_name_tool_path: string, The path to the install_name_tool
239*6777b538SAndroid Build Coastguard Worker                binary to run
240*6777b538SAndroid Build Coastguard Worker
241*6777b538SAndroid Build Coastguard Worker        Returns:
242*6777b538SAndroid Build Coastguard Worker            No output - this step is run purely for its side-effect.
243*6777b538SAndroid Build Coastguard Worker        """
244*6777b538SAndroid Build Coastguard Worker        self._install_name_tool_cmd = [install_name_tool_path]
245*6777b538SAndroid Build Coastguard Worker        return []
246*6777b538SAndroid Build Coastguard Worker
247*6777b538SAndroid Build Coastguard Worker    def run_install_name_tool(self, args_string):
248*6777b538SAndroid Build Coastguard Worker        """Linker driver action for -Wcrl,installnametool,<args>. Invokes
249*6777b538SAndroid Build Coastguard Worker        install_name_tool on the linker's output.
250*6777b538SAndroid Build Coastguard Worker
251*6777b538SAndroid Build Coastguard Worker        Args:
252*6777b538SAndroid Build Coastguard Worker            args_string: string, Comma-separated arguments for
253*6777b538SAndroid Build Coastguard Worker                `install_name_tool`.
254*6777b538SAndroid Build Coastguard Worker
255*6777b538SAndroid Build Coastguard Worker        Returns:
256*6777b538SAndroid Build Coastguard Worker            No output - this step is run purely for its side-effect.
257*6777b538SAndroid Build Coastguard Worker        """
258*6777b538SAndroid Build Coastguard Worker        command = list(self._install_name_tool_cmd)
259*6777b538SAndroid Build Coastguard Worker        command.extend(args_string.split(','))
260*6777b538SAndroid Build Coastguard Worker        command.append(self._get_linker_output())
261*6777b538SAndroid Build Coastguard Worker        subprocess.check_call(command)
262*6777b538SAndroid Build Coastguard Worker        return []
263*6777b538SAndroid Build Coastguard Worker
264*6777b538SAndroid Build Coastguard Worker    def run_dsymutil(self, dsym_path_prefix):
265*6777b538SAndroid Build Coastguard Worker        """Linker driver action for -Wcrl,dsym,<dsym-path-prefix>. Invokes
266*6777b538SAndroid Build Coastguard Worker        dsymutil on the linker's output and produces a dsym file at |dsym_file|
267*6777b538SAndroid Build Coastguard Worker        path.
268*6777b538SAndroid Build Coastguard Worker
269*6777b538SAndroid Build Coastguard Worker        Args:
270*6777b538SAndroid Build Coastguard Worker            dsym_path_prefix: string, The path at which the dsymutil output
271*6777b538SAndroid Build Coastguard Worker                should be located.
272*6777b538SAndroid Build Coastguard Worker
273*6777b538SAndroid Build Coastguard Worker        Returns:
274*6777b538SAndroid Build Coastguard Worker            list of string, Build step outputs.
275*6777b538SAndroid Build Coastguard Worker        """
276*6777b538SAndroid Build Coastguard Worker        if not len(dsym_path_prefix):
277*6777b538SAndroid Build Coastguard Worker            raise ValueError('Unspecified dSYM output file')
278*6777b538SAndroid Build Coastguard Worker
279*6777b538SAndroid Build Coastguard Worker        linker_output = self._get_linker_output()
280*6777b538SAndroid Build Coastguard Worker        base = os.path.basename(linker_output)
281*6777b538SAndroid Build Coastguard Worker        dsym_out = os.path.join(dsym_path_prefix, base + '.dSYM')
282*6777b538SAndroid Build Coastguard Worker
283*6777b538SAndroid Build Coastguard Worker        # Remove old dSYMs before invoking dsymutil.
284*6777b538SAndroid Build Coastguard Worker        _remove_path(dsym_out)
285*6777b538SAndroid Build Coastguard Worker
286*6777b538SAndroid Build Coastguard Worker        tools_paths = _find_tools_paths(self._args)
287*6777b538SAndroid Build Coastguard Worker        if os.environ.get('PATH'):
288*6777b538SAndroid Build Coastguard Worker            tools_paths.append(os.environ['PATH'])
289*6777b538SAndroid Build Coastguard Worker        dsymutil_env = os.environ.copy()
290*6777b538SAndroid Build Coastguard Worker        dsymutil_env['PATH'] = ':'.join(tools_paths)
291*6777b538SAndroid Build Coastguard Worker        subprocess.check_call(self._dsymutil_cmd +
292*6777b538SAndroid Build Coastguard Worker                              ['-o', dsym_out, linker_output],
293*6777b538SAndroid Build Coastguard Worker                              env=dsymutil_env)
294*6777b538SAndroid Build Coastguard Worker        return [dsym_out]
295*6777b538SAndroid Build Coastguard Worker
296*6777b538SAndroid Build Coastguard Worker    def set_dsymutil_path(self, dsymutil_path):
297*6777b538SAndroid Build Coastguard Worker        """Linker driver action for -Wcrl,dsymutilpath,<dsymutil_path>.
298*6777b538SAndroid Build Coastguard Worker
299*6777b538SAndroid Build Coastguard Worker        Sets the invocation command for dsymutil, which allows the caller to
300*6777b538SAndroid Build Coastguard Worker        specify an alternate dsymutil. This action is always processed before
301*6777b538SAndroid Build Coastguard Worker        the RunDsymUtil action.
302*6777b538SAndroid Build Coastguard Worker
303*6777b538SAndroid Build Coastguard Worker        Args:
304*6777b538SAndroid Build Coastguard Worker            dsymutil_path: string, The path to the dsymutil binary to run
305*6777b538SAndroid Build Coastguard Worker
306*6777b538SAndroid Build Coastguard Worker        Returns:
307*6777b538SAndroid Build Coastguard Worker            No output - this step is run purely for its side-effect.
308*6777b538SAndroid Build Coastguard Worker        """
309*6777b538SAndroid Build Coastguard Worker        self._dsymutil_cmd = [dsymutil_path]
310*6777b538SAndroid Build Coastguard Worker        return []
311*6777b538SAndroid Build Coastguard Worker
312*6777b538SAndroid Build Coastguard Worker    def run_save_unstripped(self, unstripped_path_prefix):
313*6777b538SAndroid Build Coastguard Worker        """Linker driver action for -Wcrl,unstripped,<unstripped_path_prefix>.
314*6777b538SAndroid Build Coastguard Worker        Copies the linker output to |unstripped_path_prefix| before stripping.
315*6777b538SAndroid Build Coastguard Worker
316*6777b538SAndroid Build Coastguard Worker        Args:
317*6777b538SAndroid Build Coastguard Worker            unstripped_path_prefix: string, The path at which the unstripped
318*6777b538SAndroid Build Coastguard Worker                output should be located.
319*6777b538SAndroid Build Coastguard Worker
320*6777b538SAndroid Build Coastguard Worker        Returns:
321*6777b538SAndroid Build Coastguard Worker            list of string, Build step outputs.
322*6777b538SAndroid Build Coastguard Worker        """
323*6777b538SAndroid Build Coastguard Worker        if not len(unstripped_path_prefix):
324*6777b538SAndroid Build Coastguard Worker            raise ValueError('Unspecified unstripped output file')
325*6777b538SAndroid Build Coastguard Worker
326*6777b538SAndroid Build Coastguard Worker        base = os.path.basename(self._get_linker_output())
327*6777b538SAndroid Build Coastguard Worker        unstripped_out = os.path.join(unstripped_path_prefix,
328*6777b538SAndroid Build Coastguard Worker                                      base + '.unstripped')
329*6777b538SAndroid Build Coastguard Worker
330*6777b538SAndroid Build Coastguard Worker        shutil.copyfile(self._get_linker_output(), unstripped_out)
331*6777b538SAndroid Build Coastguard Worker        return [unstripped_out]
332*6777b538SAndroid Build Coastguard Worker
333*6777b538SAndroid Build Coastguard Worker    def run_strip(self, strip_args_string):
334*6777b538SAndroid Build Coastguard Worker        """Linker driver action for -Wcrl,strip,<strip_arguments>.
335*6777b538SAndroid Build Coastguard Worker
336*6777b538SAndroid Build Coastguard Worker        Args:
337*6777b538SAndroid Build Coastguard Worker            strip_args_string: string, Comma-separated arguments for `strip`.
338*6777b538SAndroid Build Coastguard Worker
339*6777b538SAndroid Build Coastguard Worker        Returns:
340*6777b538SAndroid Build Coastguard Worker            list of string, Build step outputs.
341*6777b538SAndroid Build Coastguard Worker        """
342*6777b538SAndroid Build Coastguard Worker        strip_command = list(self._strip_cmd)
343*6777b538SAndroid Build Coastguard Worker        if len(strip_args_string) > 0:
344*6777b538SAndroid Build Coastguard Worker            strip_command += strip_args_string.split(',')
345*6777b538SAndroid Build Coastguard Worker        strip_command.append(self._get_linker_output())
346*6777b538SAndroid Build Coastguard Worker        subprocess.check_call(strip_command)
347*6777b538SAndroid Build Coastguard Worker        return []
348*6777b538SAndroid Build Coastguard Worker
349*6777b538SAndroid Build Coastguard Worker    def set_strip_path(self, strip_path):
350*6777b538SAndroid Build Coastguard Worker        """Linker driver action for -Wcrl,strippath,<strip_path>.
351*6777b538SAndroid Build Coastguard Worker
352*6777b538SAndroid Build Coastguard Worker        Sets the invocation command for strip, which allows the caller to
353*6777b538SAndroid Build Coastguard Worker        specify an alternate strip. This action is always processed before the
354*6777b538SAndroid Build Coastguard Worker        RunStrip action.
355*6777b538SAndroid Build Coastguard Worker
356*6777b538SAndroid Build Coastguard Worker        Args:
357*6777b538SAndroid Build Coastguard Worker            strip_path: string, The path to the strip binary to run
358*6777b538SAndroid Build Coastguard Worker
359*6777b538SAndroid Build Coastguard Worker        Returns:
360*6777b538SAndroid Build Coastguard Worker            No output - this step is run purely for its side-effect.
361*6777b538SAndroid Build Coastguard Worker        """
362*6777b538SAndroid Build Coastguard Worker        self._strip_cmd = [strip_path]
363*6777b538SAndroid Build Coastguard Worker        return []
364*6777b538SAndroid Build Coastguard Worker
365*6777b538SAndroid Build Coastguard Worker
366*6777b538SAndroid Build Coastguard Workerdef _find_tools_paths(full_args):
367*6777b538SAndroid Build Coastguard Worker    """Finds all paths where the script should look for additional tools."""
368*6777b538SAndroid Build Coastguard Worker    paths = []
369*6777b538SAndroid Build Coastguard Worker    for idx, arg in enumerate(full_args):
370*6777b538SAndroid Build Coastguard Worker        if arg in ['-B', '--prefix']:
371*6777b538SAndroid Build Coastguard Worker            paths.append(full_args[idx + 1])
372*6777b538SAndroid Build Coastguard Worker        elif arg.startswith('-B'):
373*6777b538SAndroid Build Coastguard Worker            paths.append(arg[2:])
374*6777b538SAndroid Build Coastguard Worker        elif arg.startswith('--prefix='):
375*6777b538SAndroid Build Coastguard Worker            paths.append(arg[9:])
376*6777b538SAndroid Build Coastguard Worker    return paths
377*6777b538SAndroid Build Coastguard Worker
378*6777b538SAndroid Build Coastguard Worker
379*6777b538SAndroid Build Coastguard Workerdef _remove_path(path):
380*6777b538SAndroid Build Coastguard Worker    """Removes the file or directory at |path| if it exists."""
381*6777b538SAndroid Build Coastguard Worker    if os.path.exists(path):
382*6777b538SAndroid Build Coastguard Worker        if os.path.isdir(path):
383*6777b538SAndroid Build Coastguard Worker            shutil.rmtree(path)
384*6777b538SAndroid Build Coastguard Worker        else:
385*6777b538SAndroid Build Coastguard Worker            os.unlink(path)
386*6777b538SAndroid Build Coastguard Worker
387*6777b538SAndroid Build Coastguard Worker
388*6777b538SAndroid Build Coastguard Workerif __name__ == '__main__':
389*6777b538SAndroid Build Coastguard Worker    LinkerDriver(sys.argv).run()
390*6777b538SAndroid Build Coastguard Worker    sys.exit(0)
391