diff --git a/godot-bindings/build.rs b/godot-bindings/build.rs index edceaa9f3..dbd915cf1 100644 --- a/godot-bindings/build.rs +++ b/godot-bindings/build.rs @@ -10,7 +10,7 @@ // It's the only purpose of this build.rs file. If a better solution is found, this file can be removed. #[rustfmt::skip] -fn main() { +fn main() { let mut count = 0; if cfg!(feature = "api-custom") { count += 1; } if cfg!(feature = "api-custom-json") { count += 1; } diff --git a/godot-bindings/src/import.rs b/godot-bindings/src/import.rs index 5b69f8fda..6fe907958 100644 --- a/godot-bindings/src/import.rs +++ b/godot-bindings/src/import.rs @@ -63,3 +63,52 @@ pub use gdextension_api::version_4_5 as prebuilt; // [line] pub use gdextension_api::version_$snakeVersion as prebuilt; pub use gdextension_api::version_4_5 as prebuilt; // ]] + +// Cross-compilation support: +// Since godot-bindings is a build-dependency, it and the gdextension-api crate are compiled for the HOST platform. +// The #[cfg] attributes in gdextension-api::load_gdextension_header_rs() evaluate for HOST, not TARGET. +// We read CARGO_CFG_TARGET_* environment variables to select the correct platform-specific Rust bindings at runtime. +#[cfg(not(any(feature = "api-custom", feature = "api-custom-json")))] +pub(crate) mod prebuilt_platform { + use std::borrow::Cow; + use std::path::PathBuf; + + /// Load platform-specific Rust bindings (gdextension_interface_{platform}.rs) for the TARGET platform. + /// + /// During cross-compilation, godot-bindings runs on the HOST, but needs to generate bindings for the TARGET. + /// This function reads CARGO_CFG_TARGET_* environment variables to determine the target platform, + /// then loads the appropriate gdextension_interface_{platform}.rs file from the gdextension-api crate's res/ directory. + pub fn load_gdextension_header_rs_for_target() -> Cow<'static, str> { + let target_family = std::env::var("CARGO_CFG_TARGET_FAMILY").ok(); + let target_os = std::env::var("CARGO_CFG_TARGET_OS").ok(); + + let platform = match (target_family.as_deref(), target_os.as_deref()) { + (Some("windows"), _) => "windows", + (_, Some("macos" | "ios")) => "macos", + _ => "linux", // Linux, Android, and other Unix-like systems + }; + + load_platform_file(platform) + } + + /// Reads gdextension_interface_{platform}.rs from the gdextension-api crate using DEP_GDEXTENSION_API_ROOT. + fn load_platform_file(platform: &str) -> Cow<'static, str> { + let dep_root = std::env::var("DEP_GDEXTENSION_API_ROOT") + .expect("DEP_GDEXTENSION_API_ROOT not set. This should be exported by gdextension-api's build script."); + + let file_path = PathBuf::from(dep_root) + .join("res") + .join(format!("gdextension_interface_{platform}.rs")); + + std::fs::read_to_string(&file_path) + .map(Cow::Owned) + .unwrap_or_else(|e| panic!( + "Failed to load platform-specific Rust bindings for '{platform}'.\n\ + Tried to read: {}\n\ + Error: {e}\n\ + \n\ + This is likely a cross-compilation issue or the gdextension-api version doesn't support this platform.", + file_path.display() + )) + } +} diff --git a/godot-bindings/src/lib.rs b/godot-bindings/src/lib.rs index 5e3346010..c0698410c 100644 --- a/godot-bindings/src/lib.rs +++ b/godot-bindings/src/lib.rs @@ -129,7 +129,11 @@ mod depend_on_prebuilt { .unwrap_or_else(|e| panic!("failed to write gdextension_interface.h: {e}")); watch.record("write_header_h"); - let rs_contents = prebuilt::load_gdextension_header_rs(); + // Cross-compilation support: + // Since godot-bindings is a build-dependency, it and the gdextension-api crate are compiled for the HOST platform. + // The #[cfg] attributes in gdextension-api::load_gdextension_header_rs() evaluate for HOST, not TARGET. + // We read CARGO_CFG_TARGET_* environment variables to select the correct platform-specific Rust bindings at runtime. + let rs_contents = crate::import::prebuilt_platform::load_gdextension_header_rs_for_target(); std::fs::write(rs_path, rs_contents.as_ref()) .unwrap_or_else(|e| panic!("failed to write gdextension_interface.rs: {e}")); watch.record("write_header_rs");