Skip to content

Commit

Permalink
Merge pull request #28 from glandium/build-script
Browse files Browse the repository at this point in the history
Various changes to the build script
  • Loading branch information
mitchmindtree authored Aug 27, 2019
2 parents 13a32d7 + 0ed7f4c commit 824d3f5
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 122 deletions.
8 changes: 6 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down
14 changes: 3 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
149 changes: 42 additions & 107 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,78 +1,30 @@
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> {
// 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<String, std::io::Error> {
// 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
Expand All @@ -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
Expand All @@ -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);
}

0 comments on commit 824d3f5

Please sign in to comment.