1#!/usr/bin/env python3 2 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. 6 7import argparse 8import contextlib 9import os 10import subprocess 11import sys 12 13# Set up path to be able to import action_helpers. 14sys.path.append( 15 os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir, 16 os.pardir, 'build')) 17import action_helpers 18 19from filter_clang_args import filter_clang_args 20 21 22def main(): 23 parser = argparse.ArgumentParser("run_bindgen.py") 24 parser.add_argument("--exe", help="Path to bindgen", required=True), 25 parser.add_argument("--header", 26 help="C header file to generate bindings for", 27 required=True) 28 parser.add_argument("--depfile", 29 help="depfile to output with header dependencies") 30 parser.add_argument("--output", help="output .rs bindings", required=True) 31 parser.add_argument( 32 "--wrap-static-fns", 33 help="output source file for `static` and `static inline` functions") 34 parser.add_argument("--ld-library-path", 35 help="LD_LIBRARY_PATH (or DYLD_LIBRARY_PATH on Mac) to " 36 "set") 37 parser.add_argument("--libclang-path", 38 help="Path to the libclang shared libray.") 39 parser.add_argument("-I", "--include", help="include path", action="append") 40 parser.add_argument("--bindgen-flags", 41 help="flags to pass to bindgen", 42 nargs="*") 43 parser.add_argument( 44 "clangargs", 45 metavar="CLANGARGS", 46 help="arguments to pass to libclang (see " 47 "https://docs.rs/bindgen/latest/bindgen/struct.Builder.html#method.clang_args)", 48 nargs="*") 49 args = parser.parse_args() 50 51 # Abort if `TARGET` exists in the environment. Cargo sets `TARGET` when 52 # running build scripts and bindgen will try to be helpful by using that value 53 # if it's set. In practice we've seen a case where someone had the value set 54 # in their build environment with no intention of it reaching bindgen, leading 55 # to a hard-to-debug build error. 56 if 'TARGET' in os.environ: 57 sys.exit('ERROR: saw TARGET in environment, remove to avoid bindgen' 58 ' failures') 59 60 with contextlib.ExitStack() as stack: 61 # Args passed to the actual bindgen cli 62 genargs = [] 63 genargs.append('--no-layout-tests') 64 if args.bindgen_flags is not None: 65 for flag in args.bindgen_flags: 66 genargs.append("--" + flag) 67 68 # TODO(danakj): We need to point bindgen to 69 # //third_party/rust-toolchain/bin/rustfmt. 70 genargs.append('--no-rustfmt-bindings') 71 genargs += ['--rust-target', 'nightly'] 72 73 if args.depfile: 74 depfile = stack.enter_context(action_helpers.atomic_output(args.depfile)) 75 genargs.append('--depfile') 76 genargs.append(depfile.name) 77 # Ideally we would use action_helpers.atomic_output for the output file, but 78 # this would put the wrong name in the depfile. 79 genargs.append('--output') 80 genargs.append(args.output) 81 82 # The GN rules know what path to find the system headers in, and we want to 83 # use the headers we specify, instead of non-hermetic headers from elsewhere 84 # in the system. 85 genargs.append('--no-include-path-detection') 86 87 if args.wrap_static_fns: 88 wrap_static_fns = stack.enter_context( 89 action_helpers.atomic_output(args.wrap_static_fns)) 90 genargs.append('--experimental') 91 genargs.append('--wrap-static-fns') 92 genargs.append('--wrap-static-fns-path') 93 genargs.append(wrap_static_fns.name) 94 genargs.append(args.header) 95 genargs.append('--') 96 genargs.extend(filter_clang_args(args.clangargs)) 97 env = os.environ 98 if args.ld_library_path: 99 if sys.platform == 'darwin': 100 env["DYLD_LIBRARY_PATH"] = args.ld_library_path 101 else: 102 env["LD_LIBRARY_PATH"] = args.ld_library_path 103 if args.libclang_path: 104 env["LIBCLANG_PATH"] = args.libclang_path 105 try: 106 subprocess.check_call([args.exe, *genargs], env=env) 107 except: 108 # Make sure we don't emit anything if bindgen failed. The other files use 109 # action_helpers for this. 110 try: 111 os.remove(args.output) 112 except FileNotFoundError: 113 pass 114 raise 115 116 117if __name__ == '__main__': 118 main() 119