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

Support visionOS, watchOS, and tvOS #103

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
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
30 changes: 30 additions & 0 deletions .github/workflows/coreaudio-sys.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,36 @@ jobs:
- name: Build for iOS target ${{matrix.target}}
run: cargo build --verbose --target=${{matrix.target}}

apple-tier-3-check:
runs-on: macOS-14
strategy:
matrix:
target: [
aarch64-apple-visionos,
aarch64-apple-visionos-sim,
aarch64-apple-watchos,
arm64_32-apple-watchos,
armv7k-apple-watchos,
aarch64-apple-watchos-sim,
x86_64-apple-watchos-sim,
aarch64-apple-tvos,
aarch64-apple-tvos-sim,
x86_64-apple-tvos,
]
steps:
- uses: actions/checkout@v4

- uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly
components: rust-src

- name: Install Xcode Command Line Tools
run: sudo xcode-select --switch /Applications/Xcode_15.4.app/Contents/Developer

- name: Build for visionOS target ${{matrix.target}}
run: cargo +nightly build -Z build-std --target=${{matrix.target}}

# Build the docs with all features to make sure docs.rs will work.
macos-docs:
runs-on: macOS-latest
Expand Down
95 changes: 55 additions & 40 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,30 @@ fn sdk_path(target: &str) -> Result<String, std::io::Error> {
}

use std::process::Command;

