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

Mac Catalyst (macabi) target objects fail to link #106021

Closed
ara4n opened this issue Dec 21, 2022 · 16 comments · Fixed by gimli-rs/object#524
Closed

Mac Catalyst (macabi) target objects fail to link #106021

ara4n opened this issue Dec 21, 2022 · 16 comments · Fixed by gimli-rs/object#524
Assignees
Labels
A-linkage Area: linking into static, shared libraries and binaries C-bug Category: This is a bug. O-ios Operating system: iOS O-macos Operating system: macOS T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@ara4n
Copy link

ara4n commented Dec 21, 2022

If you attempt to build a library for Mac Catalyst (target aarch64-apple-ios-macabi) on current nightly on Ventura (13.1), it fails to link with errors like:

ld: in /Users/matthew/workspace/matrix-rust-sdk/target/aarch64-apple-ios-macabi/dbg/deps/libstatic_assertions-fdafb4b8ba800a8a.rlib(lib.rmeta), building for Mac Catalyst, but linking in object file built for , file '/Users/matthew/workspace/matrix-rust-sdk/target/aarch64-apple-ios-macabi/dbg/deps/libstatic_assertions-fdafb4b8ba800a8a.rlib' for architecture arm64

This is because the synthetic Mach-O object files (symbols.o and lib.rmeta) emitted by object lack LC_BUILD_VERSION load commands to identify them as compatible with Catalyst, so ld complains they have a blank platform: "linking in object file built for ,".

rustc uses gimli's object to write these object files, so object needs to be extended to support writing LC_BUILD_VERSION, and then rustc needs to be fixed to write it when building for Catalyst.

I hacked this together as per https://gist.github.com/ara4n/320a53ea768aba51afad4c9ed2168536, but a) this is the first time i've written any rust, b) turns out i don't need Catalyst after all, c) i'm not sure the changes to object have the right abstractions, d) I don't have bandwidth to land it. So am opening this issue as a breadcrumb trail in the hope someone else finds it useful and can finish it off.

@ara4n ara4n added the C-bug Category: This is a bug. label Dec 21, 2022
@inquisitivecrystal inquisitivecrystal added O-macos Operating system: macOS O-ios Operating system: iOS A-linkage Area: linking into static, shared libraries and binaries T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Dec 22, 2022
@thomcc
Copy link
Member

thomcc commented Dec 29, 2022

Thanks for the report, I can probably take this over (but not until after the new year).

@imWildCat
Copy link
Contributor

Hello @thomcc ! Any hint on this bug?

I'm pretty new to LLVM/Rust compiler. If I could have some hint, I may start a draft PR in https://github.com/gimli-rs/object first.

@kgrech
Copy link

kgrech commented Feb 16, 2023

I see the same error when build for both aarch64-apple-ios-macabi and x86_64-apple-ios-macabi
if I have

[lib]
crate-type = ["cdylib"]

If I change it to crate-type = ["staticlib"], then it links, however the *.a produced fails to link to any xcode project with the same error message :(

@imWildCat
Copy link
Contributor

I got a workaround for this problem using mold instead of ld. Use this at your own risk.

I was not able to update my my Catalyst app due to this issue for over half a year. Going to use it.

brew install mold
which mold

vim ~/.cargo/config.toml and add:

[target.aarch64-apple-ios-macabi]
linker = "/usr/bin/clang"
rustflags = ["-C", "link-arg=--ld-path=/opt/homebrew/bin/mold"]

Background:

  1. I spent this weekend to set up macOS 11.0 to use old Xcode to build my rust static lib for a Catalyst project. It worked.
  2. After that, I was thinking about using old Xcode in a newer version of macOS. However, this didn't work. Possibly because cargo was still using the default ld
  3. So I thought: What if I switch to a different linker without so much Apple magic? https://github.com/rui314/mold is a great option
  4. Switched to mold and it works perfectly

cc @ara4n @kgrech @thomcc

@imWildCat
Copy link
Contributor

I got a workaround for this problem using mold instead of ld. Use this at your own risk.

I was not able to update my my Catalyst app due to this issue for over half a year. Going to use it.

brew install mold
which mold

vim ~/.cargo/config.toml and add:

[target.aarch64-apple-ios-macabi]
linker = "/usr/bin/clang"
rustflags = ["-C", "link-arg=--ld-path=/opt/homebrew/bin/mold"]

Background:

  1. I spent this weekend to set up macOS 11.0 to use old Xcode to build my rust static lib for a Catalyst project. It worked.
  2. After that, I was thinking about using old Xcode in a newer version of macOS. However, this didn't work. Possibly because cargo was still using the default ld
  3. So I thought: What if I switch to a different linker without so much Apple magic? https://github.com/rui314/mold is a great option
  4. Switched to mold and it works perfectly

cc @ara4n @kgrech @thomcc

Please note that mold linker does not work for iOS or macOS. We need a commercial license for that.

When build my app end-to-end, there's still a linker error:

image

Sorry, but I decided to stop working for the Mac Catalyst platform.

@protonjohn
Copy link

For those of us wishing to ship Rust code in Mac Catalyst apps, this thread remains very interesting and relevant :) I would encourage you to keep pulling on the thread, but if you've determined it's not worth the effort, I'd appreciate someone else experienced in the Dark Arts picking this up.

