Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion godot-bindings/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down
49 changes: 49 additions & 0 deletions godot-bindings/src/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
))
}
}
6 changes: 5 additions & 1 deletion godot-bindings/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down