Skip to content

Commit df955e6

Browse files
MarijnS95claude
andcommitted
Move bindgen generation from build.rs to api_gen binary
Replace the `generate-bindings` feature + build.rs approach with a dedicated `api_gen` workspace member binary, following the pattern used by fidelityfx-rs. Bindings are generated by running `cargo r -p api_gen` instead of `cargo b -Fgenerate-bindings`. This pins bindgen to =0.72.1 for reproducible output and removes the build-dependency from the published crate. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent fc4c14e commit df955e6

5 files changed

Lines changed: 54 additions & 26 deletions

File tree

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,12 @@ jobs:
5454
src/xess/vk.rs
5555
src/xess/xess.rs
5656
- name: Generate
57-
run: cargo b -Fgenerate-bindings
57+
run: cargo r -p api_gen
5858
- name: Upload crate source
5959
uses: actions/upload-artifact@v6
6060
with:
6161
name: crate-source
6262
path: src/
6363
- name: Diff generated Rust code
6464
shell: bash
65-
run: test -z "$(git status --porcelain)" || (echo "::error::Generated files are different, please regenerate with cargo b -Fgenerate-bindings!"; git status; false)
65+
run: test -z "$(git status --porcelain)" || (echo "::error::Generated files are different, please regenerate with 'cargo r -p api_gen'!"; git status; false)

Cargo.toml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
[workspace]
2+
members = ["api_gen"]
3+
14
[package]
25
name = "xess-sys"
36
version = "0.1.0"
@@ -12,7 +15,7 @@ categories = ["external-ffi-bindings", "graphics", "rendering"]
1215
keywords = ["Intel", "XeSS", "XeLL", "frame generation", "upscaling"]
1316
rust-version = "1.74"
1417

15-
# Headers contain a sequence of characters which are incorrectly interpreted as a doctest, these obviously fail
18+
# Headers contain a sequence of characters which are incorrectly interpreted as a doctest, these obviously fail
1619
[lib]
1720
doctest = false
1821

@@ -23,12 +26,8 @@ libloading = { version = "0.8", default-features = false }
2326
[target.'cfg(windows)'.dependencies]
2427
windows = { version = "0.62", default-features = false, optional = true }
2528

26-
[build-dependencies]
27-
bindgen = { version = "0.72", optional = true }
28-
2929
[features]
3030
default = ["vk", "dx12", "xess"]
31-
generate-bindings = ["dep:bindgen"]
3231
dx11 = []
3332
dx12 = []
3433
vk = ["dep:ash"]

api_gen/Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[package]
2+
name = "api_gen"
3+
version = "0.1.0"
4+
edition = "2021"
5+
publish = false
6+
7+
[dependencies]
8+
# Pin version to have control over how everything is generated (there is a CI
9+
# check that validates that all files are generated as currently checked in):
10+
bindgen = "=0.72.1"

