1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// Copyright The pipewire-rs Contributors.
// SPDX-License-Identifier: MIT
use std::env;
use std::path::PathBuf;
fn main() {
let libs = system_deps::Config::new()
.probe()
.expect("Cannot find libraries");
// Tell cargo to invalidate the built crate whenever the wrapper changes
println!("cargo:rerun-if-changed=wrapper.h");
// Write bindings files to the $OUT_DIR/ directory.
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
let builder = bindgen::builder()
.header("wrapper.h")
// Tell cargo to invalidate the built crate whenever any of the
// included header files changed.
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
// Use `usize` for `size_t`. This behavior of bindgen changed because it is not
// *technically* correct, but is the case in all architectures supported by Rust.
.size_t_is_usize(true)
.allowlist_function("spa_.*")
.allowlist_type("spa_.*")
.allowlist_var("SPA_.*")
// These are meant for constructing C structs
// and the generated bindings are wrong
.blocklist_var("SPA_AUDIO_LAYOUT_.*")
// These used to be macros and needed custom wrappers but became inline functions in
// https://gitlab.freedesktop.org/pipewire/pipewire/-/commit/853c4783bcc26beac190991379f257f750a5adac
// and need to be blocklisted to prevent ambiguity when building with that commit
.blocklist_function("spa_meta_bitmap_is_valid")
.blocklist_function("spa_meta_cursor_is_valid")
.prepend_enum_name(false)
.derive_eq(true)
// Some definitions are missing from the generated bindings without this
.clang_macro_fallback()
// Create callable wrapper functions around SPAs `static inline` functions so they
// can be called via FFI
.wrap_static_fns(true)
.wrap_static_fns_suffix("_libspa_rs")
.wrap_static_fns_path(out_path.join("static_fns"));
let builder = libs
.iter()
.iter()
.flat_map(|(_, lib)| lib.include_paths.iter())
.fold(builder, |builder, l| {
let arg = format!("-I{}", l.to_string_lossy());
builder.clang_arg(arg)
});
let bindings = builder.generate().expect("Unable to generate bindings");
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
const FILES: &[&str] = &[
"src/type-info.c",
"src/command.c",
"src/node-command.c",
"src/meta.c",
];
let cc_files = &[
PathBuf::from(FILES[0]),
PathBuf::from(FILES[1]),
PathBuf::from(FILES[2]),
PathBuf::from(FILES[3]),
out_path.join("static_fns.c"),
];
for file in FILES {
println!("cargo:rerun-if-changed={file}");
}
let mut cc = cc::Build::new();
cc.files(cc_files);
cc.include(env!("CARGO_MANIFEST_DIR"));
cc.includes(libs.all_include_paths());
#[cfg(feature = "v0_3_65")]
cc.define("FEATURE_0_3_65", "1");
cc.compile("libspa-rs-reexports");
}