Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix iOS bindings #17

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
89 changes: 65 additions & 24 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,25 @@ fn osx_version() -> Result<String, std::io::Error> {
Ok(version.to_owned())
}

fn isysroot_path(platform: &str) -> Result<String, std::io::Error> {
use std::process::Command;

let output = Command::new("xcrun")
.arg("--sdk")
.arg(platform)
.arg("--show-sdk-path")
.output()?
.stdout;

let sdk_path =
std::str::from_utf8(&output).expect("invalid output from `xcrun --show-sdk-path`");
let directory = String::from(sdk_path.trim());

println!("SDK Directory: {}", directory);

Ok(directory)
}

fn parse_version(version: &str) -> Option<i32> {
version
.split(".")
Expand All @@ -23,7 +42,7 @@ fn parse_version(version: &str) -> Option<i32> {
.and_then(|m| m.parse::<i32>().ok())
}

fn frameworks_path() -> Result<String, std::io::Error> {
fn frameworks_path(platform: &str) -> Result<String, std::io::Error> {
// For 10.13 and higher:
//
// While macOS has its system frameworks located at "/System/Library/Frameworks"
Expand All @@ -40,18 +59,13 @@ fn frameworks_path() -> Result<String, std::io::Error> {
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)
format!(
"Platforms/{}.platform/Developer/SDKs/{}.sdk",
platform, platform
)
};

let suffix = "System/Library/Frameworks";
Expand All @@ -63,7 +77,7 @@ fn frameworks_path() -> Result<String, std::io::Error> {
}
}

fn build(frameworks_path: &str) {
fn build(frameworks_path: &str, sysroot: &str, platform: &str, target: &str) {
// Generate one large set of bindings for all frameworks.
//
// We do this rather than generating a module per framework as some frameworks depend on other
Expand Down Expand Up @@ -97,7 +111,13 @@ fn build(frameworks_path: &str) {
{
println!("cargo:rustc-link-lib=framework=CoreAudio");
frameworks.push("CoreAudio");
headers.push("CoreAudio.framework/Headers/CoreAudio.h");
match platform {
"MacOSX" => headers.push("CoreAudio.framework/Headers/CoreAudio.h"),
"iPhoneOS" | "iPhoneSimulator" => {
headers.push("CoreAudio.framework/Headers/CoreAudioTypes.h")
}
_ => unreachable!(),
}
}

#[cfg(feature = "open_al")]
Expand All @@ -110,9 +130,13 @@ fn build(frameworks_path: &str) {

#[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");
if (platform == "MacOSX") {
println!("cargo:rustc-link-lib=framework=CoreMIDI");
frameworks.push("CoreMIDI");
headers.push("CoreMIDI.framework/Headers/CoreMIDI.h");
} else {
panic!("framework CoreMIDI is not supported by Apple on this platform");
}
}

// Get the cargo out directory.
Expand All @@ -121,7 +145,10 @@ fn build(frameworks_path: &str) {
// Begin building the bindgen params.
let mut builder = bindgen::Builder::default();

builder = builder.clang_arg(format!("-F/{}", frameworks_path));
builder = builder
.clang_arg(format!("-F/{}", frameworks_path))
.clang_arg("-isysroot")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Has this been tested on older versions of osx ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, but I have no means to do it.

.clang_arg(sysroot);

// Add all headers.
for relative_path in headers {
Expand All @@ -137,6 +164,8 @@ fn build(frameworks_path: &str) {

// Generate the bindings.
let bindings = builder
.clang_arg("-target")
.clang_arg(target)
.trust_clang_mangling(false)
.derive_default(true)
.rustfmt_bindings(false)
Expand All @@ -149,16 +178,28 @@ fn build(frameworks_path: &str) {
.expect("could not write bindings");
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
fn main() {
if let Ok(directory) = frameworks_path() {
build(&directory);
let (target, platform) = match std::env::var("TARGET") {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't there a better way of doing this? All of this should be exposed via cfg, no?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe cfg will return the building platform as this is build.rs, so here it would always be darwin. Unless I'm wrong. I can't check right now unfortunately.

Ok(val) => match val.as_ref() {
"x86_64-apple-darwin" | "i686-apple-darwin" => (val, "MacOSX"),
"aarch64-apple-ios" => (String::from("arm64-apple-ios"), "iPhoneOS"),
"armv7-apple-ios" | "armv7s-apple-ios" | "i386-apple-ios" | "x86_64-apple-ios" => {
(val, "iPhoneOS")
}
_ => panic!("coreaudio-sys requires macos or ios target. Found: {}", val),
},
Err(_e) => {
panic!("TARGET environment variable not found (are you running this outside of cargo?)")
}
};

if let Ok(directory) = frameworks_path(platform) {
if let Ok(sysroot) = isysroot_path(&platform.to_lowercase()) {
build(&directory, &sysroot, platform, &target);
} else {
eprintln!("coreaudio-sys could not find sysroot path");
}
} 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");
}