build.rs renamed to api_gen/src/main.rs

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
1-
#[cfg(feature = "generate-bindings")]
2-
fn vulkan_sdk_include_directory() -> Option<std::path::PathBuf> {
3-
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
4-
let is_windows = target_os.as_str() == "windows";
1+
use std::path::Path;
52

6-
// Mostly on Windows, the Vulkan headers don't exist in a common location but can be found based
7-
// on VULKAN_SDK, set by the Vulkan SDK installer.
3+
fn vulkan_sdk_include_directory() -> Option<std::path::PathBuf> {
84
match std::env::var("VULKAN_SDK") {
9-
Ok(v) => Some(std::path::PathBuf::from(v).join(
5+
Ok(v) => {
6+
let sdk = std::path::PathBuf::from(v);
107
// On the Windows SDK the `Include` directory is capitalized
11-
if is_windows { "Include" } else { "include" },
12-
)),
13-
// TODO: On Windows, perhaps this should be an error with a link to the SDK installation?
14-
Err(std::env::VarError::NotPresent) if is_windows => {
8+
let include = sdk.join("Include");
9+
if include.is_dir() {
10+
return Some(include);
11+
}
12+
let include = sdk.join("include");
13+
if include.is_dir() {
14+
return Some(include);
15+
}
16+
panic!(
17+
"VULKAN_SDK is set but neither Include/ nor include/ exist in {}",
18+
sdk.display()
19+
);
20+
}
21+
Err(std::env::VarError::NotPresent) if cfg!(target_os = "windows") => {
1522
// On Windows there's no common include directory like `/usr/include` where Vulkan headers can be found
1623
panic!("When targeting Windows, the VULKAN_SDK environment variable must be set")
1724
}
@@ -22,9 +29,8 @@ fn vulkan_sdk_include_directory() -> Option<std::path::PathBuf> {
2229
}
2330
}
2431

25-
#[cfg(feature = "generate-bindings")]
2632
fn generate_bindings() {
27-
let compile = |input_file, output_file, allowlist_function, allowlist_type| {
33+
let compile = |input_file: &str, output_file: &str, allowlist_function, allowlist_type| {
2834
let mut bindings = bindgen::Builder::default()
2935
.header(input_file)
3036
.allowlist_recursively(false)
@@ -33,12 +39,15 @@ fn generate_bindings() {
3339
.allowlist_var(".*xess.*")
3440
.bitfield_enum(".*(flags|bits).*")
3541
.newtype_enum(".*result_t.*")
42+
.newtype_enum(".*logging_level_t.*")
3643
.default_enum_style(bindgen::EnumVariation::Rust {
3744
non_exhaustive: false,
3845
})
3946
.parse_callbacks(Box::new(RenameCallback))
4047
.derive_default(true)
41-
.clang_args(["-x", "c++"])
48+
// XeSS headers are Windows-only (D3D12, DXGI, etc.), so clang must
49+
// always target MSVC even when api_gen itself runs on Linux.
50+
.clang_args(["-x", "c++", "--target=x86_64-pc-windows-msvc"])
4251
.prepend_enum_name(false)
4352
.layout_tests(false)
4453
.dynamic_link_require_all(true)
@@ -47,11 +56,20 @@ fn generate_bindings() {
4756
assert!(vulkan_sdk_include_dir.is_dir());
4857
bindings = bindings.clang_arg(format!("-I{}", vulkan_sdk_include_dir.display()))
4958
}
59+
60+
let output_path = Path::new(output_file);
61+
assert!(
62+
output_path.parent().unwrap().is_dir(),
63+
"Output directory does not exist for {output_file}"
64+
);
65+
5066
bindings
5167
.generate()
5268
.expect("Unable to generate bindings")
53-
.write_to_file(output_file)
69+
.write_to_file(output_path)
5470
.expect("Couldn't write bindings");
71+
72+
println!("Generated {output_file}");
5573
};
5674

5775
compile(
@@ -114,11 +132,9 @@ fn generate_bindings() {
114132
);
115133
}
116134

117-
#[cfg(feature = "generate-bindings")]
118135
#[derive(Debug)]
119136
struct RenameCallback;
120137

121-
#[cfg(feature = "generate-bindings")]
122138
impl bindgen::callbacks::ParseCallbacks for RenameCallback {
123139
fn enum_variant_name(
124140
&self,
@@ -168,6 +184,5 @@ impl bindgen::callbacks::ParseCallbacks for RenameCallback {
168184
}
169185

170186
fn main() {
171-
#[cfg(feature = "generate-bindings")]
172187
generate_bindings();
173188
}

src/xell/xell.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,11 @@ where
4949
index % 8
5050
};
5151
let mask = 1 << bit_index;
52-
if val { byte | mask } else { byte & !mask }
52+
if val {
53+
byte | mask
54+
} else {
55+
byte & !mask
56+
}
5357
}
5458
#[inline]
5559
pub fn set_bit(&mut self, index: usize, val: bool) {

0 commit comments

Comments
 (0)