extern crate bindgen;
fn osx_version() -> Result<String, std::io::Error> {
use std::process::Command;
let output = Command::new("defaults")
.arg("read")
.arg("loginwindow")
.arg("SystemVersionStampAsString")
.output()?
.stdout;
let version_str = std::str::from_utf8(&output).expect("invalid output from `defaults`");
let version = version_str.trim_right();
Ok(version.to_owned())
}
fn parse_version(version: &str) -> Option<i32> {
version
.split(".")
.skip(1)
.next()
.and_then(|m| m.parse::<i32>().ok())
}
fn frameworks_path() -> Result<String, std::io::Error> {
if osx_version()
.and_then(|version| Ok(parse_version(&version).map(|v| v >= 13).unwrap_or(false)))
.unwrap_or(false)
{
use std::process::Command;
let output = Command::new("xcode-select").arg("-p").output()?.stdout;
let prefix_str = std::str::from_utf8(&output).expect("invalid output from `xcode-select`");
let prefix = prefix_str.trim_right();
let platform = if cfg!(target_os = "macos") {
"MacOSX"
} else if cfg!(target_os = "ios") {
"iPhoneOS"
} else {
unreachable!();
};
let infix = if prefix == "/Library/Developer/CommandLineTools" {
format!("SDKs/{}.sdk", platform)
} else {
format!("Platforms/{}.platform/Developer/SDKs/{}.sdk", platform, platform)
};
let suffix = "System/Library/Frameworks";
let directory = format!("{}/{}/{}", prefix, infix, suffix);
Ok(directory)
} else {
Ok("/System/Library/Frameworks".to_string())
}
}
fn build(frameworks_path: &str) {
use std::env;
use std::path::PathBuf;
let mut frameworks = vec![];
let mut headers = vec![];
#[cfg(feature = "audio_toolbox")]
{
println!("cargo:rustc-link-lib=framework=AudioToolbox");
frameworks.push("AudioToolbox");
headers.push("AudioToolbox.framework/Headers/AudioToolbox.h");
}
#[cfg(feature = "audio_unit")]
{
println!("cargo:rustc-link-lib=framework=AudioUnit");
frameworks.push("AudioUnit");
headers.push("AudioUnit.framework/Headers/AudioUnit.h");
}
#[cfg(feature = "core_audio")]
{
println!("cargo:rustc-link-lib=framework=CoreAudio");
frameworks.push("CoreAudio");
headers.push("CoreAudio.framework/Headers/CoreAudio.h");
}
#[cfg(feature = "open_al")]
{
println!("cargo:rustc-link-lib=framework=OpenAL");
frameworks.push("OpenAL");
headers.push("OpenAL.framework/Headers/al.h");
headers.push("OpenAL.framework/Headers/alc.h");
}
#[cfg(all(feature = "core_midi", target_os = "macos"))]
{
println!("cargo:rustc-link-lib=framework=CoreMIDI");
frameworks.push("CoreMIDI");
headers.push("CoreMIDI.framework/Headers/CoreMIDI.h");
}
let out_dir = PathBuf::from(env::var("OUT_DIR").expect("env variable OUT_DIR not found"));
let mut builder = bindgen::Builder::default();
builder = builder.clang_arg(format!("-F/{}", frameworks_path));
for relative_path in headers {
let absolute_path = format!("{}/{}", frameworks_path, relative_path);
builder = builder.header(absolute_path);
}
for relative_path in frameworks {
let absolute_path = format!("{}/{}", frameworks_path, relative_path);
builder = builder.link_framework(absolute_path);
}
let bindings = builder
.trust_clang_mangling(false)
.derive_default(true)
.rustfmt_bindings(false)
.generate()
.expect("unable to generate bindings");
bindings
.write_to_file(out_dir.join("coreaudio.rs"))
.expect("could not write bindings");
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
fn main() {
if let Ok(directory) = frameworks_path() {
build(&directory);
} else {
eprintln!("coreaudio-sys could not find frameworks path");
}
}
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
fn main() {
eprintln!("coreaudio-sys requires macos or ios target");
}