Skip to content

Commit fdd9dc8

Browse files
committed
Remove bindgen dependency; generate all FFI types from JSON
gdextension_interface.rs is now fully produced by godot-codegen from gdextension_interface.json, eliminating the C header and bindgen entirely.
1 parent 8074129 commit fdd9dc8

13 files changed

Lines changed: 1754 additions & 1548 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ rust-version = "1.94"
2424
# regular dependencies. Sort alphabetically within each section; comments about a dependency come on the section header.
2525
[workspace.dependencies]
2626
# Related to godot-rust.
27-
gdextension-api = { version = "0.3.3", git = "https://github.com/godot-rust/godot4-prebuilt", branch = "release-v0.3" }
27+
gdextension-api = { version = "0.5.0", git = "https://github.com/godot-rust/godot4-prebuilt", branch = "release-v0.5" }
2828

2929
# Main library features.
3030
glam = { version = "0.32", features = ["debug-glam-assert"] }
@@ -34,7 +34,6 @@ serde_json = "1"
3434
# Related to tooling/build setup.
3535
# * regex: not used for unicode parsing -> features unicode-bool + unicode-gencat are enabled instead of unicode-perl.
3636
# 'unicode-gencat' needed for \d, see https://docs.rs/regex/latest/regex/#unicode-features.
37-
bindgen = { version = "0.72.1", default-features = false, features = ["runtime"] }
3837
libc = "0.2.183"
3938
regex = { version = "1.12", default-features = false, features = ["std", "unicode-bool", "unicode-gencat"] }
4039
which = "8"

godot-bindings/Cargo.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ api-4-6 = []
2828

2929
default = []
3030

31-
api-custom = ["dep:bindgen", "dep:regex", "dep:which"]
32-
api-custom-json = ["dep:nanoserde", "dep:bindgen", "dep:regex", "dep:which"]
31+
api-custom = ["dep:regex", "dep:which"]
32+
api-custom-json = ["dep:nanoserde", "dep:which"]
3333
api-custom-extheader = []
3434

3535
# Safeguard levels (see godot/lib.rs for detailed documentation).
@@ -39,7 +39,6 @@ safeguards-release-disengaged = []
3939
[dependencies]
4040
gdextension-api = { workspace = true }
4141

42-
bindgen = { workspace = true, optional = true }
4342
regex = { workspace = true, optional = true }
4443
which = { workspace = true, optional = true }
4544
# Required by `api-custom-json` to parse the extension API JSON (to get the Godot version).

godot-bindings/src/godot_exe.rs

Lines changed: 0 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,7 @@ use std::path::{Path, PathBuf};
1212
use std::process::{Command, Output};
1313
use std::sync::Once;
1414

15-
use regex::Regex;
16-
1715
use crate::godot_version::{parse_godot_version, validate_godot_version};
18-
use crate::header_gen::generate_rust_binding;
1916
use crate::watch::StopWatch;
2017
use crate::{GodotVersion, env_var_or_deprecated};
2118

@@ -51,41 +48,6 @@ pub fn load_gdextension_json(watch: &mut StopWatch) -> String {
5148
result
5249
}
5350

