1 # Copyright 2022 The Chromium Authors
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 import("//build/config/clang/clang.gni")
6 import("//build/config/rust.gni")
7 import("//build/config/sysroot.gni")
8 import("//build/rust/rust_static_library.gni")
11 import("//build/toolchain/win/win_toolchain_data.gni")
14 _bindgen_path = "${rust_bindgen_root}/bin/bindgen"
15 if (host_os == "win") {
16 _bindgen_path = "${_bindgen_path}.exe"
19 # On Windows, the libclang.dll is beside the bindgen.exe, otherwise it is in
21 _libclang_path = rust_bindgen_root
22 if (host_os == "win") {
23 _libclang_path += "/bin"
25 _libclang_path += "/lib"
28 # Template to build Rust/C bindings with bindgen.
30 # This template expands to a static_library containing the Rust side of the
31 # bindings. Simply treat it as a public dependency.
36 # The .h file to generate bindings for.
39 # C targets on which the headers depend in order to build successfully.
42 # C compilation targets determine the correct list of -D and -I flags based
43 # on their dependencies and any configs applied. The same applies here. Set
44 # any configs here as if this were a C target.
46 # bindgen_flags: (optional)
47 # the additional bindgen flags which are passed to the executable
49 # Rust targets depending on the output must include! the generated file.
51 template("rust_bindgen") {
52 assert(defined(invoker.header),
53 "Must specify the C header file to make bindings for.")
55 # bindgen relies on knowing the {{defines}} and {{include_dirs}} required
56 # to build the C++ headers which it's parsing. These are passed to the
57 # script's args and are populated using deps and configs.
58 forward_variables_from(invoker,
59 TESTONLY_AND_VISIBILITY + [
64 sources = [ invoker.header ]
66 if (!defined(configs)) {
70 # Several important compiler flags come from default_compiler_configs
71 configs += default_compiler_configs
73 output_dir = "$target_gen_dir"
74 out_gen_rs = "$output_dir/${target_name}.rs"
76 script = rebase_path("//build/rust/run_bindgen.py")
77 inputs = [ _bindgen_path ]
79 depfile = "$target_out_dir/${target_name}.d"
80 outputs = [ out_gen_rs ]
84 rebase_path(_bindgen_path, root_build_dir),
86 rebase_path(invoker.header, root_build_dir),
88 rebase_path(depfile, root_build_dir),
90 rebase_path(out_gen_rs, root_build_dir),
92 rebase_path(_libclang_path, root_build_dir),
96 # Linux clang, and clang libs, use a shared libstdc++, which we must
100 rebase_path(clang_base_path + "/lib", root_build_dir),
104 if (defined(invoker.bindgen_flags)) {
105 args += [ "--bindgen-flags" ]
106 foreach(flag, invoker.bindgen_flags) {
119 # libclang will run the system `clang` to find the "resource dir" which it
120 # places before the directory specified in `-isysroot`.
121 # https://github.com/llvm/llvm-project/blob/699e0bed4bfead826e210025bf33e5a1997c018b/clang/lib/Tooling/Tooling.cpp#L499-L510
123 # This means include files are pulled from the wrong place if the `clang`
124 # says the wrong thing. We point it to our clang's resource dir which will
125 # make it behave consistently with our other command line flags and allows
126 # system headers to be found.
128 rebase_path(clang_base_path + "/lib/clang/" + clang_version,
136 # On Windows we fall back to using system headers from a sysroot from
137 # depot_tools. This is negotiated by python scripts and the result is
138 # available in //build/toolchain/win/win_toolchain_data.gni. From there
139 # we get the `include_flags_imsvc` which point to the system headers.
140 if (host_cpu == "x86") {
141 win_toolchain_data = win_toolchain_data_x86
142 } else if (host_cpu == "x64") {
143 win_toolchain_data = win_toolchain_data_x64
144 } else if (host_cpu == "arm64") {
145 win_toolchain_data = win_toolchain_data_arm64
147 error("Unsupported host_cpu, add it to win_toolchain_data.gni")
149 args += win_toolchain_data.include_flags_imsvc_list
152 # Passes C comments through as rustdoc attributes.
154 args += [ "/clang:-fparse-all-comments" ]
156 args += [ "-fparse-all-comments" ]
159 # Default configs include "-fvisibility=hidden", and for some reason this
160 # causes bindgen not to emit function bindings. Override it.
162 args += [ "-fvisibility=default" ]
166 # We pass MSVC style flags to clang on Windows, and libclang needs to be
167 # told explicitly to accept them.
168 args += [ "--driver-mode=cl" ]
170 # On Windows, libclang adds arguments that it then fails to understand.
171 # -fno-spell-checking
172 # -fallow-editor-placeholders
173 # These should not cause bindgen to fail.
174 args += [ "-Wno-unknown-argument" ]
176 # Replace these two arguments with a version that clang-cl can parse.
178 "/clang:-fno-spell-checking",
179 "/clang:-fallow-editor-placeholders",
184 # LLVM searches for a default CFI ignorelist at (exactly)
185 # $(cwd)/lib/clang/$(llvm_version)/share/cfi_ignorelist.txt
186 # Even if we provide a custom -fsanitize-ignorelist, the absence
187 # of this default file will cause a fatal error. clang finds
188 # it within third_party/llvm-build, but for bindgen our cwd
189 # is the $out_dir. We _could_ create this file at the right
190 # location within the outdir using a "copy" target, but as
191 # we don't actually generate code within bindgen, the easier
192 # option is to tell bindgen to ignore all CFI ignorelists.
193 args += [ "-fno-sanitize-ignorelist" ]