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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
59 changes: 59 additions & 0 deletions src/cargo.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use std::io::{Write, Result};
use std::path::{Path, PathBuf};
use std::process::Command;

use cargo_metadata::Version;
use cargo_metadata::camino::Utf8PathBuf;

#[cfg(target_os = "macos")]
const ARCH: &str = "darwin-x86_64";
Expand Down Expand Up @@ -75,8 +77,19 @@ fn cargo_env_target_cfg(triple: &str, key: &str) -> String {
format!("CARGO_TARGET_{}_{}", &triple.replace("-", "_"), key).to_uppercase()
}

fn create_libgcc_linker_script_workaround(target_dir: &Utf8PathBuf) -> Result<Utf8PathBuf> {
let libgcc_workaround_dir = target_dir.join("cargo-ndk").join("libgcc-workaround");
std::fs::create_dir_all(&libgcc_workaround_dir)?;
let libgcc_workaround_file = libgcc_workaround_dir.join("libgcc.a");
let mut file = std::fs::File::create(libgcc_workaround_file)?;
file.write_all(b"INPUT(-lunwind)")?;

Ok(libgcc_workaround_dir)
}

pub(crate) fn run(
dir: &Path,
target_dir: &Utf8PathBuf,
ndk_home: &Path,
version: Version,
triple: &str,
Expand Down Expand Up @@ -123,6 +136,16 @@ pub(crate) fn run(
);
log::debug!("Args: {:?}", &cargo_args);

// Read initial RUSTFLAGS
let mut rustflags = match std::env::var("CARGO_ENCODED_RUSTFLAGS") {
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?

std::process::exit(1);
}
};

let mut cargo_cmd = Command::new(cargo_bin);
cargo_cmd
.current_dir(dir)
Expand All @@ -133,6 +156,42 @@ pub(crate) fn run(
.env(cargo_env_target_cfg(triple, "linker"), &target_linker)
.args(cargo_args);

// NDK releases >= 23 beta3 no longer include libgcc which rust's pre-built
// standard libraries depend on. As a workaround for newer NDKs we redirect
// libgcc to libunwind.
//
// 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.
Comment on lines +163 to +165

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.

//
// Note: even though rust-lang merged a fix to support linking the standard
// libraries against newer NDKs they still (up to 1.62.0 at time of writing)
// choose to build binaries (distributed by rustup) against an older NDK
// release (presumably aiming for broader compatibility) which means that
// even the latest versions still require this workaround.
//
// Ref: https://github.com/rust-lang/rust/pull/85806
if version.major >= 23 {
match create_libgcc_linker_script_workaround(target_dir) {
Ok(libdir) => {
// Note that we don't use `cargo rustc` to pass custom library search paths to
// rustc and instead use `CARGO_ENCODED_RUSTFLAGS` because it affects the building
// of all transitive cdylibs (which all need this workaround).
if !rustflags.is_empty() { // Avoid creating an empty '' rustc argument
rustflags.push_str("\x1f");
}
rustflags.push_str("-L\x1f");
rustflags.push_str(libdir.as_str());
cargo_cmd.env("CARGO_ENCODED_RUSTFLAGS", rustflags);
}
Err(e) => {
log::error!("Failed to create libgcc.a linker script workaround");
log::error!("{}", e);
std::process::exit(1);
}
}
}

let extra_include = format!("{}/usr/include/{}", &target_sysroot.display(), triple);
if bindgen {
let bindgen_args = format!(
Expand Down
1 change: 1 addition & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ pub(crate) fn run(args: Vec<String>) {

let status = crate::cargo::run(
&working_dir,
&metadata.target_directory,
&ndk_home,
ndk_version.clone(),
triple,
Expand Down