Skip to content

Commit 8b2ca91

Browse files
committed
Reuse artifacts; apply Git patch; change C Tag* types to __Gdext* (private)
Rename opaque pointer types to highlight their private nature. Needs an update in packed_array.rs because it accidentally uses private implementation details.
1 parent c9af2f3 commit 8b2ca91

File tree

9 files changed

+142
-78
lines changed

9 files changed

+142
-78
lines changed

godot-codegen/src/api_parser.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,9 +227,10 @@ pub fn load_extension_api(watch: &mut godot_input::StopWatch) -> (ExtensionApi,
227227

228228
// Use type inference, so we can accept both String (dynamically resolved) and &str (prebuilt).
229229
let json = godot_input::load_gdextension_json(watch);
230+
let json_str: &str = json.as_ref();
230231

231232
let model: ExtensionApi =
232-
DeJson::deserialize_json(json.as_str()).expect("failed to deserialize JSON");
233+
DeJson::deserialize_json(json_str).expect("failed to deserialize JSON");
233234
watch.record("deserialize_json");
234235

235236
(model, build_config)

godot-core/src/builtin/packed_array.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ use godot_ffi as sys;
99
use crate::builtin::*;
1010
use std::fmt;
1111
use sys::types::*;
12-
use sys::{ffi_methods, interface_fn, GodotFfi, TagString, TagType};
12+
use sys::{ffi_methods, interface_fn, GodotFfi};
13+
14+
// FIXME remove dependency on these types
15+
use sys::{__GdextString, __GdextType};
1316

1417
/// Defines and implements a single packed array type. This macro is not hygienic and is meant to
1518
/// be used only in the current module.
@@ -496,7 +499,7 @@ impl_packed_array!(
496499
opaque_type: OpaquePackedStringArray,
497500
inner_type: InnerPackedStringArray,
498501
argument_type: GodotString,
499-
return_type: TagString,
502+
return_type: __GdextString,
500503
from_array: packed_string_array_from_array,
501504
operator_index: packed_string_array_operator_index,
502505
operator_index_const: packed_string_array_operator_index_const,
@@ -514,7 +517,7 @@ impl_packed_array!(
514517
opaque_type: OpaquePackedVector2Array,
515518
inner_type: InnerPackedVector2Array,
516519
argument_type: Vector2,
517-
return_type: TagType,
520+
return_type: __GdextType,
518521
from_array: packed_vector2_array_from_array,
519522
operator_index: packed_vector2_array_operator_index,
520523
operator_index_const: packed_vector2_array_operator_index_const,
@@ -532,7 +535,7 @@ impl_packed_array!(
532535
opaque_type: OpaquePackedVector3Array,
533536
inner_type: InnerPackedVector3Array,
534537
argument_type: Vector3,
535-
return_type: TagType,
538+
return_type: __GdextType,
536539
from_array: packed_vector3_array_from_array,
537540
operator_index: packed_vector3_array_operator_index,
538541
operator_index_const: packed_vector3_array_operator_index_const,
@@ -550,7 +553,7 @@ impl_packed_array!(
550553
opaque_type: OpaquePackedColorArray,
551554
inner_type: InnerPackedColorArray,
552555
argument_type: Color,
553-
return_type: TagType,
556+
return_type: __GdextType,
554557
from_array: packed_color_array_from_array,
555558
operator_index: packed_color_array_operator_index,
556559
operator_index_const: packed_color_array_operator_index_const,

godot-ffi/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ keywords = ["gamedev", "godot", "engine", "ffi"]
88
categories = ["game-engines", "graphics"]
99

1010
[features]
11-
custom-godot = ["dep:godot-input"]
11+
custom-godot = ["godot-input/custom-godot"]
1212
codegen-fmt = ["godot-codegen/codegen-fmt"]
1313
#codegen-full = ["godot-codegen/codegen-full"]
1414

1515
[dependencies]
1616
paste = "1"
1717

1818
[build-dependencies]
19-
godot-input = { optional = true, path = "../godot-input" }
19+
godot-input = { path = "../godot-input" }
2020
godot-codegen = { path = "../godot-codegen" }

godot-ffi/build.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ fn main() {
1717
std::fs::create_dir_all(gen_path).unwrap_or_else(|e| panic!("failed to create dir: {e}"));
1818

1919
let rust_header_path = gen_path.join("gdextension_interface.rs");
20-
let header = godot_input::load_gdextension_rust_header(&rust_header_path, &mut watch);
20+
let header = godot_input::load_gdextension_header_rs(&rust_header_path, &mut watch);
2121
std::fs::write(rust_header_path, header).expect("failed to write extension header");
2222

2323
godot_codegen::generate_sys_files(gen_path, &mut watch);

godot-ffi/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ pub use crate::godot_ffi::{GodotFfi, GodotFuncMarshal};
3232
pub use gen::central::*;
3333
pub use gen::gdextension_interface::*;
3434

35+
// The impls only compile if those are different types -- ensures type safety through patch
36+
trait Distinct {}
37+
impl Distinct for GDExtensionVariantPtr {}
38+
impl Distinct for GDExtensionTypePtr {}
39+
impl Distinct for GDExtensionConstTypePtr {}
40+
3541
// ----------------------------------------------------------------------------------------------------------------------------------------------
3642

3743
struct GodotBinding {

godot-input/res/tweak.patch

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
diff --git b/godot-codegen/input/gdextension_interface.h a/godot-codegen/input/gdextension_interface.h
1+
diff --git b/godot-input/gen/gdextension_interface.h a/godot-input/gen/gdextension_interface.h
22
index 0b7615f..6db266e 100644
3-
--- b/godot-codegen/input/gdextension_interface.h
4-
+++ a/godot-codegen/input/gdextension_interface.h
5-
@@ -140,22 +140,22 @@ typedef enum {
3+
--- b/godot-input/gen/gdextension_interface.h
4+
+++ a/godot-input/gen/gdextension_interface.h
5+
@@ -139,22 +139,22 @@ typedef enum {
66

77
} GDExtensionVariantOperator;
88

@@ -17,24 +17,24 @@ index 0b7615f..6db266e 100644
1717
-typedef void *GDExtensionTypePtr;
1818
-typedef const void *GDExtensionConstTypePtr;
1919
-typedef const void *GDExtensionMethodBindPtr;
20-
+typedef struct TagVariant *GDExtensionVariantPtr;
21-
+typedef const struct TagVariant *GDExtensionConstVariantPtr;
22-
+typedef struct TagStringName *GDExtensionStringNamePtr;
23-
+typedef const struct TagStringName *GDExtensionConstStringNamePtr;
24-
+typedef struct TagString *GDExtensionStringPtr;
25-
+typedef const struct TagString *GDExtensionConstStringPtr;
26-
+typedef struct TagObject *GDExtensionObjectPtr;
27-
+typedef const struct TagObject *GDExtensionConstObjectPtr;
28-
+typedef struct TagType *GDExtensionTypePtr;
29-
+typedef const struct TagType *GDExtensionConstTypePtr;
30-
+typedef struct TagMethodBind *GDExtensionMethodBindPtr;
20+
+typedef struct __GdextVariant *GDExtensionVariantPtr;
21+
+typedef const struct __GdextVariant *GDExtensionConstVariantPtr;
22+
+typedef struct __GdextStringName *GDExtensionStringNamePtr;
23+
+typedef const struct __GdextStringName *GDExtensionConstStringNamePtr;
24+
+typedef struct __GdextString *GDExtensionStringPtr;
25+
+typedef const struct __GdextString *GDExtensionConstStringPtr;
26+
+typedef struct __GdextObject *GDExtensionObjectPtr;
27+
+typedef const struct __GdextObject *GDExtensionConstObjectPtr;
28+
+typedef struct __GdextType *GDExtensionTypePtr;
29+
+typedef const struct __GdextType *GDExtensionConstTypePtr;
30+
+typedef struct __GdextMethodBind *GDExtensionMethodBindPtr;
3131
typedef int64_t GDExtensionInt;
3232
typedef uint8_t GDExtensionBool;
3333
typedef uint64_t GDObjectInstanceID;
3434
-typedef void *GDExtensionRefPtr;
3535
-typedef const void *GDExtensionConstRefPtr;
36-
+typedef struct TagExtensionRef *GDExtensionRefPtr;
37-
+typedef const struct TagExtensionRef *GDExtensionConstRefPtr;
36+
+typedef struct __GdextExtensionRef *GDExtensionRefPtr;
37+
+typedef const struct __GdextExtensionRef *GDExtensionConstRefPtr;
3838

3939
/* VARIANT DATA I/O */
4040

godot-input/src/godot_exe.rs

Lines changed: 69 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66

77
use crate::godot_version::parse_godot_version;
8-
use crate::header_gen::run_bindgen;
8+
use crate::header_gen::generate_rust_binding;
99
use crate::watch::StopWatch;
1010
use std::path::{Path, PathBuf};
1111
use std::process::Command;
@@ -15,6 +15,7 @@ use std::process::Command;
1515
const GODOT_VERSION_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/gen/godot_version.txt");
1616
const JSON_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/gen/extension_api.json");
1717
const HEADER_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/gen/gdextension_interface.h");
18+
const RES_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/res");
1819

1920
pub fn load_gdextension_json(watch: &mut StopWatch) -> String {
2021
let json_path = Path::new(JSON_PATH);
@@ -26,12 +27,12 @@ pub fn load_gdextension_json(watch: &mut StopWatch) -> String {
2627

2728
// Regenerate API JSON if first time or Godot version is different
2829
let version = read_godot_version(&godot_bin);
29-
if !json_path.exists() || has_version_changed(&version) {
30-
dump_extension_api(&godot_bin, json_path);
31-
update_version_file(&version);
30+
// if !json_path.exists() || has_version_changed(&version) {
31+
dump_extension_api(&godot_bin, json_path);
32+
update_version_file(&version);
3233

33-
watch.record("dump_gdextension_json");
34-
}
34+
watch.record("dump_gdextension_json");
35+
// }
3536

3637
let result = std::fs::read_to_string(json_path)
3738
.unwrap_or_else(|_| panic!("failed to open file {}", json_path.display()));
@@ -40,8 +41,9 @@ pub fn load_gdextension_json(watch: &mut StopWatch) -> String {
4041
result
4142
}
4243

43-
pub fn load_gdextension_rust_header(rust_out_path: &Path, watch: &mut StopWatch) -> String {
44+
pub fn load_gdextension_header_rs(rust_out_path: &Path, watch: &mut StopWatch) -> String {
4445
let c_header_path = Path::new(HEADER_PATH);
46+
let resource_path = Path::new(RES_PATH);
4547
rerun_on_changed(c_header_path);
4648

4749
let godot_bin = locate_godot_binary();
@@ -50,14 +52,16 @@ pub fn load_gdextension_rust_header(rust_out_path: &Path, watch: &mut StopWatch)
5052

5153
// Regenerate API JSON if first time or Godot version is different
5254
let version = read_godot_version(&godot_bin);
53-
if !c_header_path.exists() || has_version_changed(&version) {
54-
dump_header_file(&godot_bin, c_header_path);
55-
update_version_file(&version);
55+
// if !c_header_path.exists() || has_version_changed(&version) {
56+
dump_header_file(&godot_bin, c_header_path);
57+
update_version_file(&version);
5658

57-
watch.record("dump_gdextension_header");
58-
}
59+
watch.record("dump_gdextension_header");
60+
// }
61+
62+
patch_c_header(&resource_path.join("tweak.patch"));
63+
generate_rust_binding(c_header_path, rust_out_path);
5964

60-
run_bindgen(c_header_path, rust_out_path);
6165
watch.record("read_header_file");
6266
std::fs::read_to_string(rust_out_path).unwrap_or_else(|_| {
6367
panic!(
@@ -67,6 +71,7 @@ pub fn load_gdextension_rust_header(rust_out_path: &Path, watch: &mut StopWatch)
6771
})
6872
}
6973

74+
#[allow(dead_code)]
7075
fn has_version_changed(current_version: &str) -> bool {
7176
let version_path = Path::new(GODOT_VERSION_PATH);
7277

@@ -121,18 +126,12 @@ fn dump_extension_api(godot_bin: &Path, out_file: &Path) {
121126
std::fs::create_dir_all(cwd).unwrap_or_else(|_| panic!("create directory '{}'", cwd.display()));
122127
println!("Dump GDExtension API JSON to dir '{}'...", cwd.display());
123128

124-
Command::new(godot_bin)
125-
.current_dir(cwd)
129+
let mut cmd = Command::new(godot_bin);
130+
cmd.current_dir(cwd)
126131
.arg("--headless")
127-
.arg("--dump-extension-api")
128-
.arg(cwd)
129-
.output()
130-
.unwrap_or_else(|_| {
131-
panic!(
132-
"failed to invoke Godot executable '{}'",
133-
godot_bin.display()
134-
)
135-
});
132+
.arg("--dump-extension-api");
133+
134+
execute(cmd, "dump Godot header file");
136135

137136
println!("Generated {}/gdextension_interface.h.", cwd.display());
138137
}
@@ -142,22 +141,28 @@ fn dump_header_file(godot_bin: &Path, out_file: &Path) {
142141
std::fs::create_dir_all(cwd).unwrap_or_else(|_| panic!("create directory '{}'", cwd.display()));
143142
println!("Dump GDExtension header file to dir '{}'...", cwd.display());
144143

145-
Command::new(godot_bin)
146-
.current_dir(cwd)
144+
let mut cmd = Command::new(godot_bin);
145+
cmd.current_dir(cwd)
147146
.arg("--headless")
148-
.arg("--dump-gdextension-interface")
149-
.arg(cwd)
150-
.output()
151-
.unwrap_or_else(|_| {
152-
panic!(
153-
"failed to invoke Godot executable '{}'",
154-
godot_bin.display()
155-
)
156-
});
147+
.arg("--dump-gdextension-interface");
148+
149+
execute(cmd, "dump Godot JSON file");
157150

158151
println!("Generated {}/extension_api.json.", cwd.display());
159152
}
160153

154+
fn patch_c_header(tweak_path: &Path) {
155+
// Note: patch must have paths relative to Git root (aka top-level dir), so cwd is root
156+
let cwd = tweak_path.parent().unwrap().parent().unwrap();
157+
rerun_on_changed(tweak_path);
158+
159+
let git = locate_git_binary();
160+
let mut cmd = Command::new(&git);
161+
cmd.current_dir(cwd).arg("apply").arg("-v").arg(tweak_path);
162+
163+
execute(cmd, "apply Git patch");
164+
}
165+
161166
fn locate_godot_binary() -> PathBuf {
162167
if let Ok(string) = std::env::var("GODOT4_BIN") {
163168
println!("Found GODOT4_BIN with path to executable: '{string}'");
@@ -167,12 +172,40 @@ fn locate_godot_binary() -> PathBuf {
167172
path
168173
} else {
169174
panic!(
170-
"Bindings generation requires 'godot4' executable or a GODOT4_BIN \
175+
"gdext with `custom-godot` feature requires 'godot4' executable or a GODOT4_BIN \
176+
environment variable (with the path to the executable)."
177+
)
178+
}
179+
}
180+
181+
fn locate_git_binary() -> PathBuf {
182+
if let Ok(string) = std::env::var("GIT_BIN") {
183+
println!("Found GIT_BIN with path to executable: '{string}'");
184+
PathBuf::from(string)
185+
} else if let Ok(path) = which::which("git") {
186+
println!("Found 'git' executable in PATH: {}", path.display());
187+
path
188+
} else {
189+
panic!(
190+
"gdext with `custom-godot` feature requires `git` executable or a GIT_BIN \
171191
environment variable (with the path to the executable)."
172192
)
173193
}
174194
}
175195

196+
fn execute(mut cmd: Command, error_message: &str) {
197+
let output = cmd
198+
.output()
199+
.unwrap_or_else(|_| panic!("failed to execute command: {error_message}"));
200+
201+
if !output.status.success() {
202+
println!("[stdout] {}", String::from_utf8(output.stdout).unwrap());
203+
println!("[stderr] {}", String::from_utf8(output.stderr).unwrap());
204+
println!("[status] {}", output.status);
205+
panic!("command returned error: {error_message}");
206+
}
207+
}
208+
176209
fn rerun_on_changed(path: &Path) {
177210
println!("cargo:rerun-if-changed={}", path.display());
178211
println!("cargo:rerun-if-env-changed=GODOT4_BIN");

godot-input/src/header_gen.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use std::env;
88
use std::path::Path;
99

10-
pub(crate) fn run_bindgen(c_header_path: &Path, out_rust_path: &Path) {
10+
pub(crate) fn generate_rust_binding(c_header_path: &Path, out_rust_path: &Path) {
1111
let c_header_path = c_header_path.display().to_string();
1212
println!("cargo:rerun-if-changed={}", c_header_path);
1313

0 commit comments

Comments
 (0)