3 # Copyright 2022 The Chromium Authors
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
13 THIS_DIR = os.path.dirname(os.path.abspath(__file__))
14 CHROMIUM_SRC_DIR = os.path.relpath(os.path.join(THIS_DIR, os.pardir, os.pardir))
15 sys.path.append(THIS_DIR)
16 from run_bindgen import filter_clang_args
18 RUST_TOOLCHAIN_DIR = os.path.join(CHROMIUM_SRC_DIR, "third_party",
20 RUSTFMT_EXE_PATH = os.path.join(RUST_TOOLCHAIN_DIR, "bin", "rustfmt")
21 RUSTFMT_CONFIG_PATH = os.path.join(CHROMIUM_SRC_DIR, ".rustfmt.toml")
22 RS_BINDINGS_FROM_CC_EXE_PATH = os.path.join(RUST_TOOLCHAIN_DIR, "bin",
23 "rs_bindings_from_cc")
26 def format_cmdline(args):
28 if ' ' not in x: return x
29 x = x.replace('"', '\\"')
32 return " ".join([quote_arg(x) for x in args])
36 parser = argparse.ArgumentParser()
37 parser.add_argument("--targets_and_args_from_gn",
39 help="File parsed into --targets_and_args Crubit arg",
41 parser.add_argument("--public_headers",
43 help="Passed through to Crubit",
45 parser.add_argument("--rs_out",
47 help="Passed through to Crubit",
49 parser.add_argument("--cc_out",
51 help="Passed through to Crubit",
53 parser.add_argument("clang_args",
55 help="Arguments to forward to clang libraries",
56 nargs=argparse.REMAINDER)
57 args = parser.parse_args()
61 generator_args.append("--rs_out={0}".format(os.path.relpath(args.rs_out)))
62 generator_args.append("--cc_out={0}".format(os.path.relpath(args.cc_out)))
63 if "CRUBIT_DEBUG" in os.environ:
64 generator_args.append("--ir_out={0}".format(
65 os.path.relpath(args.rs_out).replace(".rs", ".ir")))
68 generator_args.append("--public_headers={0}".format(",".join(
69 [os.path.relpath(hdr) for hdr in args.public_headers.split(",")])))
71 # Targets to headers map.
72 with open(args.targets_and_args_from_gn, "r") as f:
73 targets_and_args = json.load(f)
74 for entry in targets_and_args:
75 entry["f"] = ["supported"]
77 for i in range(len(hdrs)):
78 hdrs[i] = os.path.relpath(hdrs[i])
79 generator_args.append("--targets_and_args={0}".format(
80 json.dumps(targets_and_args)))
82 # All Crubit invocations in Chromium share the following cmdline args.
83 generator_args.append(f"--rustfmt_exe_path={RUSTFMT_EXE_PATH}")
84 generator_args.append(f"--rustfmt_config_path={RUSTFMT_CONFIG_PATH}")
85 generator_args.append(
86 "--crubit_support_path=third_party/crubit/src/rs_bindings_from_cc/support"
89 # Long cmdlines may not work - work around that by using Abseil's `--flagfile`
90 # https://abseil.io/docs/python/guides/flags#a-note-about---flagfile
92 # Note that `clang_args` are not written to the flag file, because Abseil's
93 # flag parsing code is only aware of `ABSL_FLAG`-declared flags and doesn't
94 # know about Clang args (e.g. `-W...` or `-I...`).
95 params_file_path = os.path.relpath(args.rs_out).replace(".rs", ".params")
96 with open(params_file_path, "w") as f:
97 for line in generator_args:
102 # The call to `filter_clang_args` is needed to avoid the following error:
103 # error: unable to find plugin 'find-bad-constructs'
105 clang_args.extend(filter_clang_args(args.clang_args))
106 # TODO(crbug.com/1329611): This warning needs to be suppressed, because
107 # otherwise Crubit/Clang complains as follows:
108 # error: .../third_party/rust-toolchain/bin/rs_bindings_from_cc:
109 # 'linker' input unused [-Werror,-Wunused-command-line-argument]
110 # Maybe `build/rust/rs_bindings_from_cc.gni` gives too much in `args`? But
111 # then `{{cflags}}` seems perfectly reasonable...
112 clang_args += ["-Wno-unused-command-line-argument"]
114 # Print a copy&pastable final cmdline when asked for debugging help.
115 cmdline = [RS_BINDINGS_FROM_CC_EXE_PATH, f"--flagfile={params_file_path}"]
116 cmdline.extend(clang_args)
117 if "CRUBIT_DEBUG" in os.environ:
118 pretty_cmdline = format_cmdline(cmdline)
119 print(f"CRUBIT_DEBUG: CMDLINE: {pretty_cmdline}", file=sys.stderr)
121 # TODO(crbug.com/1329611): run_bindgen.py removes the outputs when the tool
122 # fails. Maybe we need to do something similar here? OTOH in most failure
123 # modes Crubit will fail *before* generating its outputs...
124 return subprocess.run(cmdline).returncode
127 if __name__ == '__main__':