diff --git a/.travis.yml b/.travis.yml index 42967b0..c48317b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,9 +8,13 @@ notifications: - mitchell.nordine@gmail.com os: - osx +- linux before_script: - rustc --version - cargo --version +- rustup component add rustfmt +- if [ "$TRAVIS_OS_NAME" = linux ]; then rustup target add x86_64-apple-darwin; fi script: -- cargo build --verbose -- cargo test --verbose +- if [ "$TRAVIS_OS_NAME" = linux ]; then curl -sL https://github.com/phracker/MacOSX-SDKs/releases/download/10.13/MacOSX10.13.sdk.tar.xz | tar -Jxf -; export COREAUDIO_SDK_PATH="$PWD/MacOSX10.13.sdk"; fi +- cargo build --verbose --target=x86_64-apple-darwin +- if [ "$TRAVIS_OS_NAME" = osx ]; then cargo test --verbose; fi diff --git a/Cargo.toml b/Cargo.toml index ff180a0..1aebb0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,8 +10,9 @@ homepage = "https://github.com/RustAudio/coreaudio-sys" repository = "https://github.com/RustAudio/coreaudio-sys.git" build = "build.rs" -[build-dependencies] -bindgen = "0.42" +[build-dependencies.bindgen] +version = "0.50" +default-features = false [features] default = ["audio_toolbox", "audio_unit", "core_audio", "open_al", "core_midi"] diff --git a/README.md b/README.md index 34ebc55..2b6557c 100644 --- a/README.md +++ b/README.md @@ -10,18 +10,10 @@ Raw bindings to Apple's Core Audio API for macos and iOS generated using [rust-b When cross-compiling for MacOS on Linux there are two environment variables that are used to configure how `coreaudio-sys` finds the required headers and libraries. The following examples assume that you have OSXCross installed at `/build/osxcross`. -#### `COREAUDIO_CFLAGS` +#### `COREAUDIO_SDK_PATH` -This allows you to add arbitrary flags to the `clang` call that is made when auto-generating the Rust bindings to coreaudio. This will need to be set to include some headers used by coreaudio: +This tell `coreaudio-sys` where to find the MacOS SDK: ```bash -export COREAUDIO_CFLAGS=-I/build/osxcross/target/SDK/MacOSX10.11.sdk/System/Library/Frameworks/Kernel.framework/Headers -I/build/osxcross/target/SDK/MacOSX10.11.sdk/usr/include -``` - -#### `COREAUDIO_FRAMEWORKS_PATH` - -This tell `coreaudio-sys` where to find the Frameworks path of the MacOS SDK: - -```bash -export COREAUDIO_FRAMEWORKS_PATH=/build/osxcross/target/SDK/MacOSX10.11.sdk/System/Library/Frameworks +export COREAUDIO_SDK_PATH=/build/osxcross/target/SDK/MacOSX10.11.sdk ``` diff --git a/build.rs b/build.rs index 350761d..2b511e0 100644 --- a/build.rs +++ b/build.rs @@ -1,78 +1,30 @@ extern crate bindgen; -fn osx_version() -> Result { - 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 { - version - .split(".") - .skip(1) - .next() - .and_then(|m| m.parse::().ok()) -} - -fn frameworks_path() -> Result { - // For 10.13 and higher: - // - // While macOS has its system frameworks located at "/System/Library/Frameworks" - // for actually linking against them (especially for cross-compilation) once - // has to refer to the frameworks as found within "Xcode.app/Contents/Developer/…". - +fn sdk_path(target: &str) -> Result { // Use environment variable if set - if let Ok(path) = std::env::var("COREAUDIO_FRAMEWORKS_PATH") { - return Ok(path) + println!("cargo:rerun-if-env-changed=COREAUDIO_SDK_PATH"); + if let Ok(path) = std::env::var("COREAUDIO_SDK_PATH") { + return Ok(path); } - 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 target = std::env::var("TARGET").unwrap(); - let platform = if target.contains("apple-darwin") { - "MacOSX" - } else if target.contains("apple-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) + use std::process::Command; + + let sdk = if target.contains("apple-darwin") { + "macosx" + } else if target.contains("apple-ios") { + "iphoneos" } else { - Ok("/System/Library/Frameworks".to_string()) - } + unreachable!(); + }; + let output = Command::new("xcrun") + .args(&["--sdk", sdk, "--show-sdk-path"]) + .output()? + .stdout; + let prefix_str = std::str::from_utf8(&output).expect("invalid output from `xcrun`"); + Ok(prefix_str.trim_end().to_string()) } -fn build(frameworks_path: &str) { +fn build(sdk_path: Option<&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 @@ -85,80 +37,67 @@ 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"); + headers.push("AudioToolbox/AudioToolbox.h"); } #[cfg(feature = "audio_unit")] { println!("cargo:rustc-link-lib=framework=AudioUnit"); - frameworks.push("AudioUnit"); - headers.push("AudioUnit.framework/Headers/AudioUnit.h"); + headers.push("AudioUnit/AudioUnit.h"); } #[cfg(feature = "core_audio")] { println!("cargo:rustc-link-lib=framework=CoreAudio"); - frameworks.push("CoreAudio"); - headers.push("CoreAudio.framework/Headers/CoreAudio.h"); + headers.push("CoreAudio/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"); + headers.push("OpenAL/al.h"); + headers.push("OpenAL/alc.h"); } #[cfg(all(feature = "core_midi"))] { - if std::env::var("TARGET").unwrap().contains("apple-darwin") { + if target.contains("apple-darwin") { println!("cargo:rustc-link-lib=framework=CoreMIDI"); - frameworks.push("CoreMIDI"); - headers.push("CoreMIDI.framework/Headers/CoreMIDI.h"); + headers.push("CoreMIDI/CoreMIDI.h"); } } + println!("cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS"); // Get the cargo out directory. let out_dir = PathBuf::from(env::var("OUT_DIR").expect("env variable OUT_DIR not found")); // Begin building the bindgen params. let mut builder = bindgen::Builder::default(); - builder = builder.clang_arg(format!("-F/{}", frameworks_path)); + builder = builder.clang_args(&[&format!("--target={}", target)]); - // Add all headers. - for relative_path in headers { - let absolute_path = format!("{}/{}", frameworks_path, relative_path); - builder = builder.header(absolute_path); + if let Some(sdk_path) = sdk_path { + builder = builder.clang_args(&["-isysroot", sdk_path]); } - // Link to all frameworks. - for relative_path in frameworks { - let link_instruction = format!("#[link = \"{}/{}\"]", frameworks_path, relative_path); - builder = builder.raw_line(link_instruction); - } + let meta_header: Vec<_> = headers + .iter() + .map(|h| format!("#include <{}>\n", h)) + .collect(); + + builder = builder.header_contents("coreaudio.h", &meta_header.concat()); // Generate the bindings. builder = builder .trust_clang_mangling(false) - .derive_default(true) - .rustfmt_bindings(false); - - if let Ok(cflags) = std::env::var("COREAUDIO_CFLAGS") { - builder = builder.clang_args(cflags.split(" ")); - } + .derive_default(true); - let bindings = builder - .generate() - .expect("unable to generate bindings"); + let bindings = builder.generate().expect("unable to generate bindings"); // Write them to the crate root. bindings @@ -168,14 +107,10 @@ fn build(frameworks_path: &str) { fn main() { let target = std::env::var("TARGET").unwrap(); - if ! (target.contains("apple-darwin") || target.contains("apple-ios")) { - eprintln!("coreaudio-sys requires macos or ios target"); + if !(target.contains("apple-darwin") || target.contains("apple-ios")) { + panic!("coreaudio-sys requires macos or ios target"); } - if let Ok(directory) = frameworks_path() { - build(&directory); - } else { - eprintln!("coreaudio-sys could not find frameworks path"); - } + let directory = sdk_path(&target).ok(); + build(directory.as_ref().map(String::as_ref), &target); } -