#[cfg(feature = "generate-bindings")]
const XPLANE_SDK_PATH_KEY: &str = "XPLANE_SDK_PATH";
#[cfg(feature = "generate-bindings")]
const XPLANE_SDK_VERSIONS_KEY: &str = "XPLANE_SDK_VERSIONS";
#[cfg(feature = "generate-bindings")]
const DEFAULT_XPLM_VERSION_DEFINITIONS: [&str; 7] = [
"-DXPLM200",
"-DXPLM210",
"-DXPLM300",
"-DXPLM301",
"-DXPLM303",
"-DXPLM400",
"-DXPLM410",
];
fn main() {
#[cfg(all(
not(feature = "generate-bindings"),
any(target_os = "windows", target_os = "macos")
))]
let sdk_path = std::env::var("CARGO_MANIFEST_DIR")
.map(std::path::PathBuf::from)
.expect("failed to locate packaged SDK, env variable `CARGO_MANIFEST_DIR` should be set")
.join("SDK");
#[cfg(feature = "generate-bindings")]
let sdk_path = std::env::var(XPLANE_SDK_PATH_KEY)
.map(std::path::PathBuf::from)
.expect("failed to locate the SDK, env variable `XPLANE_SDK_PATH` should point to the SDK");
#[cfg(feature = "generate-bindings")]
generate_bindings(&sdk_path);
#[cfg(any(target_os = "windows", target_os = "macos"))]
link_libraries(&sdk_path);
}
#[cfg(feature = "generate-bindings")]
fn generate_bindings(sdk_path: &std::path::Path) {
println!("cargo:rerun-if-env-changed={XPLANE_SDK_PATH_KEY}");
println!("cargo:rerun-if-env-changed={XPLANE_SDK_VERSIONS_KEY}");
let include_path = sdk_path.join("CHeaders");
let out_path = std::env::var("OUT_DIR")
.map(std::path::PathBuf::from)
.expect("env variable `OUT_DIR` should be defined");
let mut headers = Vec::new();
headers.extend_from_slice(
&collect_headers(&include_path.join("XPLM"))
.expect("failed to gather header files in `XPLM`"),
);
headers.extend_from_slice(
&collect_headers(&include_path.join("Widgets"))
.expect("failed to gather header files in `Widgets`"),
);
let mut builder = bindgen::Builder::default()
.clang_args([
"-fparse-all-comments",
"-DLIN=1",
&format!("-I{}", include_path.join("XPLM").display()),
&format!("-I{}", include_path.join("Widgets").display()),
]);
for header in headers {
builder = builder.header(header);
}
match custom_sdk_versions() {
Some(custom_versions) => builder = builder.clang_args(custom_versions),
None => builder = builder.clang_args(DEFAULT_XPLM_VERSION_DEFINITIONS),
};
let bindings = builder
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.generate()
.expect("failed to generate bindings");
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("failed to write bindings to disk");
}
#[cfg(feature = "generate-bindings")]
fn collect_headers(dir: &std::path::Path) -> std::io::Result<Vec<String>> {
let mut headers = Vec::new();
for entry in dir.read_dir()? {
let entry = entry?;
let path = entry.path();
if path.is_file() && path.extension().map(|ext| ext == "h").unwrap_or_default() {
headers.push(path.to_str().expect("path is not valid UTF-8").to_string());
}
}
Ok(headers)
}
#[cfg(any(target_os = "windows", target_os = "macos"))]
fn link_libraries(sdk_path: &std::path::Path) {
let library_path = sdk_path.join("Libraries");
if cfg!(windows) {
println!(
"cargo:rustc-link-search={}",
library_path.join("Win").display()
);
println!("cargo:rustc-link-lib=XPLM_64");
println!("cargo:rustc-link-lib=XPWidgets_64");
} else {
println!(
"cargo:rustc-link-search=framework={}",
library_path.join("Mac").display()
);
println!("cargo:rustc-link-lib=framework=XPLM");
println!("cargo:rustc-link-lib=framework=XPWidgets");
}
}
#[cfg(feature = "generate-bindings")]
fn custom_sdk_versions() -> Option<Vec<String>> {
let custom_versions = match std::env::var(XPLANE_SDK_VERSIONS_KEY) {
Ok(versions) => versions,
Err(std::env::VarError::NotPresent) => return None,
Err(std::env::VarError::NotUnicode(_)) => panic!(
"`{}` environment variable has to be valid UTF-8",
XPLANE_SDK_VERSIONS_KEY
),
};
Some(
custom_versions
.split(';')
.map(str::trim)
.filter(|v| !v.is_empty())
.map(|version| format!("-D{}", version))
.collect(),
)
}