Skip to content

Commit

Permalink
cargo-apk: Work around missing libgcc on NDK r23 with linker script
Browse files Browse the repository at this point in the history
Rust still searches for libgcc even though [85806] replaces internal use
with libunwind, especially now that the Android NDK (since r23-beta3)
doesn't ship with any of gcc anymore.  The apparent solution is to build
your application with nightly and compile std locally (`-Zbuild-std`),
but that is not desired for the majority of users.  [7339] suggests to
provide a local `libgcc.a` as linker script, which simply redirects
linking to `libunwind` instead - and that has proven to work fine so
far.

Intead of shipping this file with the crate or writing it to an existing
link-search directory on the system, we write it to a new directory that
can be easily passed or removed to `rustc`, say in the event that a user
switches to an older NDK and builds without cleaning.  For this we need
to switch from `cargo build` to `cargo rustc`, but the existing
arguments and desired workflow remain identical.

[85806]: rust-lang/rust#85806
[7339]: termux/termux-packages#7339 (comment)
  • Loading branch information
MarijnS95 committed Nov 12, 2021
1 parent e8765fe commit 61795db
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 5 deletions.
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,13 @@ Branch | Version | Status | Working
r18 | 18.1.5063045 | _Deprecated_ | :x:
r19 | 19.2.5345600 | _Deprecated_ | :heavy_check_mark:
r20 | 20.1.5948944 | _Deprecated_ | :heavy_check_mark:
r21 | 21.4.7075529 | LTS | :heavy_check_mark:
r22 | 22.1.7171670 | Rolling Release | :heavy_check_mark:
r23 beta 1/2 | | Beta | :heavy_check_mark:
r23 beta 3 and beyond | | Beta | :x: Breaking on [#149](https://github.com/rust-windowing/android-ndk-rs/issues/149) :x:
r21 | 21.4.7075529 | _Deprecated_ | :heavy_check_mark:
r22 | 22.1.7171670 | _Deprecated_ | :heavy_check_mark:
r23 | beta 1/2 | _Deprecated_ | :heavy_check_mark:
r23 | 23.0.7272597-beta3 | _Deprecated_ | :heavy_check_mark: Workaround in [#189](https://github.com/rust-windowing/android-ndk-rs/pull/189)
r23 | 23.1.7779620 | LTS | :heavy_check_mark: Workaround in [#189](https://github.com/rust-windowing/android-ndk-rs/pull/189)
r24 | 24.0.7856742-beta1 | Rolling Release | :heavy_check_mark: Workaround in [#189](https://github.com/rust-windowing/android-ndk-rs/pull/189)


## Hello world

Expand Down
2 changes: 2 additions & 0 deletions cargo-apk/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Unreleased

- Fixed the library name in case of multiple build artifacts in the Android manifest.
- Work around missing `libgcc` on NDK r23 beta 3 and above, by providing linker script that "redirects" to `libunwind`.
See https://github.com/rust-windowing/android-ndk-rs/issues/149 and https://github.com/rust-lang/rust/pull/85806 for more details.

# 0.8.1 (2021-08-06)

Expand Down
23 changes: 22 additions & 1 deletion cargo-apk/src/apk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,32 @@ impl<'a> ApkBuilder<'a> {
let target_sdk_version = config.manifest.sdk.target_sdk_version.unwrap();

let mut cargo = cargo_ndk(&config.ndk, *target, target_sdk_version)?;
cargo.arg("build");
cargo.arg("rustc");
if self.cmd.target().is_none() {
cargo.arg("--target").arg(triple);
}
cargo.args(self.cmd.args());

// 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 self.ndk.build_tag() > 7272597 {
if !self.cmd.args().contains(&"--".to_owned()) {
cargo.arg("--");
}
let cargo_apk_link_dir = self
.cmd
.target_dir()
.join("cargo-apk-temp-extra-link-libraries");
std::fs::create_dir_all(&cargo_apk_link_dir)?;
std::fs::write(cargo_apk_link_dir.join("libgcc.a"), "INPUT(-lunwind)")
.expect("Failed to write");
cargo.arg("-L").arg(cargo_apk_link_dir);
}

if !cargo.status()?.success() {
return Err(NdkError::CmdFailed(cargo).into());
}
Expand Down
2 changes: 2 additions & 0 deletions ndk-build/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Unreleased

- Provide NDK `build_tag` version from `source.properties` in the NDK root.

# 0.4.2 (2021-08-06)

- Pass UNIX path separators to `aapt` on non-UNIX systems, ensuring the resulting separator is compatible with the target device instead of the host platform.
Expand Down
31 changes: 31 additions & 0 deletions ndk-build/src/ndk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub struct Ndk {
sdk_path: PathBuf,
ndk_path: PathBuf,
build_tools_version: String,
build_tag: u32,
platforms: Vec<u32>,
}

Expand Down Expand Up @@ -54,6 +55,31 @@ impl Ndk {
.max()
.ok_or(NdkError::BuildToolsNotFound)?;

let build_tag = std::fs::read_to_string(ndk_path.join("source.properties"))
.expect("Failed to read source.properties");

let build_tag = build_tag
.split('\n')
.find_map(|line| {
let (key, value) = line
.split_once('=')
.expect("Failed to parse `key = value` from source.properties");
if key.trim() == "Pkg.Revision" {
// AOSP writes a constantly-incrementing build version to the patch field.
// This number is incrementing across NDK releases.
let mut parts = value.trim().split('.');
let _major = parts.next().unwrap();
let _minor = parts.next().unwrap();
let patch = parts.next().unwrap();
// Can have an optional `XXX-beta1`
let patch = patch.split_once('-').map_or(patch, |(patch, _beta)| patch);
Some(patch.parse().expect("Failed to parse patch field"))
} else {
None
}
})
.expect("No `Pkg.Revision` in source.properties");

let ndk_platforms = std::fs::read_to_string(ndk_path.join("build/core/platforms.mk"))?;
let ndk_platforms = ndk_platforms
.split('\n')
Expand Down Expand Up @@ -88,6 +114,7 @@ impl Ndk {
sdk_path,
ndk_path,
build_tools_version,
build_tag,
platforms,
})
}
Expand All @@ -104,6 +131,10 @@ impl Ndk {
&self.build_tools_version
}

pub fn build_tag(&self) -> u32 {
self.build_tag
}

pub fn platforms(&self) -> &[u32] {
&self.platforms
}
Expand Down

0 comments on commit 61795db

Please sign in to comment.