run_rs_bindings_from_cc.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. #!/usr/bin/env python3
  2. # Copyright 2022 The Chromium Authors. All rights reserved.
  3. # Use of this source code is governed by a BSD-style license that can be
  4. # found in the LICENSE file.
  5. import argparse
  6. import json
  7. import os
  8. import subprocess
  9. import sys
  10. # Set up path to be able to import build_utils.
  11. THIS_DIR = os.path.dirname(os.path.abspath(__file__))
  12. CHROMIUM_SRC_DIR = os.path.relpath(os.path.join(THIS_DIR, os.pardir, os.pardir))
  13. sys.path.append(THIS_DIR)
  14. sys.path.append(os.path.join(CHROMIUM_SRC_DIR, 'build', 'android', 'gyp'))
  15. from run_bindgen import filter_clang_args
  16. from util import build_utils
  17. RUST_TOOLCHAIN_DIR = os.path.join(CHROMIUM_SRC_DIR, "third_party",
  18. "rust-toolchain")
  19. RUSTFMT_EXE_PATH = os.path.join(RUST_TOOLCHAIN_DIR, "bin", "rustfmt")
  20. RUSTFMT_CONFIG_PATH = os.path.join(CHROMIUM_SRC_DIR, ".rustfmt.toml")
  21. RS_BINDINGS_FROM_CC_EXE_PATH = os.path.join(RUST_TOOLCHAIN_DIR, "bin",
  22. "rs_bindings_from_cc")
  23. def format_cmdline(args):
  24. def quote_arg(x):
  25. if ' ' not in x: return x
  26. x = x.replace('"', '\\"')
  27. return f"\"{x}\""
  28. return " ".join([quote_arg(x) for x in args])
  29. def main():
  30. parser = argparse.ArgumentParser()
  31. parser.add_argument("--targets_and_headers_from_gn",
  32. metavar="FILE",
  33. help="File parsed into --targets_and_headers Crubit arg",
  34. required=True),
  35. parser.add_argument("--public_headers",
  36. metavar="FILE",
  37. help="Passed through to Crubit",
  38. required=True),
  39. parser.add_argument("--rs_out",
  40. metavar="FILE",
  41. help="Passed through to Crubit",
  42. required=True),
  43. parser.add_argument("--cc_out",
  44. metavar="FILE",
  45. help="Passed through to Crubit",
  46. required=True),
  47. parser.add_argument("clang_args",
  48. metavar="CLANGARGS",
  49. help="Arguments to forward to clang libraries",
  50. nargs=argparse.REMAINDER)
  51. args = parser.parse_args()
  52. # Output paths
  53. generator_args = []
  54. generator_args.append("--rs_out={0}".format(os.path.relpath(args.rs_out)))
  55. generator_args.append("--cc_out={0}".format(os.path.relpath(args.cc_out)))
  56. if "CRUBIT_DEBUG" in os.environ:
  57. generator_args.append("--ir_out={0}".format(
  58. os.path.relpath(args.rs_out).replace(".rs", ".ir")))
  59. # Public headers.
  60. generator_args.append("--public_headers={0}".format(",".join(
  61. [os.path.relpath(hdr) for hdr in args.public_headers.split(",")])))
  62. # Targets to headers map.
  63. with open(args.targets_and_headers_from_gn, "r") as f:
  64. targets_and_headers = json.load(f)
  65. for entry in targets_and_headers:
  66. hdrs = entry["h"]
  67. for i in range(len(hdrs)):
  68. hdrs[i] = os.path.relpath(hdrs[i])
  69. generator_args.append("--targets_and_headers={0}".format(
  70. json.dumps(targets_and_headers)))
  71. # All Crubit invocations in Chromium share the following cmdline args.
  72. generator_args.append(f"--rustfmt_exe_path={RUSTFMT_EXE_PATH}")
  73. generator_args.append(f"--rustfmt_config_path={RUSTFMT_CONFIG_PATH}")
  74. generator_args.append(
  75. "--crubit_support_path=third_party/crubit/src/rs_bindings_from_cc/support"
  76. )
  77. # Long cmdlines may not work - work around that by using Abseil's `--flagfile`
  78. # https://abseil.io/docs/python/guides/flags#a-note-about---flagfile
  79. #
  80. # Note that `clang_args` are not written to the flag file, because Abseil's
  81. # flag parsing code is only aware of `ABSL_FLAG`-declared flags and doesn't
  82. # know about Clang args (e.g. `-W...` or `-I...`).
  83. params_file_path = os.path.relpath(args.rs_out).replace(".rs", ".params")
  84. with open(params_file_path, "w") as f:
  85. for line in generator_args:
  86. print(line, file=f)
  87. # Clang arguments.
  88. #
  89. # The call to `filter_clang_args` is needed to avoid the following error:
  90. # error: unable to find plugin 'find-bad-constructs'
  91. clang_args = []
  92. clang_args.extend(filter_clang_args(args.clang_args))
  93. # TODO(crbug.com/1329611): This warning needs to be suppressed, because
  94. # otherwise Crubit/Clang complains as follows:
  95. # error: .../third_party/rust-toolchain/bin/rs_bindings_from_cc:
  96. # 'linker' input unused [-Werror,-Wunused-command-line-argument]
  97. # Maybe `build/rust/rs_bindings_from_cc.gni` gives too much in `args`? But
  98. # then `{{cflags}}` seems perfectly reasonable...
  99. clang_args += ["-Wno-unused-command-line-argument"]
  100. # Print a copy&pastable final cmdline when asked for debugging help.
  101. cmdline = [RS_BINDINGS_FROM_CC_EXE_PATH, f"--flagfile={params_file_path}"]
  102. cmdline.extend(clang_args)
  103. if "CRUBIT_DEBUG" in os.environ:
  104. pretty_cmdline = format_cmdline(cmdline)
  105. print(f"CRUBIT_DEBUG: CMDLINE: {pretty_cmdline}", file=sys.stderr)
  106. # TODO(crbug.com/1329611): run_bindgen.py removes the outputs when the tool
  107. # fails. Maybe we need to do something similar here? OTOH in most failure
  108. # modes Crubit will fail *before* generating its outputs...
  109. return subprocess.run(cmdline).returncode
  110. if __name__ == '__main__':
  111. sys.exit(main())