Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce reproducible builds with stable sorting #2003

Merged
merged 3 commits into from Sep 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
40 changes: 11 additions & 29 deletions crates/libs/bindgen/src/functions.rs
Expand Up @@ -26,15 +26,10 @@ fn gen_sys_function(gen: &Gen, def: MethodDef) -> TokenStream {
quote! { #name: #tokens }
});

let calling_convention = calling_convention(gen, def);

quote! {
#[cfg_attr(windows, link(name = "windows"))]
extern #calling_convention {
#doc
#features
pub fn #name(#(#params),*) #return_type;
}
#doc
#features
pub fn #name(#(#params),*) #return_type;
}
}

Expand Down Expand Up @@ -69,7 +64,7 @@ fn gen_win_function(gen: &Gen, def: MethodDef) -> TokenStream {
let cfg = gen.reader.signature_cfg(&signature);
let doc = gen.cfg_doc(&cfg);
let features = gen.cfg_features(&cfg);
let calling_convention = calling_convention(gen, def);
let extern_abi = gen.reader.method_def_extern_abi(def);

let kind = gen.reader.signature_kind(&signature);
match kind {
Expand All @@ -85,7 +80,7 @@ fn gen_win_function(gen: &Gen, def: MethodDef) -> TokenStream {
#[inline]
pub unsafe fn #name<#generics>(#params) -> ::windows::core::Result<T> #where_clause {
#link_attr
extern #calling_convention {
extern #extern_abi {
fn #name(#(#abi_params),*) #abi_return_type;
}
let mut result__ = ::core::option::Option::None;
Expand All @@ -105,7 +100,7 @@ fn gen_win_function(gen: &Gen, def: MethodDef) -> TokenStream {
#[inline]
pub unsafe fn #name<#generics>(#params result__: *mut ::core::option::Option<T>) -> ::windows::core::Result<()> #where_clause {
#link_attr
extern #calling_convention {
extern #extern_abi {
fn #name(#(#abi_params),*) #abi_return_type;
}
#name(#args).ok()
Expand All @@ -125,7 +120,7 @@ fn gen_win_function(gen: &Gen, def: MethodDef) -> TokenStream {
#[inline]
pub unsafe fn #name<#generics>(#params) -> ::windows::core::Result<#return_type_tokens> #where_clause {
#link_attr
extern #calling_convention {
extern #extern_abi {
fn #name(#(#abi_params),*) #abi_return_type;
}
let mut result__ = ::core::mem::MaybeUninit::zeroed();
Expand All @@ -143,7 +138,7 @@ fn gen_win_function(gen: &Gen, def: MethodDef) -> TokenStream {
#[inline]
pub unsafe fn #name<#generics>(#params) -> ::windows::core::Result<()> #where_clause {
#link_attr
extern #calling_convention {
extern #extern_abi {
fn #name(#(#abi_params),*) #abi_return_type;
}
#name(#args).ok()
Expand All @@ -162,7 +157,7 @@ fn gen_win_function(gen: &Gen, def: MethodDef) -> TokenStream {
#[inline]
pub unsafe fn #name<#generics>(#params) -> ::windows::core::Result<#return_type> #where_clause {
#link_attr
extern #calling_convention {
extern #extern_abi {
fn #name(#(#abi_params),*) -> #return_type;
}
let result__ = #name(#args);
Expand All @@ -179,7 +174,7 @@ fn gen_win_function(gen: &Gen, def: MethodDef) -> TokenStream {
#[inline]
pub unsafe fn #name<#generics>(#params) #abi_return_type #where_clause {
#link_attr
extern #calling_convention {
extern #extern_abi {
fn #name(#(#abi_params),*) #abi_return_type;
}
#name(#args)
Expand All @@ -198,7 +193,7 @@ fn gen_win_function(gen: &Gen, def: MethodDef) -> TokenStream {
#[inline]
pub unsafe fn #name<#generics>(#params) #does_not_return #where_clause {
#link_attr
extern #calling_convention {
extern #extern_abi {
fn #name(#(#abi_params),*) #does_not_return;
}
#name(#args)
Expand Down Expand Up @@ -233,16 +228,3 @@ fn handle_last_error(gen: &Gen, def: MethodDef, signature: &Signature) -> bool {
}
false
}

fn calling_convention(gen: &Gen, def: MethodDef) -> &'static str {
let impl_map = gen.reader.method_def_impl_map(def).expect("ImplMap not found");
let flags = gen.reader.impl_map_flags(impl_map);

if flags.conv_platform() {
"system"
} else if flags.conv_cdecl() {
"cdecl"
} else {
unimplemented!()
}
}
20 changes: 0 additions & 20 deletions crates/libs/bindgen/src/gen.rs
Expand Up @@ -14,26 +14,6 @@ impl<'a> Gen<'a> {
Self { reader, namespace: "", sys: false, cfg: false, doc: false, component: false }
}

//
// Definitions
//

