Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Doesn't cross-compile from Linux #23

Open
totorigolo opened this issue Dec 5, 2018 · 6 comments
Open

Doesn't cross-compile from Linux #23

totorigolo opened this issue Dec 5, 2018 · 6 comments

Comments

@totorigolo
Copy link

totorigolo commented Dec 5, 2018

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)
...
@Rhuagh
Copy link
Collaborator

Rhuagh commented Dec 7, 2018

You need xcode headers installed to build, no way around that fact unfortunately.

@ChunMinChang
Copy link

ChunMinChang commented Mar 1, 2019

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.

@zicklag
Copy link
Contributor

zicklag commented Jul 1, 2019

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.

@mitchmindtree
Copy link
Member

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!

@zicklag
Copy link
Contributor

zicklag commented Jul 1, 2019

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.

@zicklag
Copy link
Contributor

zicklag commented Jul 1, 2019

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 ).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants