blob: 01449578ca0ba5a33677dea431f504cb60a982ce [file] [log] [blame]
Manoj Guptad1a78462022-01-13 21:46:42 -08001# Copyright 2022 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Creates a remote_toolchain_inputs file for Reclient.
6
7Reclient(go/rbe/dev/x/reclient) is used for remote execution of build
8actions in build systems e.g. Chrome. It needs a toolchain inputs file
9next to clang compiler binary which has all the input dependencies
10needed to run the clang binary remotely.
11
12Running the script:
13$ generate_reclient_inputs [--output file_name] [--clang /path/to/clang]
14will create the file /path/to/file_name.
15
16By default, the script will write to /usr/bin/remote_toolchain_inputs.
17
18Contact: Chrome OS toolchain team.
19"""
20
Mike Frysinger49c6e1f2022-04-14 15:41:40 -040021import argparse
Manoj Guptad1a78462022-01-13 21:46:42 -080022import os
23from pathlib import Path
24from typing import List, Optional, Set
25
26from chromite.lib import commandline
27from chromite.lib import cros_build_lib
Manoj Guptaf23b3932022-01-21 08:44:59 -080028from chromite.lib import osutils
Manoj Guptad1a78462022-01-13 21:46:42 -080029from chromite.third_party import lddtree
30
31
32def _GetSymLinkPath(base_dir: Path, link_path: str) -> Path:
33 """Return the actual symlink path relative to base directory."""
34 if not link_path:
35 return None
36 # Handle absolute symlink paths.
37 if link_path[0] == '/':
38 return link_path
39 # handle relative symlinks.
40 return base_dir / link_path
41
42
43def _CollectElfDeps(elfpath: Path) -> Set[Path]:
44 """Returns the set of dependent files for the elf file."""
45 libs = set()
Manoj Gupta70f1be92022-02-03 17:24:42 -080046 to_process = [elfpath]
Manoj Guptad1a78462022-01-13 21:46:42 -080047 elf = lddtree.ParseELF(elfpath, ldpaths=lddtree.LoadLdpaths())
48 for _, lib_data in elf['libs'].items():
49 if lib_data['path']:
50 to_process.append(Path(lib_data['path']))
51
52 while to_process:
53 path = to_process.pop()
54 if not path or path in libs:
55 continue
56 libs.add(path)
57 if path.is_symlink():
58 # TODO: Replace os.readlink() by path.readlink().
59 to_process.append(_GetSymLinkPath(path.parent, os.readlink(path)))
60
61 return libs
62
63
64def _GenerateRemoteInputsFile(out_file: str, clang_path: Path) -> None:
65 """Generate Remote Inputs for Clang for executing on reclient/RBE."""
66 clang_dir = clang_path.parent
67 # Start with collecting shared library dependencies.
68 paths = _CollectElfDeps(clang_path)
69
70 # Clang is typically a symlink, collect actual files.
71 paths.add(clang_path)
Manoj Guptad1a78462022-01-13 21:46:42 -080072
Manoj Gupta70f1be92022-02-03 17:24:42 -080073 # Add clang resources, gcc config and glibc loader files.
Manoj Guptad1a78462022-01-13 21:46:42 -080074 cmd = [str(clang_path), '--print-resource-dir']
75 resource_dir = cros_build_lib.run(
76 cmd, capture_output=True, encoding='utf-8',
77 print_cmd=False).stdout.splitlines()[0]
78 paths.add(Path(resource_dir) / 'share')
Manoj Gupta70f1be92022-02-03 17:24:42 -080079 paths.update(
80 Path(x) for x in (
81 '/etc/env.d/gcc',
82 '/etc/ld.so.cache',
83 '/etc/ld.so.conf',
84 '/etc/ld.so.conf.d',
85 ))
Manoj Guptad1a78462022-01-13 21:46:42 -080086
87 # Write the files relative to clang binary location.
Manoj Guptaf23b3932022-01-21 08:44:59 -080088 osutils.WriteFile(
89 clang_dir / out_file,
90 [os.path.relpath(x, clang_dir) + '\n' for x in sorted(paths)],
91 sudo=True)
Manoj Guptad1a78462022-01-13 21:46:42 -080092
93
Mike Frysinger49c6e1f2022-04-14 15:41:40 -040094def ParseArgs(argv: Optional[List[str]]) -> argparse.Namespace:
Manoj Guptad1a78462022-01-13 21:46:42 -080095 """Parses program arguments."""
96 parser = commandline.ArgumentParser(description=__doc__)
97
98 parser.add_argument(
99 '--output',
100 default='remote_toolchain_inputs',
101 help='Name of remote toolchain file relative to clang binary directory.')
102 parser.add_argument(
103 '--clang', type=Path, default='/usr/bin/clang', help='Clang binary path.')
104
105 opts = parser.parse_args(argv)
106 opts.Freeze()
107 return opts
108
109
110def main(argv: Optional[List[str]] = None) -> Optional[int]:
111 cros_build_lib.AssertInsideChroot()
112 opts = ParseArgs(argv)
113 _GenerateRemoteInputsFile(opts.output, opts.clang)