pub(crate) fn define(&self, def: TypeDef) -> Option<TokenStream> {
match self.reader.type_def_kind(def) {
TypeKind::Class => {
if self.reader.type_def_flags(def).winrt() {
Some(classes::gen(self, def))
} else {
None
}
}
TypeKind::Interface => Some(interfaces::gen(self, def)),
TypeKind::Enum => Some(enums::gen(self, def)),
TypeKind::Struct => Some(structs::gen(self, def)),
TypeKind::Delegate => Some(delegates::gen(self, def)),
}
}

//
// TypeDef
//
Expand Down
154 changes: 70 additions & 84 deletions crates/libs/bindgen/src/lib.rs
Expand Up @@ -21,97 +21,82 @@ use std::collections::*;
use std::fmt::Write;
use tokens::*;

pub fn define(gen: &Gen, name: &str) -> String {
let mut tokens = String::new();
let type_name = TypeName::parse(name);
pub fn namespace(gen: &Gen, tree: &Tree) -> String {
let mut tokens = TokenStream::new();

for def in gen.reader.get(type_name) {
if let Some(def) = gen.define(def) {
tokens.push_str(def.as_str());
for (name, tree) in &tree.nested {
let name = to_ident(name);
let namespace = tree.namespace[tree.namespace.find('.').unwrap() + 1..].replace('.', "_");
if gen.cfg {
tokens.combine(&quote! { #[cfg(feature = #namespace)] });
}
tokens.combine(&quote! { pub mod #name; });
}

if tokens.is_empty() {
if let Some(apis) = gen.reader.get(TypeName::new(type_name.namespace, "Apis")).next() {
for method in gen.reader.type_def_methods(apis) {
if gen.reader.method_def_name(method) == type_name.name {
tokens.push_str(functions::gen(gen, method).as_str());
let mut functions = BTreeMap::<&str, BTreeMap<&str, TokenStream>>::new();
let mut types = BTreeMap::<TypeKind, BTreeMap<&str, TokenStream>>::new();

for def in gen.reader.namespace_types(tree.namespace) {
let type_name = gen.reader.type_def_type_name(def);
if CORE_TYPES.iter().any(|(x, _)| x == &type_name) {
continue;
}
let name = type_name.name;
let kind = gen.reader.type_def_kind(def);
match kind {
TypeKind::Class => {
if gen.reader.type_def_flags(def).winrt() {
types.entry(kind).or_default().insert(name, classes::gen(gen, def));
} else {
for method in gen.reader.type_def_methods(def) {
let name = gen.reader.method_def_name(method);
let extern_abi = gen.reader.method_def_extern_abi(method);
functions.entry(extern_abi).or_default().entry(name).or_default().combine(&functions::gen(gen, method));
}
for field in gen.reader.type_def_fields(def) {
let name = gen.reader.field_name(field);
types.entry(kind).or_default().entry(name).or_default().combine(&constants::gen(gen, field));
}
}
}
if tokens.is_empty() {
for field in gen.reader.type_def_fields(apis) {
if gen.reader.field_name(field) == type_name.name {
tokens.push_str(constants::gen(gen, field).as_str());
TypeKind::Interface => types.entry(kind).or_default().entry(name).or_default().combine(&interfaces::gen(gen, def)),
TypeKind::Enum => types.entry(kind).or_default().entry(name).or_default().combine(&enums::gen(gen, def)),
TypeKind::Struct => {
if gen.reader.type_def_fields(def).next().is_none() {
if let Some(guid) = gen.reader.type_def_guid(def) {
let value = gen.guid(&guid);
let guid = gen.type_name(&Type::GUID);
let constant = quote! { pub const #name: #guid = #value; };
types.entry(TypeKind::Class).or_default().entry(name).or_default().combine(&constant);
continue;
}
}
types.entry(kind).or_default().entry(name).or_default().combine(&structs::gen(gen, def));
}
TypeKind::Delegate => types.entry(kind).or_default().entry(name).or_default().combine(&delegates::gen(gen, def)),
}
}

assert!(!tokens.is_empty(), "`{}` not found", name);
tokens
}

pub fn namespace(gen: &Gen, tree: &Tree) -> String {
let namespaces = tree.nested.iter().map(move |(name, tree)| {
let name = to_ident(name);
let namespace = tree.namespace[tree.namespace.find('.').unwrap() + 1..].replace('.', "_");
if gen.cfg {
quote! {
#[cfg(feature = #namespace)] pub mod #name;
}
for (extern_abi, functions) in functions {
let functions = functions.values();
if gen.sys {
tokens.combine(&quote! {
#[cfg_attr(windows, link(name = "windows"))]
extern #extern_abi {
#(#functions)*
}
});
} else {
quote! {
pub mod #name;
}
}
});

let mut functions = vec![];

if gen.sys {
if let Some(apis) = gen.reader.get(TypeName::new(tree.namespace, "Apis")).next() {
// TODO: replace with Vec once parity is achieved - BTreeMap just used to make diffing simpler.
let mut methods = BTreeMap::new();
for method in gen.reader.type_def_methods(apis) {
combine(&mut methods, gen.reader.method_def_name(method), functions::gen(gen, method));
}
// TODO: instead of Vec just check whether class has `Apis` methods and then pass an iterator?
if !methods.is_empty() {
let methods = methods.values();
functions = vec![quote! {
#(#methods)*
}];
}
tokens.combine(&quote! {
#(#functions)*
});
}
}

// TODO: replace with Vec once parity is achieved - BTreeMap just used to make diffing simpler.
let mut types = BTreeMap::<&str, TokenStream>::new();

for def in gen.reader.namespace_types(tree.namespace) {
if let Some(tokens) = gen.define(def) {
combine_type(&mut types, gen.reader.type_def_type_name(def), tokens);
} else {
if !gen.sys {
for method in gen.reader.type_def_methods(def) {
combine(&mut types, gen.reader.method_def_name(method), functions::gen(gen, method));
}
}
for field in gen.reader.type_def_fields(def) {
combine(&mut types, gen.reader.field_name(field), constants::gen(gen, field));
}
}
for ty in types.values().flat_map(|v| v.values()) {
tokens.combine(ty);
}

let types = types.values();

let mut tokens = quote! {
#(#namespaces)*
#(#functions)*
#(#types)*
};

if tree.namespace == "Windows.Win32.UI.WindowsAndMessaging" {
tokens.combine(&quote! {
#[cfg(target_pointer_width = "32")]
Expand All @@ -136,7 +121,18 @@ pub fn namespace_impl(gen: &Gen, tree: &Tree) -> String {
let mut types = BTreeMap::<&str, TokenStream>::new();

for def in gen.reader.namespace_types(tree.namespace) {
combine_type(&mut types, gen.reader.type_def_type_name(def), implements::gen(gen, def));
let type_name = gen.reader.type_def_type_name(def);
if CORE_TYPES.iter().any(|(x, _)| x == &type_name) {
continue;
}
if gen.reader.type_def_kind(def) != TypeKind::Interface {
continue;
}
let tokens = implements::gen(gen, def);

if !tokens.is_empty() {
types.insert(type_name.name, tokens);
}
}

let types = types.values();
Expand All @@ -159,16 +155,6 @@ pub fn component(namespace: &str, files: &[File]) -> String {
bindings
}

fn combine<'a>(types: &mut BTreeMap<&'a str, TokenStream>, name: &'a str, tokens: TokenStream) {
types.entry(name).or_default().combine(&tokens);
}

fn combine_type<'a>(types: &mut BTreeMap<&'a str, TokenStream>, type_name: TypeName<'a>, tokens: TokenStream) {
if !CORE_TYPES.iter().any(|(x, _)| x == &type_name) {
types.entry(type_name.name).or_default().combine(&tokens);
}
}

/// Expand a possibly empty generics list with a new generic
fn expand_generics(generics: TokenStream, new: TokenStream) -> TokenStream {
if generics.is_empty() {
Expand Down
6 changes: 1 addition & 5 deletions crates/libs/bindgen/src/structs.rs
Expand Up @@ -22,11 +22,7 @@ fn gen_struct_with_name(gen: &Gen, def: TypeDef, struct_name: &str, cfg: &Cfg) -
let name = to_ident(struct_name);

if gen.reader.type_def_fields(def).next().is_none() {
if let Some(guid) = gen.reader.type_def_guid(def) {
let value = gen.guid(&guid);
let guid = gen.type_name(&Type::GUID);
return quote! { pub const #name: #guid = #value; };
} else if name.as_str().ends_with("Vtbl") {
if name.as_str().ends_with("Vtbl") {
// This just omits some useless struct declarations like `IDDVideoPortContainerVtbl`
return quote! {};
} else {
Expand Down
14 changes: 13 additions & 1 deletion crates/libs/metadata/src/reader/mod.rs
Expand Up @@ -93,7 +93,7 @@ pub enum AsyncKind {
OperationWithProgress,
}

#[derive(PartialEq, Eq, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord)]
pub enum TypeKind {
Interface,
Class,
Expand Down Expand Up @@ -585,6 +585,18 @@ impl<'a> Reader<'a> {

Signature { def: row, params, return_type }
}
pub fn method_def_extern_abi(&self, def: MethodDef) -> &'static str {
let impl_map = self.method_def_impl_map(def).expect("ImplMap not found");
let flags = self.impl_map_flags(impl_map);

if flags.conv_platform() {
"system"
} else if flags.conv_cdecl() {
"cdecl"
} else {
unimplemented!()
}
}
pub fn method_def_size(&self, method: MethodDef) -> usize {
let signature = self.method_def_signature(method, &[]);
signature.params.iter().fold(0, |sum, param| sum + std::cmp::max(4, self.type_size(&param.ty)))
Expand Down