Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions crates/libs/bindgen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ mod type_name;
mod type_tree;
mod types;
mod value;
mod warnings;
mod winmd;
mod writer;

Expand All @@ -44,6 +45,7 @@ use type_name::*;
use type_tree::*;
use types::*;
use value::*;
pub use warnings::*;
use winmd::*;
use writer::*;
mod method_names;
Expand All @@ -64,11 +66,12 @@ struct Config {
pub implement: bool,
pub derive: Derive,
pub link: String,
pub warnings: WarningBuilder,
}

/// The Windows code generator.
#[track_caller]
pub fn bindgen<I, S>(args: I)
pub fn bindgen<I, S>(args: I) -> Warnings
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
Expand Down Expand Up @@ -201,6 +204,7 @@ where
sys,
implement,
link,
warnings: WarningBuilder::default(),
};

let tree = TypeTree::new(&config.types);
Expand All @@ -210,7 +214,8 @@ where
namespace: "",
};

writer.write(tree)
writer.write(tree);
config.warnings.build()
}

enum ArgKind {
Expand Down
5 changes: 5 additions & 0 deletions crates/libs/bindgen/src/types/cpp_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ impl CppInterface {
if method.dependencies.included(writer.config) {
CppMethodOrName::Method(method)
} else {
writer.config.warnings.skip_method(
method.def,
&method.dependencies,
writer.config,
);
CppMethodOrName::Name(method.def)
}
})
Expand Down
5 changes: 5 additions & 0 deletions crates/libs/bindgen/src/types/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ impl Interface {
if method.dependencies.included(writer.config) {
MethodOrName::Method(method)
} else {
writer.config.warnings.skip_method(
method.def,
&method.dependencies,
writer.config,
);
MethodOrName::Name(method.def)
}
})
Expand Down
65 changes: 65 additions & 0 deletions crates/libs/bindgen/src/warnings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
use super::*;
use std::sync::RwLock;

#[derive(Default)]
pub(crate) struct WarningBuilder(RwLock<Vec<String>>);

impl WarningBuilder {
pub fn build(self) -> Warnings {
Warnings(self.0.write().unwrap().split_off(0))
}

pub fn add(&self, message: String) {
self.0.write().unwrap().push(message);
}

pub fn skip_method(&self, method: MethodDef, dependencies: &TypeMap, config: &Config) {
let mut message = String::new();
writeln!(
&mut message,
"skipping `{}.{}` due to missing dependencies:",
method.parent().type_name(),
method.name()
)
.unwrap();

for tn in dependencies.keys() {
if !config.types.contains_key(tn) && config.references.contains(*tn).is_none() {
writeln!(&mut message, " {tn}").unwrap();
}
}

self.add(message);
}
}

/// Contains warnings collected during code generation.
#[derive(Debug)]
pub struct Warnings(Vec<String>);

impl Warnings {
/// Panics if any warnings are present.
#[track_caller]
pub fn unwrap(&self) {
if !self.is_empty() {
panic!("{self}");
}
}
}

impl std::fmt::Display for Warnings {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for message in &self.0 {
write!(f, "{message}")?;
}
Ok(())
}
}

impl std::ops::Deref for Warnings {
type Target = Vec<String>;

fn deref(&self) -> &Self::Target {
&self.0
}
}
7 changes: 7 additions & 0 deletions crates/libs/bindgen/src/winmd/codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@ code! { MemberRefParent(3)
}

impl MemberRefParent {
pub fn type_name(&self) -> TypeName {
match self {
Self::TypeDef(row) => row.type_name(),
Self::TypeRef(row) => row.type_name(),
}
}

pub fn name(&self) -> &'static str {
match self {
Self::TypeDef(row) => row.name(),
Expand Down
33 changes: 31 additions & 2 deletions crates/tests/bindgen/tests/panic.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#[track_caller]
fn bindgen(args: &str) {
windows_bindgen::bindgen(args.split_whitespace());
fn bindgen(args: &str) -> windows_bindgen::Warnings {
windows_bindgen::bindgen(args.split_whitespace())
}

#[test]
Expand Down Expand Up @@ -151,3 +151,32 @@ fn failed_to_write_file() {

bindgen(&format!("--out {test_path} --in default --filter POINT",));
}

#[test]
#[should_panic(
expected = "skipping `Windows.Win32.System.Com.IPersistFile.Load` due to missing dependencies:\n Windows.Win32.System.Com.STGM"
)]
fn skip_cpp_method() {
let mut path = std::env::temp_dir();
path.push("skip_cpp_method");

windows_bindgen::bindgen(["--out", &path.to_string_lossy(), "--filter", "IPersistFile"])
.unwrap();
}

#[test]
#[should_panic(
expected = "skipping `Windows.Foundation.IMemoryBuffer.CreateReference` due to missing dependencies:\n Windows.Foundation.IMemoryBufferReference"
)]
fn skip_method() {
let mut path = std::env::temp_dir();
path.push("skip_method");

windows_bindgen::bindgen([
"--out",
&path.to_string_lossy(),
"--filter",
"IMemoryBuffer",
])
.unwrap();
}
23 changes: 12 additions & 11 deletions crates/tools/bindings/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@ use windows_bindgen::*;
fn main() {
let time = std::time::Instant::now();

bindgen(["--etc", "crates/tools/bindings/src/async.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/async_impl.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/collections.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/core_com.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/core.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/metadata.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/numerics.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/registry.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/result.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/strings.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/async.txt"]).unwrap();
bindgen(["--etc", "crates/tools/bindings/src/async_impl.txt"]).unwrap();
bindgen(["--etc", "crates/tools/bindings/src/collections.txt"]).unwrap();
bindgen(["--etc", "crates/tools/bindings/src/core_com.txt"]).unwrap();
bindgen(["--etc", "crates/tools/bindings/src/core.txt"]).unwrap();
bindgen(["--etc", "crates/tools/bindings/src/metadata.txt"]).unwrap();
bindgen(["--etc", "crates/tools/bindings/src/numerics.txt"]).unwrap();
bindgen(["--etc", "crates/tools/bindings/src/registry.txt"]).unwrap();
bindgen(["--etc", "crates/tools/bindings/src/result.txt"]).unwrap();
bindgen(["--etc", "crates/tools/bindings/src/strings.txt"]).unwrap();
bindgen(["--etc", "crates/tools/bindings/src/version.txt"]).unwrap();

bindgen(["--etc", "crates/tools/bindings/src/sys.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/version.txt"]);
bindgen(["--etc", "crates/tools/bindings/src/windows.txt"]);

println!("Finished in {:.2}s", time.elapsed().as_secs_f32());
Expand Down