Skip to content

Commit dec2568

Browse files
committed
Simplify and fix bindgen setup both for native and cross compilation
The current setup requires 2 environment variables for cross-compilation, and can fail to build under some circumstances on a freshly installed OSX + Xcode machine. This change simplifies the setup by: - On native builds, using `xcrun --show-sdk-path` instead of `xcode-select -p` to find the SDK. - On cross builds, checking COREAUDIO_SDK_PATH. - Pass --target to clang, which makes things work for cross-compilation with plain clang (as opposed to osxcross). - Pass -isysroot to clang instead of -F, which makes it find all possible headers in the SDK, especially TargetConditionals.h, which lives in $COREAUDIO_SDK_PATH/usr/include. - Instruct cargo of the environment variables that affect the build script. COREAUDIO_CFLAGS is left as a convenience, for now.
1 parent 7150b8c commit dec2568

File tree

2 files changed

+29
-82
lines changed

2 files changed

+29
-82
lines changed

README.md

+3-11
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,10 @@ Raw bindings to Apple's Core Audio API for macos and iOS generated using [rust-b
1010

1111
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`.
1212

13-
#### `COREAUDIO_CFLAGS`
13+
#### `MACOS_SDK_PATH`
1414

15-
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:
15+
This tell `coreaudio-sys` where to find the MacOS SDK:
1616

1717
```bash
18-
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
19-
```
20-
21-
#### `COREAUDIO_FRAMEWORKS_PATH`
22-
23-
This tell `coreaudio-sys` where to find the Frameworks path of the MacOS SDK:
24-
25-
```bash
26-
export COREAUDIO_FRAMEWORKS_PATH=/build/osxcross/target/SDK/MacOSX10.11.sdk/System/Library/Frameworks
18+
export MACOS_SDK_PATH=/build/osxcross/target/SDK/MacOSX10.11.sdk
2719
```

build.rs

+26-71
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,32 @@
11
extern crate bindgen;
22

3-
fn osx_version() -> Result<String, std::io::Error> {
4-
use std::process::Command;
5-
6-
let output = Command::new("defaults")
7-
.arg("read")
8-
.arg("loginwindow")
9-
.arg("SystemVersionStampAsString")
10-
.output()?
11-
.stdout;
12-
let version_str = std::str::from_utf8(&output).expect("invalid output from `defaults`");
13-
let version = version_str.trim_right();
14-
15-
Ok(version.to_owned())
16-
}
17-
18-
fn parse_version(version: &str) -> Option<i32> {
19-
version
20-
.split(".")
21-
.skip(1)
22-
.next()
23-
.and_then(|m| m.parse::<i32>().ok())
24-
}
25-
26-
fn frameworks_path() -> Result<String, std::io::Error> {
27-
// For 10.13 and higher:
28-
//
29-
// While macOS has its system frameworks located at "/System/Library/Frameworks"
30-
// for actually linking against them (especially for cross-compilation) once
31-
// has to refer to the frameworks as found within "Xcode.app/Contents/Developer/…".
3+
const FRAMEWORKS_PATH: &'static str = "System/Library/Frameworks";
324

5+
fn sdk_path(target: &str) -> Result<String, std::io::Error> {
336
// Use environment variable if set
34-
if let Ok(path) = std::env::var("COREAUDIO_FRAMEWORKS_PATH") {
7+
println!("cargo:rerun-if-env-changed=COREAUDIO_SDK_PATH");
8+
if let Ok(path) = std::env::var("COREAUDIO_SDK_PATH") {
359
return Ok(path);
3610
}
3711

38-
if osx_version()
39-
.and_then(|version| Ok(parse_version(&version).map(|v| v >= 13).unwrap_or(false)))
40-
.unwrap_or(false)
41-
{
42-
use std::process::Command;
43-
44-
let output = Command::new("xcode-select").arg("-p").output()?.stdout;
45-
let prefix_str = std::str::from_utf8(&output).expect("invalid output from `xcode-select`");
46-
let prefix = prefix_str.trim_right();
47-
48-
let target = std::env::var("TARGET").unwrap();
49-
let platform = if target.contains("apple-darwin") {
50-
"MacOSX"
51-
} else if target.contains("apple-ios") {
52-
"iPhoneOS"
53-
} else {
54-
unreachable!();
55-
};
56-
57-
let infix = if prefix == "/Library/Developer/CommandLineTools" {
58-
format!("SDKs/{}.sdk", platform)
59-
} else {
60-
format!(
61-
"Platforms/{}.platform/Developer/SDKs/{}.sdk",
62-
platform, platform
63-
)
64-
};
65-
66-
let suffix = "System/Library/Frameworks";
67-
let directory = format!("{}/{}/{}", prefix, infix, suffix);
68-
69-
Ok(directory)
12+
use std::process::Command;
13+
14+
let sdk = if target.contains("apple-darwin") {
15+
"macosx"
16+
} else if target.contains("apple-ios") {
17+
"iphoneos"
7018
} else {
71-
Ok("/System/Library/Frameworks".to_string())
72-
}
19+
unreachable!();
20+
};
21+
let output = Command::new("xcrun")
22+
.args(&["--sdk", sdk, "--show-sdk-path"])
23+
.output()?
24+
.stdout;
25+
let prefix_str = std::str::from_utf8(&output).expect("invalid output from `xcrun`");
26+
Ok(prefix_str.trim_end().to_string())
7327
}
7428

75-
fn build(frameworks_path: &str) {
29+
fn build(sdk_path: &str, target: &str) {
7630
// Generate one large set of bindings for all frameworks.
7731
//
7832
// We do this rather than generating a module per framework as some frameworks depend on other
@@ -114,7 +68,7 @@ fn build(frameworks_path: &str) {
11468

11569
#[cfg(all(feature = "core_midi"))]
11670
{
117-
if std::env::var("TARGET").unwrap().contains("apple-darwin") {
71+
if target.contains("apple-darwin") {
11872
println!("cargo:rustc-link-lib=framework=CoreMIDI");
11973
headers.push("CoreMIDI.framework/Headers/CoreMIDI.h");
12074
}
@@ -126,11 +80,11 @@ fn build(frameworks_path: &str) {
12680
// Begin building the bindgen params.
12781
let mut builder = bindgen::Builder::default();
12882

129-
builder = builder.clang_arg(format!("-F/{}", frameworks_path));
83+
builder = builder.clang_args(&[&format!("--target={}", target), "-isysroot", sdk_path]);
13084

13185
// Add all headers.
13286
for relative_path in headers {
133-
let absolute_path = format!("{}/{}", frameworks_path, relative_path);
87+
let absolute_path = format!("{}/{}/{}", sdk_path, FRAMEWORKS_PATH, relative_path);
13488
builder = builder.header(absolute_path);
13589
}
13690

@@ -140,6 +94,7 @@ fn build(frameworks_path: &str) {
14094
.derive_default(true)
14195
.rustfmt_bindings(false);
14296

97+
println!("cargo:rerun-if-env-changed=COREAUDIO_CFLAGS");
14398
if let Ok(cflags) = std::env::var("COREAUDIO_CFLAGS") {
14499
builder = builder.clang_args(cflags.split(" "));
145100
}
@@ -158,9 +113,9 @@ fn main() {
158113
eprintln!("coreaudio-sys requires macos or ios target");
159114
}
160115

161-
if let Ok(directory) = frameworks_path() {
162-
build(&directory);
116+
if let Ok(directory) = sdk_path(&target) {
117+
build(&directory, &target);
163118
} else {
164-
eprintln!("coreaudio-sys could not find frameworks path");
119+
eprintln!("coreaudio-sys could not find an appropriate SDK");
165120
}
166121
}

0 commit comments

Comments
 (0)