@thomcc
Copy link
Member

thomcc commented Mar 25, 2023

Sorry for the delay here.

@simlay
Copy link
Contributor

simlay commented Mar 26, 2023

It's unclear if it's related or not but in LaurentMazare/tch-rs#660 when doing a clean build for aarch64-apple-ios-sim from m1 macOS (13.2.1), I get:

ld: in /Users/simlay/projects/tch-rs/target/debug/deps/libring-9ce1a2518f1231ce.rlib(aesv8-armx-ios64.o), building for macOS, but linking in object file built for iOS, file '/Users/simlay/projects/tch-rs/target/debug/deps/libring-9ce1a2518f1231ce.rlib' for architecture arm64

In this case, ring is a sub-dependency of ureqand ureq is a strictly a build-dependency. This could be an issue with ring but I'm actually not sure how to give this bug more context.

@munhitsu
Copy link

munhitsu commented Apr 7, 2023

This might be a separate issue looking at timing but since after the nightly 2023-02-02 I can't build Catalyst output and bundle it into xcframework.
See: https://github.com/automerge/automerge-swifter/pull/18/files

@imWildCat
Copy link
Contributor

Hello @thomcc, thanks for your help to kick off the first step.

Last night, I was trying to patch the Rust compiler according to @ara4n's GH gist. However, I found we could not initialize MachOBuildVersion because it is marked as non_exhaustive.

#[derive(Debug, Default, Clone, Copy)]
#[non_exhaustive] // May want to add the tool list?
pub struct MachOBuildVersion {
    /// One of the `PLATFORM_` constants (for example,
    /// [`object::macho::PLATFORM_MACOS`](macho::PLATFORM_MACOS)).
    pub platform: u32,
    /// The minimum OS version, where `X.Y.Z` is encoded in nibbles as
    /// `xxxx.yy.zz`.
    pub minos: u32,
    /// The SDK version as `X.Y.Z`, where `X.Y.Z` is encoded in nibbles as
    /// `xxxx.yy.zz`.
    pub sdk: u32,
}
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -140,6 +140,14 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
     };
 
     let mut file = write::Object::new(binary_format, architecture, endianness);