let sdk = if target.contains("apple-darwin") {
"macosx"
} else if target == "x86_64-apple-ios"
|| target == "i386-apple-ios"
|| target == "aarch64-apple-ios-sim"
{
"iphonesimulator"
} else if target == "aarch64-apple-ios"
|| target == "armv7-apple-ios"
|| target == "armv7s-apple-ios"
{
"iphoneos"
} else {
unreachable!();
let sdk = match target {
"aarch64-apple-darwin" | "x86_64-apple-darwin" => {
"macosx"
},
"x86_64-apple-ios" | "i386-apple-ios" | "aarch64-apple-ios-sim" => {
"iphonesimulator"
},
"aarch64-apple-ios" | "armv7-apple-ios" | "armv7s-apple-ios" => {
"iphoneos"
},
"aarch64-apple-visionos-sim" => "xrsimulator",
"aarch64-apple-visionos" => "xros",

"aarch64-apple-tvos-sim" | "x86_64-apple-tvos" => "appletvsimulator",
"aarch64-apple-tvos" => "appletvos",

"aarch64-apple-watchos" | "armv7k-apple-watchos" | "arm64_32-apple-watchos" => "watchos",
"aarch64-apple-watchos-sim" | "x86_64-apple-watchos-sim" => "watchsimulator",

target => {
panic!("{} is not supported!", target);
}
};

let output = Command::new("xcrun")
.args(&["--sdk", sdk, "--show-sdk-path"])
.output()?
Expand Down Expand Up @@ -52,42 +60,45 @@ fn build(sdk_path: Option<&str>, target: &str) {
// Since iOS 10.0 and macOS 10.12, all the functionality in AudioUnit
// moved to AudioToolbox, and the AudioUnit headers have been simple
// wrappers ever since.
if target.contains("apple-ios") {
// On iOS, the AudioUnit framework does not have (and never had) an
// actual dylib to link to, it is just a few header files.
// The AudioToolbox framework contains the symbols instead.
println!("cargo:rustc-link-lib=framework=AudioToolbox");
} else {
if target.contains("apple-darwin") {
// On macOS, the symbols are present in the AudioToolbox framework,
// but only on macOS 10.12 and above.
//
// However, unlike on iOS, the AudioUnit framework on macOS
// contains a dylib with the desired symbols, that we can link to
// (in later versions just re-exports from AudioToolbox).
println!("cargo:rustc-link-lib=framework=AudioUnit");
headers.push("AudioUnit/AudioUnit.h");
} else if !target.contains("apple-watchos") {
// On iOS, the AudioUnit framework does not have (and never had) an
// actual dylib to link to, it is just a few header files.
// The AudioToolbox framework contains the symbols instead.
println!("cargo:rustc-link-lib=framework=AudioToolbox");
headers.push("AudioUnit/AudioUnit.h");
}
headers.push("AudioUnit/AudioUnit.h");
}

#[cfg(feature = "audio_toolbox")]
{
println!("cargo:rustc-link-lib=framework=AudioToolbox");
headers.push("AudioToolbox/AudioToolbox.h");
if !target.contains("apple-watchos") {
headers.push("AudioToolbox/AudioToolbox.h");
}
}

#[cfg(feature = "core_audio")]
{
println!("cargo:rustc-link-lib=framework=CoreAudio");

if target.contains("apple-ios") {
headers.push("CoreAudio/CoreAudioTypes.h");
} else {
if target.contains("apple-darwin") {
headers.push("CoreAudio/CoreAudio.h");

#[cfg(feature = "audio_server_plugin")]
{
headers.push("CoreAudio/AudioServerPlugIn.h");
}
} else {
headers.push("CoreAudio/CoreAudioTypes.h");
}
}

Expand All @@ -100,9 +111,11 @@ fn build(sdk_path: Option<&str>, target: &str) {

#[cfg(feature = "open_al")]
{
println!("cargo:rustc-link-lib=framework=OpenAL");
headers.push("OpenAL/al.h");
headers.push("OpenAL/alc.h");
if target.contains("apple-tvos") || target.contains("apple-ios") || target.contains("apple-darwin") {
println!("cargo:rustc-link-lib=framework=OpenAL");
headers.push("OpenAL/al.h");
headers.push("OpenAL/alc.h");
}
}

#[cfg(all(feature = "core_midi"))]
Expand All @@ -123,21 +136,23 @@ fn build(sdk_path: Option<&str>, target: &str) {
// See https://github.com/rust-lang/rust-bindgen/issues/1211
// Technically according to the llvm mailing list, the argument to clang here should be
// -arch arm64 but it looks cleaner to just change the target.
let target = if target == "aarch64-apple-ios" {
"arm64-apple-ios"
} else if target == "aarch64-apple-darwin" {
"arm64-apple-darwin"
} else {
target
// The full list of clang targtes may be:
// https://github.com/llvm/llvm-project/blob/7476c20c481cbccbdb89139fb94620e083015932/llvm/include/llvm/BinaryFormat/MachO.def#L123-L138
let clang_target = match target {
"aarch64-apple-ios" => "arm64-apple-ios",
"aarch64-apple-visionos" => "arm64-apple-xros",
"aarch64-apple-visionos-sim" => "aarch64-apple-xros-simulator",
"aarch64-apple-darwin" => "arm64-apple-darwin",
target => target,
Comment on lines +139 to +146
Copy link
Member Author

Choose a reason for hiding this comment

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

I am unsure that this link is fully relevant/correct. Getting the target triple of aarch64-apple-xros-simulator took a bit of brute force... now that I look at it, I don't know that I tried arm64-aple-xros-simulator as a target. This passes with both aarch64-apple-xros-simulator and arm64-apple-xros-simulator. Neither are close to the rust target triples so I have no idea what to use.

Copy link

Choose a reason for hiding this comment

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

there was a conversation about this at clang and rust-lang.
Apple originally rolled out xros targets in llvm and clang. Later they released visionOS branding and that's what Xcode uses, but Xcode translates it to xros and sends it to clang. See my #102 notes.

};
builder = builder.size_t_is_usize(true);

builder = builder.clang_args(&[&format!("--target={}", target)]);
builder = builder.clang_args(&[&format!("--target={}", clang_target)]);

if let Some(sdk_path) = sdk_path {
builder = builder.clang_args(&["-isysroot", sdk_path]);
}
if target.contains("apple-ios") {
if !target.contains("apple-darwin") {
// time.h as has a variable called timezone that conflicts with some of the objective-c
// calls from NSCalendar.h in the Foundation framework. This removes that one variable.
builder = builder.blocklist_item("timezone");
Expand All @@ -159,7 +174,7 @@ fn build(sdk_path: Option<&str>, target: &str) {
// Generate the bindings.
builder = builder.trust_clang_mangling(false).derive_default(true);

let bindings = builder.generate().expect("unable to generate bindings");
let bindings = builder.generate().expect(format!("unable to generate bindings for {target}").as_str());

// Write them to the crate root.
bindings
Expand All @@ -169,8 +184,8 @@ fn build(sdk_path: Option<&str>, target: &str) {

fn main() {
let target = std::env::var("TARGET").unwrap();
if !(target.contains("apple-darwin") || target.contains("apple-ios")) {
panic!("coreaudio-sys requires macos or ios target");
if !target.contains("apple") {
panic!("coreaudio-sys requires an apple target.");
}

let directory = sdk_path(&target).ok();
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg(any(target_os = "macos", target_os = "ios"))]
#![cfg(target_vendor = "apple")]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
Expand Down