Skip to content

Commit

Permalink
Merge pull request #1014 from godot-rust/qol/remove-dead-4.0-code
Browse files Browse the repository at this point in the history
Remove dead binding code regarding Godot 4.0
  • Loading branch information
Bromeon authored Jan 19, 2025
2 parents 7461251 + ccb0c7a commit b345a7e
Showing 1 changed file with 22 additions and 71 deletions.
93 changes: 22 additions & 71 deletions godot-bindings/src/godot_exe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,16 @@ pub fn write_gdextension_headers(
watch: &mut StopWatch,
) {
// None=(unknown, no engine), Some=(version of Godot). Later verified by header itself.
let is_engine_4_0;
if is_h_provided {
is_engine_4_0 = None;
} else {
// Even though we don't support 4.0 anymore, we still detect it, for better error messages.
if !is_h_provided {
// No external C header file: Godot binary is present, we use it to dump C header
let godot_bin = locate_godot_binary();
rerun_on_changed(&godot_bin);
watch.record("locate_godot");

// Regenerate API JSON if first time or Godot version is different
let version = read_godot_version(&godot_bin);
is_engine_4_0 = Some(version.major == 4 && version.minor == 0);
// Regenerate API JSON if first time or Godot version is different.
// Note: read_godot_version() already panics if 4.0 is still in use; no need to check again.
let _version = read_godot_version(&godot_bin);

// if !c_header_path.exists() || has_version_changed(&version) {
dump_header_file(&godot_bin, inout_h_path);
Expand All @@ -79,7 +77,7 @@ pub fn write_gdextension_headers(
// Listening to changes on files that are generated by this build step cause an infinite loop with cargo watch of
// build -> detect change -> rebuild -> detect change -> ...
// rerun_on_changed(inout_h_path);
patch_c_header(inout_h_path, is_engine_4_0);
patch_c_header(inout_h_path);
watch.record("patch_header_h");

generate_rust_binding(inout_h_path, out_rs_path);
Expand Down Expand Up @@ -117,7 +115,13 @@ pub(crate) fn read_godot_version(godot_bin: &Path) -> GodotVersion {
assert_eq!(
parsed.major,
4,
"Only Godot versions >= 4.0 are supported; found version {}.",
"Only Godot versions with major version 4 are supported; found version {}.",
stdout.trim()
);

assert!(
parsed.minor > 0,
"Godot 4.0 is no longer supported by godot-rust; found version {}.",
stdout.trim()
);

Expand Down Expand Up @@ -158,35 +162,23 @@ fn dump_header_file(godot_bin: &Path, out_file: &Path) {
println!("Generated {}/gdextension_interface.h.", cwd.display());
}

fn patch_c_header(inout_h_path: &Path, is_engine_4_0: Option<bool>) {
fn patch_c_header(inout_h_path: &Path) {
// The C header path *must* be passed in by the invoking crate, as the path cannot be relative to this crate.
// Otherwise, it can be something like `/home/runner/.cargo/git/checkouts/gdext-76630c89719e160c/efd3b94/godot-bindings`.

println!(
"Patch C header '{}' (is_engine_4_0={is_engine_4_0:?})...",
inout_h_path.display()
);
println!("Patch C header '{}'...", inout_h_path.display());

let mut c = fs::read_to_string(inout_h_path)
.unwrap_or_else(|_| panic!("failed to read C header file {}", inout_h_path.display()));

// Detect whether header is legacy (4.0) or modern (4.1+) format.
let is_header_4_0 = !c.contains("GDExtensionInterfaceGetProcAddress");
println!("is_header_4_0={is_header_4_0}");

// Sanity check
if let Some(is_engine_4_0) = is_engine_4_0 {
assert_eq!(
is_header_4_0, is_engine_4_0,
"Mismatch between engine/header versions"
);
}

if is_header_4_0 {
polyfill_legacy_header(&mut c);
}
// Detect whether header is legacy (4.0) format. This should generally already be checked outside.
assert!(
c.contains("GDExtensionInterfaceGetProcAddress"),
"C header file '{}' seems to be GDExtension version 4.0, which is no longer support by godot-rust.",
inout_h_path.display()
);

// Patch for variant converters and type constructors
// Patch for variant converters and type constructors.
c = c.replace(
"typedef void (*GDExtensionVariantFromTypeConstructorFunc)(GDExtensionVariantPtr, GDExtensionTypePtr);",
"typedef void (*GDExtensionVariantFromTypeConstructorFunc)(GDExtensionUninitializedVariantPtr, GDExtensionTypePtr);"
Expand Down Expand Up @@ -217,47 +209,6 @@ fn patch_c_header(inout_h_path: &Path, is_engine_4_0: Option<bool>) {
});
}

/// Backport Godot 4.1+ changes to the old GDExtension API, so gdext can use both uniformly.
fn polyfill_legacy_header(c: &mut String) {
// Newer Uninitialized* types -- use same types as initialized ones, because old functions are not written with Uninitialized* in mind
let pos = c
.find("typedef int64_t GDExtensionInt;")
.expect("Unexpected gdextension_interface.h format (int)");

c.insert_str(
pos,
"\
// gdext polyfill\n\
typedef struct __GdextVariant *GDExtensionUninitializedVariantPtr;\n\
typedef struct __GdextStringName *GDExtensionUninitializedStringNamePtr;\n\
typedef struct __GdextString *GDExtensionUninitializedStringPtr;\n\
typedef struct __GdextObject *GDExtensionUninitializedObjectPtr;\n\
typedef struct __GdextType *GDExtensionUninitializedTypePtr;\n\
\n",
);

// Typedef GDExtensionInterfaceGetProcAddress (simply resolving to GDExtensionInterface, as it's the same parameter)
let pos = c
.find("/* INITIALIZATION */")
.expect("Unexpected gdextension_interface.h format (struct)");

c.insert_str(
pos,
"\
// gdext polyfill\n\
typedef struct {\n\
uint32_t major;\n\
uint32_t minor;\n\
uint32_t patch;\n\
const char *string;\n\
} GDExtensionGodotVersion;\n\
typedef void (*GDExtensionInterfaceFunctionPtr)();\n\
typedef void (*GDExtensionInterfaceGetGodotVersion)(GDExtensionGodotVersion *r_godot_version);\n\
typedef GDExtensionInterfaceFunctionPtr (*GDExtensionInterfaceGetProcAddress)(const char *p_function_name);\n\
\n",
);
}

pub(crate) fn locate_godot_binary() -> PathBuf {
if let Ok(string) = std::env::var("GODOT4_BIN") {
println!("Found GODOT4_BIN with path to executable: '{string}'");
Expand Down

0 comments on commit b345a7e

Please sign in to comment.