blob: a07d4cf811805fe561b8df033daa7599a2d88fff [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])