coreaudio-sys
coreaudio-sys copied to clipboard
Doesn't cross-compile from Linux
Hi!
I tried to compile an Amethyst (mini) game for macos from my Linux, since I don't have a mac but some of my friends do. Here are my commands:
rustup default nightly
rustup install nightly-x86_64-apple-darwin
rustup target add x86_64-apple-darwin
cargo build --release --target=x86_64-apple-darwin
Everything went fine until:
$ cargo build --release --target=x86_64-apple-darwin 130 ↵
Compiling coreaudio-sys v0.2.2
error: couldn't read /home/totorigolo/Programmation/Rust/ldjam-43/target/x86_64-apple-darwin/release/build/coreaudio-sys-a35cb65331eb6c13/out/coreaudio.rs: No such file or directory (os error 2)
--> /home/totorigolo/.cargo/registry/src/github.com-1ecc6299db9ec823/coreaudio-sys-0.2.2/src/lib.rs:6:1
|
6 | include!(concat!(env!("OUT_DIR"), "/coreaudio.rs"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
error: Could not compile `coreaudio-sys`.
To learn more, run the command again with --verbose.
In ./target/x86_64-apple-darwin/release/build/coreaudio-sys-a35cb65331eb6c13/
, there is this error:
coreaudio-sys requires macos or ios target
Any ideas on how I can fix this? On the 368 dependencies, at least 360 do compile, so I guess that it's not the only crate that does bindings.
$ cargo --version --verbose
cargo 1.32.0-nightly (5e85ba14a 2018-12-02)
release: 1.32.0
commit-hash: 5e85ba14aaa20f8133863373404cb0af69eeef2c
commit-date: 2018-12-02
$ rustc --version --verbose
... cannot execute binary file
$ rustup update
info: syncing channel updates for 'nightly-x86_64-apple-darwin'
...
info: latest update on 2018-12-06, rust version 1.32.0-nightly (14997d56a 2018-12-05)
...
You need xcode headers installed to build, no way around that fact unfortunately.
One way for cross-compiling is to import your own raw bindings rather than using bindgen on the platform that you have no idea where those headers are. servo's core-foundation-rs is an example.
You could copy the coreaudio.rs generated from this crate and replace #[link = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/XXXX"]
to #[link(name = "XXXX", kind = "framework")]
as your fullback raw bindings. core-audio-sys might be another choice, but I am not sure how many bindings it provides.
If you're running on non-apple os, but your std::env::var("TARGET")
is one of apple series, e.g., x86_64-apple-darwin
or i686-apple-darwin
(see all support target here), you can link to the frameworks by cargo:rustc-link-lib=framework=XXXX
as long as they are installed. In lib.rs, including the fullback raw bindings instead of the env!("OUT_DIR")/coreaudio.rs
should make it work.
Specifically, you can change the non-apple-os case in build.rs like:
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
fn main() {
let target = std::env::var("TARGET").unwrap();
// Using the fullback raw bindings instead
if target.contains("-apple") {
println!("cargo:rustc-link-lib=framework=AudioUnit");
println!("cargo:rustc-link-lib=framework=CoreAudio");
println!("cargo:rustc-cfg=fullback_bindings");
} else {
eprintln!("{} is not a valid target for coreaudio-sys.", target);
}
}
In the lib.rs, include your fullback raw bindings if the bindings doesn't be generated from the bindgen:
#[cfg(fullback_bindings)]
include!("fullback_coreaudio.rs");
#[cfg(not(fullback_bindings))]
include!(concat!(env!("OUT_DIR"), "/coreaudio.rs"));
and the fullback raw bindings(fullback_coreaudio.rs here) may look like
// Replace #[link = "...../SDKs/MacOSX.sdk/System/Library/Frameworks/AudioUnit"]
#[link(name = "AudioUnit", kind = "framework")]
// Replace #[link = "...../SDKs/MacOSX.sdk/System/Library/Frameworks/CoreAudio"]
#[link(name = "CoreAudio", kind = "framework")]|
// Replace #[link = "...../SDKs/MacOSX.sdk/System/Library/Frameworks/XXXX"]
#[link(name = "XXXX", kind = "framework")]|
...
// The following code is copied from coreaudio.rs generated from the bindgen
...
...
...
pub const TARGET_OS_MAC : u32 = 1 ; ....
Hope this helps.
I am getting the same exact issue, but I do have the MacOS headers ( the whole SDK and the cross-compiler toolchain built with osxcross ). What I'm confused at is that the message coreaudio-sys requires macos or ios target
should only be displayed when the target is not either "macos" or "ios". If I've set the cargo --target to x86_64-apple-darwin shouldn't that set the target to "macos"?
Also, after patching the build.rs script for this repo and hardcoding the path to the frameworks path, I still get an error:
error: failed to run custom build command for `coreaudio-sys v0.2.2`
process didn't exit successfully: `/arsenal/arsenal-runtime/target/debug/build/coreaudio-sys-110096316bbc4140/build-script-build` (exit code: 101)
--- stdout
cargo:rustc-link-lib=framework=AudioUnit
cargo:rustc-link-lib=framework=CoreAudio
--- stderr
/System/Library/Frameworks/AudioUnit.framework/Headers/AudioUnit.h:12:10: fatal error: 'TargetConditionals.h' file not found
/System/Library/Frameworks/AudioUnit.framework/Headers/AudioUnit.h:12:10: fatal error: 'TargetConditionals.h' file not found, err: true
thread 'main' panicked at 'unable to generate bindings: ()', src/libcore/result.rs:997:5
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
It looks like it just isn't adding the /System/Library/Frameworks/Kernel.framework/Headers
dir to the include path, but I don't know how to add it.
It's very likely that to get this working with iOS there might be some tweaking necessary, as I've only tested this with macOS since the last bindgen update.
Very open to PRs for both fallback bindings and any tweaks required to get iOS working!
I got this to compile on my Linux system for Mac with the following diff to the build.rs
file ( note that I symlinked the /System
dir from the OSX SDK to /System
on my host ):
diff --git a/build.rs b/build.rs
index 2974293..0ab4036 100644
--- a/build.rs
+++ b/build.rs
@@ -140,6 +140,7 @@ fn build(frameworks_path: &str) {
// Generate the bindings.
let bindings = builder
+ .clang_args(&["-I/System/Library/Frameworks/Kernel.framework/Headers", "-I/build/osxcros
s/target/SDK/MacOSX10.11.sdk/usr/include"])
.trust_clang_mangling(false)
.derive_default(true)
.rustfmt_bindings(false)
@@ -152,16 +153,16 @@ fn build(frameworks_path: &str) {
.expect("could not write bindings");
}
-#[cfg(any(target_os = "macos", target_os = "ios"))]
+//#[cfg(any(target_os = "macos", target_os = "ios"))]
fn main() {
- if let Ok(directory) = frameworks_path() {
- build(&directory);
- } else {
- eprintln!("coreaudio-sys could not find frameworks path");
- }
+ //if let Ok(directory) = frameworks_path() {
+ build("/System/Library/Frameworks");
+ //} else {
+ //eprintln!("coreaudio-sys could not find frameworks path");
+ //}
}
-#[cfg(not(any(target_os = "macos", target_os = "ios")))]
-fn main() {
- eprintln!("coreaudio-sys requires macos or ios target");
-}
+//#[cfg(not(any(target_os = "macos", target_os = "ios")))]
+//fn main() {
+ //eprintln!("coreaudio-sys requires macos or ios target");
+//}
So first I have to understand why building with cargo build --target x86_64-apple-darwin
causes the second main()
function to run and output coreaudio-sys requires macos or ios target
error. For some reason it is not detecting that I am building for MacOS.
Second @mitchmindtree what do you think about reading from a CFLAGS
environment variable to allow you to add those -I/path/to/headers
flags that I needed to add? Or do you know if there is a way to automate the detection of those headers and add them to the path. I'm thinking that there probably isn't because I'm not a Linux system and not a Mac.
I'm good submitting a PR for a way to make this work, I just need to know how we want to handle this.
I think I just figured out why this isn't correctly detecting that I'm building for MacOS:
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
The problem with the line above is that the build.rs
script isn't getting built for MacOS. The build script is getting build for Linux because the build script gets run by Cargo on my host system, not on the target system. That means that we need a different way to tell whether or not the application target is MacOS.
Edit: We can use the TARGET
environment variable that is set by Cargo to the target triple. If we do that to detect the target and additionally read a CFLAGS
environment variable to allow setting the extra include directories, that would make it possible to compile on Linux, at least in my environment. It would probably be good to have an environment variable like FRAMEWORK_PATH as well for people who don't want to drop the System
dir in the root of their fileystem ( I don't mind because I'm building inside of a container, but probably I would mind if it were anywhere else ).