+    if sess.target.llvm_target.ends_with("-macabi") {
+        let version = write::MachOBuildVersion {
+            platform: object::macho::PLATFORM_MACCATALYST,
+            minos: 0x000E0000,
+            sdk: 0x00100200,
+        };
+        file.set_macho_build_version(version);
+    }
     let e_flags = match architecture {
         Architecture::Mips => {
             let arch = match sess.target.options.cpu.as_ref() {

May I have some hints about how to initialize a MachOBuildVersion?

I was just trying it on my own. Please feel free to do it if you have the bandwidth.

Thanks!

@philipc
Copy link
Contributor

philipc commented Apr 16, 2023

You should be able use ..Default::default().

@imWildCat
Copy link
Contributor

@philipc thanks!

updated the lib object and found a new error at a line where I didn't make any change:

error[E0277]: the trait bound `StreamingBuffer<BufWriter<std::fs::File>>: object::write::util::WritableBuffer` is not satisfied
   --> compiler/rustc_codegen_ssa/src/back/link.rs:649:32
    |
649 |         package.finish()?.emit(&mut output_stream)?;
    |                                ^^^^^^^^^^^^^^^^^^ the trait `object::write::util::WritableBuffer` is not implemented for `StreamingBuffer<BufWriter<std::fs::File>>`
    |
    = help: the following other types implement trait `object::write::util::WritableBuffer`:
              Vec<u8>
              object::write::util::StreamingBuffer<W>
    = note: required for the cast from `StreamingBuffer<BufWriter<std::fs::File>>` to the object type `dyn object::write::util::WritableBuffer`

   Compiling rustc_transmute v0.1.0 (/Volumes/QuickMac/rust/compiler/rustc_transmute)
For more information about this error, try `rustc --explain E0277`.
error: could not compile `rustc_codegen_ssa` due to previous error
warning: build failed, waiting for other jobs to finish...
Build completed unsuccessfully in 0:01:50

https://github.com/imWildCat/rust/pull/1/files

Not sure about how to fix it. May I have some hint please? Thanks!

@philipc
Copy link
Contributor

philipc commented Apr 19, 2023

That's due to mixing different versions of the object crate. In this case, thorin-dwp still depends on the older version. See rust-lang/thorin#24

bmisiak added a commit to bmisiak/rust that referenced this issue May 25, 2023
Issue rust-lang#106021
Apple LD requires build versions in object files for Catalyst
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue May 25, 2023
…henkov

Fix linking Mac Catalyst by including LC_BUILD_VERSION in object files

Hello. My first rustc PR!

Issue rust-lang#106021 prevents Rust code from being linked into Mac Catalyst applications. Apple's LD has started requiring object files to contain version information about the platform they were built for, such as:
* the "deployment target" (minimum supported OS version),
* the SDK version
* the type of the platform (macOS/iOS/catalyst/tvOS/watchOS all have a different number).

This is currently only enforced when building for Mac Catalyst.

Rust uses the `object` crate which added support for including this information starting with `0.31.0`. ~~I upgraded it along with `thorin-dwp` so that everything depends on 0.31.
Apparently 0.31 [pulls in](gimli-rs/object#463) `ruzstd` due to a [new ELF standard](https://maskray.me/blog/2022-09-09-zstd-compressed-debug-sections) because its `compression` feature is enabled by thorin. If you find this objectionable, let me know what the best way to avoid pulling in those dependencies might be.~~

**(`object` upgraded in rust-lang#111413

I then added two commits:
* The first one adds very basic, hard-coded support for calling `set_macho_build_version` for `-macabi` (Catalyst) targets, where it claims deployment target of Catalyst 14.0 and SDK of 16.2.
* The second weaves the versioning through `rust_target::spec::TargetOptions`, so that we can stick to specifying all target-related info in one place.

Kudos to `@ara4n` for writing [this gist](https://gist.github.com/ara4n/320a53ea768aba51afad4c9ed2168536).
compiler-errors added a commit to compiler-errors/rust that referenced this issue May 26, 2023
…henkov

Fix linking Mac Catalyst by including LC_BUILD_VERSION in object files

Hello. My first rustc PR!

Issue rust-lang#106021 prevents Rust code from being linked into Mac Catalyst applications. Apple's LD has started requiring object files to contain version information about the platform they were built for, such as:
* the "deployment target" (minimum supported OS version),
* the SDK version
* the type of the platform (macOS/iOS/catalyst/tvOS/watchOS all have a different number).

This is currently only enforced when building for Mac Catalyst.

Rust uses the `object` crate which added support for including this information starting with `0.31.0`. ~~I upgraded it along with `thorin-dwp` so that everything depends on 0.31.
Apparently 0.31 [pulls in](gimli-rs/object#463) `ruzstd` due to a [new ELF standard](https://maskray.me/blog/2022-09-09-zstd-compressed-debug-sections) because its `compression` feature is enabled by thorin. If you find this objectionable, let me know what the best way to avoid pulling in those dependencies might be.~~

**(`object` upgraded in rust-lang#111413

I then added two commits:
* The first one adds very basic, hard-coded support for calling `set_macho_build_version` for `-macabi` (Catalyst) targets, where it claims deployment target of Catalyst 14.0 and SDK of 16.2.
* The second weaves the versioning through `rust_target::spec::TargetOptions`, so that we can stick to specifying all target-related info in one place.

Kudos to `@ara4n` for writing [this gist](https://gist.github.com/ara4n/320a53ea768aba51afad4c9ed2168536).
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue May 26, 2023
…henkov

Fix linking Mac Catalyst by including LC_BUILD_VERSION in object files

Hello. My first rustc PR!

Issue rust-lang#106021 prevents Rust code from being linked into Mac Catalyst applications. Apple's LD has started requiring object files to contain version information about the platform they were built for, such as:
* the "deployment target" (minimum supported OS version),
* the SDK version
* the type of the platform (macOS/iOS/catalyst/tvOS/watchOS all have a different number).

This is currently only enforced when building for Mac Catalyst.

Rust uses the `object` crate which added support for including this information starting with `0.31.0`. ~~I upgraded it along with `thorin-dwp` so that everything depends on 0.31.
Apparently 0.31 [pulls in](gimli-rs/object#463) `ruzstd` due to a [new ELF standard](https://maskray.me/blog/2022-09-09-zstd-compressed-debug-sections) because its `compression` feature is enabled by thorin. If you find this objectionable, let me know what the best way to avoid pulling in those dependencies might be.~~

**(`object` upgraded in rust-lang#111413

I then added two commits:
* The first one adds very basic, hard-coded support for calling `set_macho_build_version` for `-macabi` (Catalyst) targets, where it claims deployment target of Catalyst 14.0 and SDK of 16.2.
* The second weaves the versioning through `rust_target::spec::TargetOptions`, so that we can stick to specifying all target-related info in one place.

Kudos to ``@ara4n`` for writing [this gist](https://gist.github.com/ara4n/320a53ea768aba51afad4c9ed2168536).
@spullara
Copy link

This might be a separate issue looking at timing but since after the nightly 2023-02-02 I can't build Catalyst output and bundle it into xcframework.
See: https://github.com/automerge/automerge-swifter/pull/18/files

This worked for me. Hopefully we can get this fixed in latest Rust.

@bmisiak
Copy link
Contributor

bmisiak commented Aug 28, 2023

Should be fixed since #111384 is merged and released with Rust 1.71. Okay to close?

@workingjubilee
Copy link
Member

Agreed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-linkage Area: linking into static, shared libraries and binaries C-bug Category: This is a bug. O-ios Operating system: iOS O-macos Operating system: macOS T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.