54-
pub fn write_gdextension_headers(
55-
inout_h_path: &Path,
56-
out_rs_path: &Path,
57-
is_h_provided: bool,
58-
watch: &mut StopWatch,
59-
) {
60-
// Use Godot binary to dump GDExtension headers if they weren't provided by the user.
61-
if !is_h_provided {
62-
// No external C header file: Godot binary is present, we use it to dump C header
63-
let godot_bin = locate_godot_binary();
64-
rerun_on_changed(&godot_bin);
65-
watch.record("locate_godot");
66-
67-
// Regenerate API JSON if first time or Godot version is different.
68-
// Note: read_godot_version() already panics if 4.0 is still in use; no need to check again.
69-
// This also validates whether we run a Debug build.
70-
let _version = read_godot_version(&godot_bin);
71-
72-
// if !c_header_path.exists() || has_version_changed(&version) {
73-
dump_header_file(&godot_bin, inout_h_path);
74-
// update_version_file(&version);
75-
watch.record("dump_header_h");
76-
// }
77-
};
78-
79-
// Listening to changes on files that are generated by this build step cause an infinite loop with cargo watch of
80-
// build -> detect change -> rebuild -> detect change -> ...
81-
// rerun_on_changed(inout_h_path);
82-
patch_c_header(inout_h_path, inout_h_path);
83-
watch.record("patch_header_h");
84-
85-
generate_rust_binding(inout_h_path, out_rs_path);
86-
watch.record("generate_header_rs");
87-
}
88-
8951
/*
9052
fn has_version_changed(current_version: &str) -> bool {
9153
let version_path = Path::new(GODOT_VERSION_PATH);
@@ -161,67 +123,6 @@ fn dump_extension_api(godot_bin: &Path, out_file: &Path) {
161123
println!("Generated {}/extension_api.json.", cwd.display());
162124
}
163125

164-
fn dump_header_file(godot_bin: &Path, out_file: &Path) {
165-
let cwd = out_file.parent().unwrap();
166-
fs::create_dir_all(cwd).unwrap_or_else(|_| panic!("create directory '{}'", cwd.display()));
167-
println!("Dump GDExtension header file to dir '{}'...", cwd.display());
168-
169-
let mut cmd = Command::new(godot_bin);
170-
cmd.current_dir(cwd)
171-
.arg("--headless")
172-
.arg("--dump-gdextension-interface");
173-
174-
execute(cmd, "dump Godot header file");
175-
println!("Generated {}/gdextension_interface.h.", cwd.display());
176-
}
177-
178-
pub(crate) fn patch_c_header(in_h_path: &Path, out_h_path: &Path) {
179-
// The C header path *must* be passed in by the invoking crate, as the path cannot be relative to this crate.
180-
// Otherwise, it can be something like `/home/runner/.cargo/git/checkouts/gdext-76630c89719e160c/efd3b94/godot-bindings`.
181-
182-
println!("Patch C header '{}'...", in_h_path.display());
183-
184-
let mut c = fs::read_to_string(in_h_path)
185-
.unwrap_or_else(|_| panic!("failed to read C header file {}", in_h_path.display()));
186-
187-
// Detect whether header is legacy (4.0) format. This should generally already be checked outside.
188-
assert!(
189-
c.contains("GDExtensionInterfaceGetProcAddress"),
190-
"C header file '{}' seems to be GDExtension version 4.0, which is no longer support by godot-rust.",
191-
in_h_path.display()
192-
);
193-
194-
// Patch for variant converters and type constructors.
195-
c = c.replace(
196-
"typedef void (*GDExtensionVariantFromTypeConstructorFunc)(GDExtensionVariantPtr, GDExtensionTypePtr);",
197-
"typedef void (*GDExtensionVariantFromTypeConstructorFunc)(GDExtensionUninitializedVariantPtr, GDExtensionTypePtr);"
198-
)
199-
.replace(
200-
"typedef void (*GDExtensionTypeFromVariantConstructorFunc)(GDExtensionTypePtr, GDExtensionVariantPtr);",
201-
"typedef void (*GDExtensionTypeFromVariantConstructorFunc)(GDExtensionUninitializedTypePtr, GDExtensionVariantPtr);"
202-
)
203-
.replace(
204-
"typedef void (*GDExtensionPtrConstructor)(GDExtensionTypePtr p_base, const GDExtensionConstTypePtr *p_args);",
205-
"typedef void (*GDExtensionPtrConstructor)(GDExtensionUninitializedTypePtr p_base, const GDExtensionConstTypePtr *p_args);"
206-
);
207-
208-
// Use single regex with independent "const"/"Const", as there are definitions like this:
209-
// typedef const void *GDExtensionMethodBindPtr;
210-
let c = Regex::new(r"typedef (const )?void \*GDExtension(Const)?([a-zA-Z0-9]+?)Ptr;") //
211-
.expect("regex for mut typedef")
212-
.replace_all(&c, "typedef ${1}struct __Gdext$3 *GDExtension${2}${3}Ptr;");
213-
214-
// println!("Patched contents:\n\n{}\n\n", c.as_ref());
215-
216-
// Write the modified contents back to the file
217-
fs::write(out_h_path, c.as_ref()).unwrap_or_else(|_| {
218-
panic!(
219-
"failed to write patched C header file {}",
220-
out_h_path.display()
221-
)
222-
});
223-
}
224-
225126
pub(crate) fn locate_godot_binary() -> PathBuf {
226127
static WARN_ONCE: Once = Once::new();
227128
let env_var = env_var_or_deprecated(&WARN_ONCE, "GDRUST_GODOT_BIN", "GODOT4_BIN");

godot-bindings/src/godot_json.rs

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,8 @@ use std::sync::Once;
2020

2121
use nanoserde::DeJson;
2222

23-
use crate::depend_on_custom_json::header_gen::generate_rust_binding;
2423
use crate::godot_version::validate_godot_version;
25-
use crate::{GodotVersion, StopWatch, env_var_or_deprecated};
26-
27-
#[rustfmt::skip] // Do not reorder.
28-
// GDExtension headers are backward compatible (new incremental changes in general are exposed as additions to the existing API) while godot-rust simply ignores extra declarations in header file.
29-
// Therefore, latest headers should work fine for all the past and future Godot versions – as long as the engine remains unchanged.
30-
// [version-sync] [[
31-
// [include] current.minor
32-
// [line] use gdextension_api::version_$snakeVersion::load_gdextension_header_h as load_latest_gdextension_headers;
33-
use gdextension_api::version_4_6::load_gdextension_header_h as load_latest_gdextension_headers;
34-
// ]]
24+
use crate::{GodotVersion, env_var_or_deprecated};
3525

3626
/// A minimal version of deserialized JsonExtensionApi that includes only the header.
3727
#[derive(DeJson)]
@@ -97,17 +87,3 @@ pub(crate) fn read_godot_version() -> GodotVersion {
9787

9888
version
9989
}
100-
101-
pub(crate) fn write_gdextension_headers(
102-
out_h_path: &Path,
103-
out_rs_path: &Path,
104-
watch: &mut StopWatch,
105-
) {
106-
let h_contents = load_latest_gdextension_headers();
107-
fs::write(out_h_path, h_contents.as_ref())
108-
.unwrap_or_else(|e| panic!("failed to write gdextension_interface.h: {e}"));
109-
watch.record("write_header_h");
110-
111-
generate_rust_binding(out_h_path, out_rs_path);
112-
watch.record("generate_header_rs");
113-
}

godot-bindings/src/header_gen.rs

Lines changed: 0 additions & 130 deletions
This file was deleted.

0 commit comments

Comments
 (0)