Skip to content

Commit

Permalink
Support visionOS, watchOS, and tvOS
Browse files Browse the repository at this point in the history
Co-authored By: Eugene Hauptmann <eugene@reactivelions.com>
  • Loading branch information
simlay committed Jun 8, 2024
1 parent e7dafbd commit 9cc7712
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 41 deletions.
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-sim,
]
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,
};
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

0 comments on commit 9cc7712

Please sign in to comment.