blob: 353874ccc3a55e6c93b81db87712f163b1b9bfa3 [file] [log] [blame] [edit]
#!/usr/bin/env fuchsia-vendored-python
# Copyright 2023 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import os
import re
import subprocess
import sys
import datetime
# All other paths are relative to here (main changes to this directory on startup).
ROOT_PATH = os.path.join(os.path.dirname(__file__), "..", "..", "..")
RUST_DIR = "prebuilt/third_party/rust/linux-x64/bin"
BINDGEN_PATH = "prebuilt/third_party/rust_bindgen/linux-x64/bindgen"
FX_PATH = "scripts/fx"
GENERATED_FILE_HEADER = (
"""// Copyright %d The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#![allow(dead_code)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
"""
% datetime.datetime.now().year
)
class Bindgen:
def __init__(self):
self.clang_target = "x86_64-pc-linux-gnu"
self.c_types_prefix = ""
self.raw_lines = ""
self.opaque_types = []
self.include_dirs = []
self.auto_derive_traits = []
self.replacements = []
self.ignore_functions = False
self.function_allowlist = []
self.var_allowlist = []
self.type_allowlist = []
self.no_debug_types = []
self.no_copy_types = []
def set_auto_derive_traits(self, traits_map):
self.auto_derive_traits = [(re.compile(x[0]), x[1]) for x in traits_map]
def set_replacements(self, replacements):
self.replacements = [(re.compile(x[0]), x[1]) for x in replacements]
def run_bindgen(self, input_file, output_file):
# Bindgen arguments.
args = [
BINDGEN_PATH,
"--no-layout-tests",
"--with-derive-default",
"--explicit-padding",
"--raw-line",
GENERATED_FILE_HEADER + self.raw_lines,
"-o",
output_file,
]
if self.ignore_functions:
args.append("--ignore-functions")
if self.c_types_prefix:
args.append("--ctypes-prefix=" + self.c_types_prefix)
args += ["--allowlist-function=" + x for x in self.function_allowlist]
args += ["--allowlist-var=" + x for x in self.var_allowlist]
args += ["--allowlist-type=" + x for x in self.type_allowlist]
args += ["--opaque-type=" + x for x in self.opaque_types]
args += ["--no-debug=" + x for x in self.no_debug_types]
args += ["--no-copy=" + x for x in self.no_copy_types]
args += [input_file]
# Clang arguments (after the "--").
args += [
"--",
"-target",
self.clang_target,
"-nostdlibinc",
"-D__Fuchsia_API_level__=4294967295",
"-DIS_BINDGEN=1",
]
for i in self.include_dirs:
args += ["-I", i]
args += ["-I", "."]
# Need to set the PATH to the prebuilt binary location for it to find rustfmt.
env = os.environ.copy()
env["PATH"] = "%s:%s" % (os.path.abspath(RUST_DIR), env["PATH"])
subprocess.check_call(args, env=env)
def get_auto_derive_traits(self, line):
"""Returns true if the given line defines a Rust structure with a name
matching any of the types we need to add FromBytes."""
if not (
line.startswith("pub struct ") or line.startswith("pub union ")
):
return None
# The third word (after the "pub struct") is the type name.
split = re.split("[ <\(]", line)
if len(split) < 3:
return None
type_name = split[2]
for t, traits in self.auto_derive_traits:
if t.match(type_name):
return traits
return None
def post_process_rust_file(self, rust_file_name):
with open(rust_file_name, "r+") as source_file:
input_lines = source_file.readlines()
output_lines = []
for line in input_lines:
extra_traits = self.get_auto_derive_traits(line)
if extra_traits:
# Parse existing traits, if any.
if len(output_lines) > 0 and output_lines[-1].startswith(
"#[derive("
):
traits = output_lines[-1][9:-3].split(", ")
traits.extend(
x for x in extra_traits if x not in traits
)
output_lines.pop()
else:
traits = extra_traits
output_lines.append(
"#[derive(" + ", ".join(traits) + ")]\n"
)
output_lines.append(line)
text = "".join(output_lines)
for regexp, replacement in self.replacements:
text = regexp.sub(replacement, text)
source_file.seek(0)
source_file.write(text)
def run(self, input_file, rust_file):
os.chdir(ROOT_PATH)
self.run_bindgen(input_file, rust_file)
self.post_process_rust_file(rust_file)
subprocess.check_call([FX_PATH, "format-code", "--files=" + rust_file])