Skip to content

Commit

Permalink
Introduce reproducible builds with stable sorting (#2003)
Browse files Browse the repository at this point in the history
  • Loading branch information
kennykerr committed Sep 6, 2022
1 parent 874960a commit 13d0062
Show file tree
Hide file tree
Showing 826 changed files with 1,673,270 additions and 1,723,921 deletions.
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

0 comments on commit 13d0062

Please sign in to comment.