mirror of
https://gitee.com/openharmony/third_party_rust_bindgen
synced 2024-12-11 17:14:31 +00:00
Add the --override-abi
option (#2329)
* Add the `--override-abi` option. This option can be used from the CLI with the <abi>:<regex> syntax and it overrides the ABI of a function if it matches <regex>. Fixes #2257
This commit is contained in:
parent
a673a6bc9b
commit
9c32b46048
@ -148,6 +148,8 @@
|
||||
# Unreleased
|
||||
|
||||
## Added
|
||||
* new feature: `--override-abi` flag to override the ABI used by functions
|
||||
matching a regular expression.
|
||||
|
||||
## Changed
|
||||
|
||||
|
@ -568,6 +568,12 @@ where
|
||||
Arg::new("merge-extern-blocks")
|
||||
.long("merge-extern-blocks")
|
||||
.help("Deduplicates extern blocks."),
|
||||
Arg::new("override-abi")
|
||||
.long("override-abi")
|
||||
.help("Overrides the ABI of functions matching <regex>. The <override> value must be of the shape <abi>:<regex> where <abi> can be one of C, stdcall, fastcall, thiscall, aapcs or win64.")
|
||||
.value_name("override")
|
||||
.multiple_occurrences(true)
|
||||
.number_of_values(1),
|
||||
Arg::new("V")
|
||||
.long("version")
|
||||
.help("Prints the version, and exits"),
|
||||
@ -1088,5 +1094,17 @@ where
|
||||
builder = builder.merge_extern_blocks(true);
|
||||
}
|
||||
|
||||
if let Some(abi_overrides) = matches.values_of("override-abi") {
|
||||
for abi_override in abi_overrides {
|
||||
let (regex, abi_str) = abi_override
|
||||
.rsplit_once("=")
|
||||
.expect("Invalid ABI override: Missing `=`");
|
||||
let abi = abi_str
|
||||
.parse()
|
||||
.unwrap_or_else(|err| panic!("Invalid ABI override: {}", err));
|
||||
builder = builder.override_abi(abi, regex);
|
||||
}
|
||||
}
|
||||
|
||||
Ok((builder, output, verbose))
|
||||
}
|
||||
|
16
bindgen-tests/tests/expectations/tests/abi-override.rs
generated
Normal file
16
bindgen-tests/tests/expectations/tests/abi-override.rs
generated
Normal file
@ -0,0 +1,16 @@
|
||||
#![allow(
|
||||
dead_code,
|
||||
non_snake_case,
|
||||
non_camel_case_types,
|
||||
non_upper_case_globals
|
||||
)]
|
||||
|
||||
extern "fastcall" {
|
||||
pub fn foo();
|
||||
}
|
||||
extern "stdcall" {
|
||||
pub fn bar();
|
||||
}
|
||||
extern "C" {
|
||||
pub fn baz();
|
||||
}
|
5
bindgen-tests/tests/headers/abi-override.h
Normal file
5
bindgen-tests/tests/headers/abi-override.h
Normal file
@ -0,0 +1,5 @@
|
||||
// bindgen-flags: --override-abi=foo=fastcall --override-abi=bar=stdcall
|
||||
|
||||
void foo();
|
||||
void bar();
|
||||
void baz();
|
@ -1,5 +1,5 @@
|
||||
use crate::codegen;
|
||||
use crate::ir::function::Abi;
|
||||
use crate::ir::function::ClangAbi;
|
||||
use proc_macro2::Ident;
|
||||
|
||||
/// Used to build the output tokens for dynamic bindings.
|
||||
@ -113,10 +113,10 @@ impl DynamicItems {
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn push(
|
||||
pub(crate) fn push(
|
||||
&mut self,
|
||||
ident: Ident,
|
||||
abi: Abi,
|
||||
abi: ClangAbi,
|
||||
is_variadic: bool,
|
||||
is_required: bool,
|
||||
args: Vec<proc_macro2::TokenStream>,
|
||||
|
@ -32,7 +32,9 @@ use crate::ir::derive::{
|
||||
};
|
||||
use crate::ir::dot;
|
||||
use crate::ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
|
||||
use crate::ir::function::{Abi, Function, FunctionKind, FunctionSig, Linkage};
|
||||
use crate::ir::function::{
|
||||
Abi, ClangAbi, Function, FunctionKind, FunctionSig, Linkage,
|
||||
};
|
||||
use crate::ir::int::IntKind;
|
||||
use crate::ir::item::{IsOpaque, Item, ItemCanonicalName, ItemCanonicalPath};
|
||||
use crate::ir::item_kind::ItemKind;
|
||||
@ -2474,9 +2476,13 @@ impl MethodCodegen for Method {
|
||||
_ => panic!("How in the world?"),
|
||||
};
|
||||
|
||||
let supported_abi = match signature.abi() {
|
||||
Abi::ThisCall => ctx.options().rust_features().thiscall_abi,
|
||||
Abi::Vectorcall => ctx.options().rust_features().vectorcall_abi,
|
||||
let supported_abi = match signature.abi(ctx, Some(&*name)) {
|
||||
ClangAbi::Known(Abi::ThisCall) => {
|
||||
ctx.options().rust_features().thiscall_abi
|
||||
}
|
||||
ClangAbi::Known(Abi::Vectorcall) => {
|
||||
ctx.options().rust_features().vectorcall_abi
|
||||
}
|
||||
_ => true,
|
||||
};
|
||||
|
||||
@ -3988,14 +3994,16 @@ impl TryToRustTy for FunctionSig {
|
||||
// TODO: we might want to consider ignoring the reference return value.
|
||||
let ret = utils::fnsig_return_ty(ctx, self);
|
||||
let arguments = utils::fnsig_arguments(ctx, self);
|
||||
let abi = self.abi();
|
||||
let abi = self.abi(ctx, None);
|
||||
|
||||
match abi {
|
||||
Abi::ThisCall if !ctx.options().rust_features().thiscall_abi => {
|
||||
ClangAbi::Known(Abi::ThisCall)
|
||||
if !ctx.options().rust_features().thiscall_abi =>
|
||||
{
|
||||
warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target");
|
||||
Ok(proc_macro2::TokenStream::new())
|
||||
}
|
||||
Abi::Vectorcall
|
||||
ClangAbi::Known(Abi::Vectorcall)
|
||||
if !ctx.options().rust_features().vectorcall_abi =>
|
||||
{
|
||||
warn!("Skipping function with vectorcall ABI that isn't supported by the configured Rust target");
|
||||
@ -4099,22 +4107,24 @@ impl CodeGenerator for Function {
|
||||
attributes.push(attributes::doc(comment));
|
||||
}
|
||||
|
||||
let abi = match signature.abi() {
|
||||
Abi::ThisCall if !ctx.options().rust_features().thiscall_abi => {
|
||||
let abi = match signature.abi(ctx, Some(name)) {
|
||||
ClangAbi::Known(Abi::ThisCall)
|
||||
if !ctx.options().rust_features().thiscall_abi =>
|
||||
{
|
||||
warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target");
|
||||
return None;
|
||||
}
|
||||
Abi::Vectorcall
|
||||
ClangAbi::Known(Abi::Vectorcall)
|
||||
if !ctx.options().rust_features().vectorcall_abi =>
|
||||
{
|
||||
warn!("Skipping function with vectorcall ABI that isn't supported by the configured Rust target");
|
||||
return None;
|
||||
}
|
||||
Abi::Win64 if signature.is_variadic() => {
|
||||
ClangAbi::Known(Abi::Win64) if signature.is_variadic() => {
|
||||
warn!("Skipping variadic function with Win64 ABI that isn't supported");
|
||||
return None;
|
||||
}
|
||||
Abi::Unknown(unknown_abi) => {
|
||||
ClangAbi::Unknown(unknown_abi) => {
|
||||
panic!(
|
||||
"Invalid or unknown abi {:?} for function {:?} ({:?})",
|
||||
unknown_abi, canonical_name, self
|
||||
@ -4512,7 +4522,7 @@ pub(crate) fn codegen(
|
||||
pub mod utils {
|
||||
use super::{error, ToRustTyOrOpaque};
|
||||
use crate::ir::context::BindgenContext;
|
||||
use crate::ir::function::{Abi, FunctionSig};
|
||||
use crate::ir::function::{Abi, ClangAbi, FunctionSig};
|
||||
use crate::ir::item::{Item, ItemCanonicalPath};
|
||||
use crate::ir::ty::TypeKind;
|
||||
use proc_macro2;
|
||||
@ -4973,10 +4983,10 @@ pub mod utils {
|
||||
// Returns true if `canonical_name` will end up as `mangled_name` at the
|
||||
// machine code level, i.e. after LLVM has applied any target specific
|
||||
// mangling.
|
||||
pub fn names_will_be_identical_after_mangling(
|
||||
pub(crate) fn names_will_be_identical_after_mangling(
|
||||
canonical_name: &str,
|
||||
mangled_name: &str,
|
||||
call_conv: Option<Abi>,
|
||||
call_conv: Option<ClangAbi>,
|
||||
) -> bool {
|
||||
// If the mangled name and the canonical name are the same then no
|
||||
// mangling can have happened between the two versions.
|
||||
@ -4989,13 +4999,13 @@ pub mod utils {
|
||||
let mangled_name = mangled_name.as_bytes();
|
||||
|
||||
let (mangling_prefix, expect_suffix) = match call_conv {
|
||||
Some(Abi::C) |
|
||||
Some(ClangAbi::Known(Abi::C)) |
|
||||
// None is the case for global variables
|
||||
None => {
|
||||
(b'_', false)
|
||||
}
|
||||
Some(Abi::Stdcall) => (b'_', true),
|
||||
Some(Abi::Fastcall) => (b'@', true),
|
||||
Some(ClangAbi::Known(Abi::Stdcall)) => (b'_', true),
|
||||
Some(ClangAbi::Known(Abi::Fastcall)) => (b'@', true),
|
||||
|
||||
// This is something we don't recognize, stay on the safe side
|
||||
// by emitting the `#[link_name]` attribute
|
||||
|
@ -15,6 +15,7 @@ use proc_macro2;
|
||||
use quote;
|
||||
use quote::TokenStreamExt;
|
||||
use std::io;
|
||||
use std::str::FromStr;
|
||||
|
||||
const RUST_DERIVE_FUNPTR_LIMIT: usize = 12;
|
||||
|
||||
@ -170,8 +171,8 @@ impl DotAttributes for Function {
|
||||
}
|
||||
}
|
||||
|
||||
/// An ABI extracted from a clang cursor.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
/// A valid rust ABI.
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
|
||||
pub enum Abi {
|
||||
/// The default C ABI.
|
||||
C,
|
||||
@ -187,32 +188,72 @@ pub enum Abi {
|
||||
Aapcs,
|
||||
/// The "win64" ABI.
|
||||
Win64,
|
||||
/// An unknown or invalid ABI.
|
||||
Unknown(CXCallingConv),
|
||||
}
|
||||
|
||||
impl Abi {
|
||||
/// Returns whether this Abi is known or not.
|
||||
fn is_unknown(&self) -> bool {
|
||||
matches!(*self, Abi::Unknown(..))
|
||||
impl FromStr for Abi {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"C" => Ok(Self::C),
|
||||
"stdcall" => Ok(Self::Stdcall),
|
||||
"fastcall" => Ok(Self::Fastcall),
|
||||
"thiscall" => Ok(Self::ThisCall),
|
||||
"vectorcall" => Ok(Self::Vectorcall),
|
||||
"aapcs" => Ok(Self::Aapcs),
|
||||
"win64" => Ok(Self::Win64),
|
||||
_ => Err(format!("Invalid or unknown ABI {:?}", s)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Abi {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let s = match *self {
|
||||
Self::C => "C",
|
||||
Self::Stdcall => "stdcall",
|
||||
Self::Fastcall => "fastcall",
|
||||
Self::ThisCall => "thiscall",
|
||||
Self::Vectorcall => "vectorcall",
|
||||
Self::Aapcs => "aapcs",
|
||||
Self::Win64 => "win64",
|
||||
};
|
||||
|
||||
s.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl quote::ToTokens for Abi {
|
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||
tokens.append_all(match *self {
|
||||
Abi::C => quote! { "C" },
|
||||
Abi::Stdcall => quote! { "stdcall" },
|
||||
Abi::Fastcall => quote! { "fastcall" },
|
||||
Abi::ThisCall => quote! { "thiscall" },
|
||||
Abi::Vectorcall => quote! { "vectorcall" },
|
||||
Abi::Aapcs => quote! { "aapcs" },
|
||||
Abi::Win64 => quote! { "win64" },
|
||||
Abi::Unknown(cc) => panic!(
|
||||
let abi = self.to_string();
|
||||
tokens.append_all(quote! { #abi });
|
||||
}
|
||||
}
|
||||
|
||||
/// An ABI extracted from a clang cursor.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(crate) enum ClangAbi {
|
||||
Known(Abi),
|
||||
/// An unknown or invalid ABI.
|
||||
Unknown(CXCallingConv),
|
||||
}
|
||||
|
||||
impl ClangAbi {
|
||||
/// Returns whether this Abi is known or not.
|
||||
fn is_unknown(&self) -> bool {
|
||||
matches!(*self, ClangAbi::Unknown(..))
|
||||
}
|
||||
}
|
||||
|
||||
impl quote::ToTokens for ClangAbi {
|
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||
match *self {
|
||||
Self::Known(abi) => abi.to_tokens(tokens),
|
||||
Self::Unknown(cc) => panic!(
|
||||
"Cannot turn unknown calling convention to tokens: {:?}",
|
||||
cc
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -234,21 +275,21 @@ pub struct FunctionSig {
|
||||
must_use: bool,
|
||||
|
||||
/// The ABI of this function.
|
||||
abi: Abi,
|
||||
abi: ClangAbi,
|
||||
}
|
||||
|
||||
fn get_abi(cc: CXCallingConv) -> Abi {
|
||||
fn get_abi(cc: CXCallingConv) -> ClangAbi {
|
||||
use clang_sys::*;
|
||||
match cc {
|
||||
CXCallingConv_Default => Abi::C,
|
||||
CXCallingConv_C => Abi::C,
|
||||
CXCallingConv_X86StdCall => Abi::Stdcall,
|
||||
CXCallingConv_X86FastCall => Abi::Fastcall,
|
||||
CXCallingConv_X86ThisCall => Abi::ThisCall,
|
||||
CXCallingConv_X86VectorCall => Abi::Vectorcall,
|
||||
CXCallingConv_AAPCS => Abi::Aapcs,
|
||||
CXCallingConv_X86_64Win64 => Abi::Win64,
|
||||
other => Abi::Unknown(other),
|
||||
CXCallingConv_Default => ClangAbi::Known(Abi::C),
|
||||
CXCallingConv_C => ClangAbi::Known(Abi::C),
|
||||
CXCallingConv_X86StdCall => ClangAbi::Known(Abi::Stdcall),
|
||||
CXCallingConv_X86FastCall => ClangAbi::Known(Abi::Fastcall),
|
||||
CXCallingConv_X86ThisCall => ClangAbi::Known(Abi::ThisCall),
|
||||
CXCallingConv_X86VectorCall => ClangAbi::Known(Abi::Vectorcall),
|
||||
CXCallingConv_AAPCS => ClangAbi::Known(Abi::Aapcs),
|
||||
CXCallingConv_X86_64Win64 => ClangAbi::Known(Abi::Win64),
|
||||
other => ClangAbi::Unknown(other),
|
||||
}
|
||||
}
|
||||
|
||||
@ -354,25 +395,6 @@ fn args_from_ty_and_cursor(
|
||||
}
|
||||
|
||||
impl FunctionSig {
|
||||
/// Construct a new function signature.
|
||||
pub fn new(
|
||||
return_type: TypeId,
|
||||
argument_types: Vec<(Option<String>, TypeId)>,
|
||||
is_variadic: bool,
|
||||
is_divergent: bool,
|
||||
must_use: bool,
|
||||
abi: Abi,
|
||||
) -> Self {
|
||||
FunctionSig {
|
||||
return_type,
|
||||
argument_types,
|
||||
is_variadic,
|
||||
is_divergent,
|
||||
must_use,
|
||||
abi,
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a new function signature from the given Clang type.
|
||||
pub fn from_ty(
|
||||
ty: &clang::Type,
|
||||
@ -540,20 +562,21 @@ impl FunctionSig {
|
||||
call_conv = cursor_call_conv;
|
||||
}
|
||||
}
|
||||
|
||||
let abi = get_abi(call_conv);
|
||||
|
||||
if abi.is_unknown() {
|
||||
warn!("Unknown calling convention: {:?}", call_conv);
|
||||
}
|
||||
|
||||
Ok(Self::new(
|
||||
ret,
|
||||
args,
|
||||
ty.is_variadic(),
|
||||
Ok(FunctionSig {
|
||||
return_type: ret,
|
||||
argument_types: args,
|
||||
is_variadic: ty.is_variadic(),
|
||||
is_divergent,
|
||||
must_use,
|
||||
abi,
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
/// Get this function signature's return type.
|
||||
@ -567,8 +590,27 @@ impl FunctionSig {
|
||||
}
|
||||
|
||||
/// Get this function signature's ABI.
|
||||
pub fn abi(&self) -> Abi {
|
||||
self.abi
|
||||
pub(crate) fn abi(
|
||||
&self,
|
||||
ctx: &BindgenContext,
|
||||
name: Option<&str>,
|
||||
) -> ClangAbi {
|
||||
// FIXME (pvdrz): Try to do this check lazily instead. Maybe store the ABI inside `ctx`
|
||||
// instead?.
|
||||
if let Some(name) = name {
|
||||
if let Some((abi, _)) = ctx
|
||||
.options()
|
||||
.abi_overrides
|
||||
.iter()
|
||||
.find(|(_, regex_set)| regex_set.matches(name))
|
||||
{
|
||||
ClangAbi::Known(*abi)
|
||||
} else {
|
||||
self.abi
|
||||
}
|
||||
} else {
|
||||
self.abi
|
||||
}
|
||||
}
|
||||
|
||||
/// Is this function signature variadic?
|
||||
@ -598,7 +640,7 @@ impl FunctionSig {
|
||||
return false;
|
||||
}
|
||||
|
||||
matches!(self.abi, Abi::C | Abi::Unknown(..))
|
||||
matches!(self.abi, ClangAbi::Known(Abi::C) | ClangAbi::Unknown(..))
|
||||
}
|
||||
|
||||
pub(crate) fn is_divergent(&self) -> bool {
|
||||
|
@ -74,6 +74,7 @@ pub use crate::features::{
|
||||
RustTarget, LATEST_STABLE_RUST, RUST_TARGET_STRINGS,
|
||||
};
|
||||
use crate::ir::context::{BindgenContext, ItemId};
|
||||
pub use crate::ir::function::Abi;
|
||||
use crate::ir::item::Item;
|
||||
use crate::parse::{ClangItemParser, ParseError};
|
||||
use crate::regex_set::RegexSet;
|
||||
@ -364,6 +365,13 @@ impl Builder {
|
||||
}
|
||||
}
|
||||
|
||||
for (abi, set) in &self.options.abi_overrides {
|
||||
for item in set.get_items() {
|
||||
output_vector.push("--override-abi".to_owned());
|
||||
output_vector.push(format!("{}={}", item, abi));
|
||||
}
|
||||
}
|
||||
|
||||
if !self.options.layout_tests {
|
||||
output_vector.push("--no-layout-tests".into());
|
||||
}
|
||||
@ -1774,6 +1782,16 @@ impl Builder {
|
||||
self.options.c_naming = doit;
|
||||
self
|
||||
}
|
||||
|
||||
/// Override the ABI of a given function. Regular expressions are supported.
|
||||
pub fn override_abi<T: Into<String>>(mut self, abi: Abi, arg: T) -> Self {
|
||||
self.options
|
||||
.abi_overrides
|
||||
.entry(abi)
|
||||
.or_default()
|
||||
.insert(arg.into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration options for generated bindings.
|
||||
@ -2109,11 +2127,13 @@ struct BindgenOptions {
|
||||
|
||||
/// Deduplicate `extern` blocks.
|
||||
merge_extern_blocks: bool,
|
||||
|
||||
abi_overrides: HashMap<Abi, RegexSet>,
|
||||
}
|
||||
|
||||
impl BindgenOptions {
|
||||
fn build(&mut self) {
|
||||
let mut regex_sets = [
|
||||
let regex_sets = [
|
||||
&mut self.allowlisted_vars,
|
||||
&mut self.allowlisted_types,
|
||||
&mut self.allowlisted_functions,
|
||||
@ -2143,7 +2163,7 @@ impl BindgenOptions {
|
||||
&mut self.must_use_types,
|
||||
];
|
||||
let record_matches = self.record_matches;
|
||||
for regex_set in &mut regex_sets {
|
||||
for regex_set in self.abi_overrides.values_mut().chain(regex_sets) {
|
||||
regex_set.build(record_matches);
|
||||
}
|
||||
}
|
||||
@ -2280,6 +2300,7 @@ impl Default for BindgenOptions {
|
||||
vtable_generation: false,
|
||||
sort_semantically: false,
|
||||
merge_extern_blocks: false,
|
||||
abi_overrides: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user