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

Provide libgcc linker script workaround for NDK >= 23 #67

Merged
merged 1 commit into from Jul 24, 2022

Conversation

rib
Copy link
Contributor

@rib rib commented Jul 23, 2022

libgcc was removed from NDK v23 which breaks Rust builds against pre-built standard libraries that were linked against libgcc instead of libunwind.

As a workaround this ensures that there is a libgcc.a in the library search paths which is a linker script that will redirect to link with libunwind instead.

The libgcc.a linker script is created under:
target/cargo-ndk/libgcc_workaround/libgcc.a

Fixes: #22

For reference the underlying issue has been fixed upstream but it still depends on building the std library from source (via -Zbuild-std) instead of using the pre-built libraries distributed via rustup. This currently means using a nightly toolchain. See: rust-lang/rust#85806

@MarijnS95
Copy link

You might want to look at how we implemented and evolved this workaround in ndk-build instead.

@rib
Copy link
Contributor Author

rib commented Jul 24, 2022

er, okey? I mean fwiw I did skim it before I opened this PR and it vaguely looked similar - not sure what the frowny face is about here - I guess I've stepped on a nerve? maybe you could say what's wrong with this?

@rib
Copy link
Contributor Author

rib commented Jul 24, 2022

For reference this is the code in ndk-build:

// Workaround for https://github.com/rust-windowing/android-ndk-rs/issues/149:
    // Rust (1.56 as of writing) still requires libgcc during linking, but this does
    // not ship with the NDK anymore since NDK r23 beta 3.
    // See https://github.com/rust-lang/rust/pull/85806 for a discussion on why libgcc
    // is still required even after replacing it with libunwind in the source.
    // XXX: Add an upper-bound on the Rust version whenever this is not necessary anymore.
    if ndk.build_tag() > 7272597 {
        let cargo_apk_link_dir = target_dir
            .as_ref()
            .join("cargo-apk-temp-extra-link-libraries");
        std::fs::create_dir_all(&cargo_apk_link_dir)
            .map_err(|e| NdkError::IoPathError(cargo_apk_link_dir.clone(), e))?;
        let libgcc = cargo_apk_link_dir.join("libgcc.a");
        std::fs::write(&libgcc, "INPUT(-lunwind)").map_err(|e| NdkError::IoPathError(libgcc, e))?;

        // cdylibs in transitive dependencies still get built and also need this
        // workaround linker flag, yet arguments passed to `cargo rustc` are only
        // forwarded to the final compiler invocation rendering our workaround ineffective.
        // The cargo page documenting this discrepancy (https://doc.rust-lang.org/cargo/commands/cargo-rustc.html)
        // suggests to resort to RUSTFLAGS.
        // Note that `rustflags` will never be empty because of an unconditional `.push_str` above,
        // so we can safely start with appending \x1f here.
        rustflags.push_str("\x1f-L\x1f");
        rustflags.push_str(
            cargo_apk_link_dir
                .to_str()
                .expect("Target dir must be valid UTF-8"),
        );
    }

    cargo.env("CARGO_ENCODED_RUSTFLAGS", rustflags);

Although I wrote the patch before going to check this, I did actually already check this out of curiosity and it looks pretty similar to what my PR does?

There are more comments here about RUSTFLAGS I guess because some other solution didn't work out and I suppose it's just dumb luck that I went with passing the -L flag with RUSTFLAGS.

It would probably be good to use CARGO_ENCODED_RUSTFLAGS considering the possibility of target directory paths with spaces - maybe that's what you were thinking of?

libgcc was removed from NDK v23 which breaks Rust builds against
pre-built standard libraries that were linked against libgcc
instead of libunwind.

As a workaround this ensures that there is a libgcc.a in the
library search paths which is a linker script that will redirect
to link with libunwind instead.

The libgcc.a linker script is created under:

 target/cargo-ndk/libgcc-workaround/libgcc.a

Fixes: bbqsrc#22
@rib rib force-pushed the libgcc-linker-script-workaround branch from 0b4a77f to f2637c8 Compare July 24, 2022 10:55
@rib
Copy link
Contributor Author

rib commented Jul 24, 2022

Okey, the updated PR now:

  • uses CARGO_ENCODED_RUSTFLAGS and I tested that it works if the target directory has spaces
  • reads any pre-set CARGO_ENCODED_RUSTFLAGS value from the environment so that the workaround doesn't discard any user-set flags
  • creates a directory named libgcc-workaround instead of libgcc_workaround
  • has more comments

Ok(val) => val,
Err(std::env::VarError::NotPresent) => "".to_string(),
Err(std::env::VarError::NotUnicode(_)) => {
log::error!("RUSTFLAGS environment variable contains non-unicode characters");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/RUSTFLAGS/CARGO_ENCODED_RUSTFLAGS?

Comment on lines +163 to +165
// Note: there is a tiny chance of a false positive here while the first two
// beta releases for NDK v23 didn't yet include libunwind for all
// architectures.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're copying things from ndk-build anyway, why not use the same r23 beta3 tag: https://github.com/rust-windowing/android-ndk-rs/blob/814be0864bd05f6fff616299ce25c075487fa244/ndk-build/src/cargo.rs#L54

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I considered it but it didn't look like cargo-ndk parsed the build tag in the same way.

Since it doesn't look like you can download the first two betas anymore and also since by their very nature beta releases shouldn't be relied on it seems reasonable in this case to just check the major number.

@MarijnS95
Copy link

er, okey? I mean fwiw I did skim it before I opened this PR and it vaguely looked similar - not sure what the frowny face is about here - I guess I've stepped on a nerve?

The official term is the :confused: emoji, which is how I felt when reading your change.

maybe you could say what's wrong with this?

Looks like you found some yourself, though I wouldn't have bothered for the s/_/- change nor the comments. At the same time you could've used the build tag to distinguish r23 beta2 and beta3 accordingly.


Regardless my point still stands; this crate should use (or merge with) ndk-build instead of reinventing copy-pasting the wheel to fix identical issues up to a year later. But alas, I don't use it (cargo-apk does the same job when executed correctly) so such a change won't come out of my time budget.

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

Successfully merging this pull request may close these issues.

NDK 23 beta: Build fails with unable to find library -lgcc
3 participants