blob: e74df0932fe272000267a68cfd7c17f509a3c319 [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
Mike Frysinger807d8282022-04-28 22:45:17 -040026from chromite.third_party import lddtree
27
Manoj Guptad1a78462022-01-13 21:46:42 -080028from chromite.lib import commandline
29from chromite.lib import cros_build_lib
Manoj Guptaf23b3932022-01-21 08:44:59 -080030from chromite.lib import osutils
Manoj Guptad1a78462022-01-13 21:46:42 -080031
32
33def _GetSymLinkPath(base_dir: Path, link_path: str) -> Path:
Alex Klein1699fab2022-09-08 08:46:06 -060034 """Return the actual symlink path relative to base directory."""
35 if not link_path:
36 return None
37 # Handle absolute symlink paths.
38 if link_path[0] == "/":
39 return link_path
40 # handle relative symlinks.
41 return base_dir / link_path
Manoj Guptad1a78462022-01-13 21:46:42 -080042
43
44def _CollectElfDeps(elfpath: Path) -> Set[Path]:
Alex Klein1699fab2022-09-08 08:46:06 -060045 """Returns the set of dependent files for the elf file."""
46 libs = set()
47 to_process = [elfpath]
48 elf = lddtree.ParseELF(elfpath, ldpaths=lddtree.LoadLdpaths())
49 for _, lib_data in elf["libs"].items():
50 if lib_data["path"]:
51 to_process.append(Path(lib_data["path"]))
Manoj Guptad1a78462022-01-13 21:46:42 -080052
Alex Klein1699fab2022-09-08 08:46:06 -060053 while to_process:
54 path = to_process.pop()
55 if not path or path in libs:
56 continue
57 libs.add(path)
58 if path.is_symlink():
59 # TODO: Replace os.readlink() by path.readlink().
60 to_process.append(_GetSymLinkPath(path.parent, os.readlink(path)))
Manoj Guptad1a78462022-01-13 21:46:42 -080061
Alex Klein1699fab2022-09-08 08:46:06 -060062 return libs
Manoj Guptad1a78462022-01-13 21:46:42 -080063
64
65def _GenerateRemoteInputsFile(out_file: str, clang_path: Path) -> None:
Alex Klein1699fab2022-09-08 08:46:06 -060066 """Generate Remote Inputs for Clang for executing on reclient/RBE."""
67 clang_dir = clang_path.parent
68 # Start with collecting shared library dependencies.
69 paths = _CollectElfDeps(clang_path)
Manoj Guptad1a78462022-01-13 21:46:42 -080070
Alex Klein1699fab2022-09-08 08:46:06 -060071 # Clang is typically a symlink, collect actual files.
72 paths.add(clang_path)
Manoj Guptad1a78462022-01-13 21:46:42 -080073
Alex Klein1699fab2022-09-08 08:46:06 -060074 # Add clang resources, gcc config and glibc loader files.
75 cmd = [str(clang_path), "--print-resource-dir"]
76 resource_dir = cros_build_lib.run(
77 cmd, capture_output=True, encoding="utf-8", print_cmd=False
78 ).stdout.splitlines()[0]
79 paths.add(Path(resource_dir) / "share")
80 paths.update(
81 Path(x)
82 for x in (
83 "/etc/env.d/gcc",
84 "/etc/ld.so.cache",
85 "/etc/ld.so.conf",
86 "/etc/ld.so.conf.d",
87 )
88 )
Manoj Guptad1a78462022-01-13 21:46:42 -080089
Alex Klein1699fab2022-09-08 08:46:06 -060090 # Write the files relative to clang binary location.
91 osutils.WriteFile(
92 clang_dir / out_file,
93 [os.path.relpath(x, clang_dir) + "\n" for x in sorted(paths)],
94 sudo=True,
95 )
Manoj Guptad1a78462022-01-13 21:46:42 -080096
97
Mike Frysinger49c6e1f2022-04-14 15:41:40 -040098def ParseArgs(argv: Optional[List[str]]) -> argparse.Namespace:
Alex Klein1699fab2022-09-08 08:46:06 -060099 """Parses program arguments."""
100 parser = commandline.ArgumentParser(description=__doc__)
Manoj Guptad1a78462022-01-13 21:46:42 -0800101
Alex Klein1699fab2022-09-08 08:46:06 -0600102 parser.add_argument(
103 "--output",
104 default="remote_toolchain_inputs",
105 help="Name of remote toolchain file relative to clang binary directory.",
106 )
107 parser.add_argument(
108 "--clang",
109 type=Path,
110 default="/usr/bin/clang",
111 help="Clang binary path.",
112 )
Manoj Guptad1a78462022-01-13 21:46:42 -0800113
Alex Klein1699fab2022-09-08 08:46:06 -0600114 opts = parser.parse_args(argv)
115 opts.Freeze()
116 return opts
Manoj Guptad1a78462022-01-13 21:46:42 -0800117
118
119def main(argv: Optional[List[str]] = None) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600120 cros_build_lib.AssertInsideChroot()
121 opts = ParseArgs(argv)
122 _GenerateRemoteInputsFile(opts.output, opts.clang)