Skip to content

Commit

Permalink
apk: Include recursive libraries via gradle as well
Browse files Browse the repository at this point in the history
The `gradle` build was only including the target library from `cargo`,
but not any (in)direct dependencies like `libc++_shared.so`.

Move the logic where we recursively scan all libraries, and pass
the result to the `gradle` builder in addition to the existing `apk`
builder.
  • Loading branch information
MarijnS95 committed Oct 10, 2023
1 parent f58cf19 commit 2a13bae
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 128 deletions.
8 changes: 2 additions & 6 deletions apk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,10 @@ impl Apk {
}

pub fn add_lib(&mut self, target: Target, path: &Path) -> Result<()> {
let name = path
.file_name()
.context("invalid path")?
.to_str()
.context("invalid path")?;
let name = path.file_name().context("invalid path")?;
self.zip.add_file(
path,
&Path::new("lib").join(target.android_abi()).join(name),
&Path::new("lib").join(target.as_str()).join(name),
ZipFileOptions::Compressed,
)
}
Expand Down
2 changes: 1 addition & 1 deletion apk/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub enum Target {

impl Target {
/// Identifier used in the NDK to refer to the ABI
pub fn android_abi(self) -> &'static str {
pub fn as_str(self) -> &'static str {
match self {
Self::Arm64V8a => "arm64-v8a",
Self::ArmV7a => "armeabi-v7a",
Expand Down
228 changes: 116 additions & 112 deletions xbuild/src/command/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::cargo::CrateType;
use crate::download::DownloadManager;
use crate::task::TaskRunner;
use crate::{BuildEnv, Format, Opt, Platform};
use anyhow::{Context, Result};
use anyhow::{ensure, Context, Result};
use apk::Apk;
use appbundle::AppBundle;
use appimage::AppImage;
Expand Down Expand Up @@ -71,116 +71,97 @@ pub fn build(env: &BuildEnv) -> Result<()> {
}
Platform::Android => {
let out = platform_dir.join(format!("{}.{}", env.name(), env.target().format()));
if env.config().android().gradle {
crate::gradle::build(env, &out)?;
runner.end_verbose_task();
return Ok(());
} else {
let mut apk = Apk::new(
out,
env.config().android().manifest.clone(),
env.target().opt() != Opt::Debug,
)?;
apk.add_res(env.icon(), &env.android_jar())?;

for asset in &env.config().android().assets {
let path = env.cargo().package_root().join(asset.path());

if !asset.optional() || path.exists() {
apk.add_asset(&path, asset.alignment().to_zip_file_options())?
ensure!(has_lib, "Android APKs/AABs require a library");

let mut libraries = vec![];

for target in env.target().compile_targets() {
let arch_dir = platform_dir.join(target.arch().to_string());
let cargo_dir = arch_dir.join("cargo");
let lib = env.cargo_artefact(&cargo_dir, target, CrateType::Cdylib)?;

let ndk = env.android_ndk();

let deps_dir = {
let arch_dir = if target.is_host()? {
cargo_dir.to_path_buf()
} else {
cargo_dir.join(target.rust_triple()?)
};
let opt_dir = arch_dir.join(target.opt().to_string());
opt_dir.join("deps")
};

let mut search_paths = env
.cargo()
.lib_search_paths(&cargo_dir, target)
.with_context(|| {
format!(
"Finding libraries in `{}` for {:?}",
cargo_dir.display(),
target
)
})?;
search_paths.push(deps_dir);
let search_paths = search_paths.iter().map(AsRef::as_ref).collect::<Vec<_>>();

let ndk_sysroot_libs = ndk.join("usr/lib").join(target.ndk_triple());
let provided_libs_paths = [
ndk_sysroot_libs.as_path(),
&*ndk_sysroot_libs.join(
// Use libraries (symbols) from the lowest NDK that is supported by the application,
// to prevent inadvertently making newer APIs available:
// https://developer.android.com/ndk/guides/sdk-versions
env.config()
.android()
.manifest
.sdk
.min_sdk_version
.unwrap()
.to_string(),
),
];

let mut explicit_libs = vec![lib];

// Collect the libraries the user wants to include
for runtime_lib_path in env.config().runtime_libs(env.target().platform()) {
let abi_dir = env
.cargo()
.package_root()
.join(runtime_lib_path)
.join(target.android_abi().as_str());
let entries = std::fs::read_dir(abi_dir)?;
for entry in entries {
let entry = entry?;
let path = entry.path();
if !path.is_dir() && path.extension() == Some(OsStr::new("so")) {
explicit_libs.push(path);
}
}
}

if has_lib {
for target in env.target().compile_targets() {
let arch_dir = platform_dir.join(target.arch().to_string());
let cargo_dir = arch_dir.join("cargo");
let lib = env.cargo_artefact(&cargo_dir, target, CrateType::Cdylib)?;

let ndk = env.android_ndk();

let deps_dir = {
let arch_dir = if target.is_host()? {
cargo_dir.to_path_buf()
} else {
cargo_dir.join(target.rust_triple()?)
};
let opt_dir = arch_dir.join(target.opt().to_string());
opt_dir.join("deps")
};

let mut search_paths = env
.cargo()
.lib_search_paths(&cargo_dir, target)
.with_context(|| {
format!(
"Finding libraries in `{}` for {:?}",
cargo_dir.display(),
target
)
})?;
search_paths.push(deps_dir);
let search_paths =
search_paths.iter().map(AsRef::as_ref).collect::<Vec<_>>();

let ndk_sysroot_libs = ndk.join("usr/lib").join(target.ndk_triple());
let provided_libs_paths = [
ndk_sysroot_libs.as_path(),
&*ndk_sysroot_libs.join(
// Use libraries (symbols) from the lowest NDK that is supported by the application,
// to prevent inadvertently making newer APIs available:
// https://developer.android.com/ndk/guides/sdk-versions
env.config()
.android()
.manifest
.sdk
.min_sdk_version
.unwrap()
.to_string(),
),
];

let mut explicit_libs = vec![lib];

// Collect the libraries the user wants to include
for runtime_lib_path in env.config().runtime_libs(env.target().platform()) {
let abi_dir = env
.cargo()
.package_root()
.join(runtime_lib_path)
.join(target.android_abi().android_abi());
let entries = std::fs::read_dir(abi_dir)?;
for entry in entries {
let entry = entry?;
let path = entry.path();
if !path.is_dir() && path.extension() == Some(OsStr::new("so")) {
explicit_libs.push(path);
}
}
}
// Collect the names of libraries provided by the user, and assume these
// are available for other dependencies to link to, too.
let mut included_libs = explicit_libs
.iter()
.map(|p| p.file_name().unwrap().to_owned())
.collect::<HashSet<_>>();

// Collect the names of libraries provided by the user, and assume these
// are available for other dependencies to link to, too.
let mut included_libs = explicit_libs
.iter()
.map(|p| p.file_name().unwrap().to_owned())
.collect::<HashSet<_>>();

// Collect the names of all libraries that are available on Android
for provided_libs_path in provided_libs_paths {
included_libs
.extend(xcommon::llvm::find_libs_in_dir(provided_libs_path)?);
}
// Collect the names of all libraries that are available on Android
for provided_libs_path in provided_libs_paths {
included_libs.extend(xcommon::llvm::find_libs_in_dir(provided_libs_path)?);
}

// libc++_shared is bundled with the NDK but not available on-device
included_libs.remove(OsStr::new("libc++_shared.so"));
// libc++_shared is bundled with the NDK but not available on-device
included_libs.remove(OsStr::new("libc++_shared.so"));

let mut needs_cpp_shared = false;
let mut needs_cpp_shared = false;

for lib in explicit_libs {
apk.add_lib(target.android_abi(), &lib)?;
for lib in explicit_libs {
libraries.push((target.android_abi(), lib.clone()));

let (extra_libs, cpp_shared) = xcommon::llvm::list_needed_libs_recursively(
let (extra_libs, cpp_shared) = xcommon::llvm::list_needed_libs_recursively(
&lib,
&search_paths,
&included_libs,
Expand All @@ -193,18 +174,41 @@ pub fn build(env: &BuildEnv) -> Result<()> {
search_paths
)
})?;
needs_cpp_shared |= cpp_shared;
for lib in &extra_libs {
apk.add_lib(target.android_abi(), lib)?;
}
}
if needs_cpp_shared {
let cpp_shared = ndk_sysroot_libs.join("libc++_shared.so");
apk.add_lib(target.android_abi(), &cpp_shared)?;
}
needs_cpp_shared |= cpp_shared;
for lib in extra_libs {
libraries.push((target.android_abi(), lib));
}
}
if needs_cpp_shared {
let cpp_shared = ndk_sysroot_libs.join("libc++_shared.so");
libraries.push((target.android_abi(), cpp_shared));
}
}

if env.config().android().gradle {
crate::gradle::build(env, libraries, &out)?;
runner.end_verbose_task();
return Ok(());
} else {
let mut apk = Apk::new(
out,
env.config().android().manifest.clone(),
env.target().opt() != Opt::Debug,
)?;
apk.add_res(env.icon(), &env.android_jar())?;

for asset in &env.config().android().assets {
let path = env.cargo().package_root().join(asset.path());

if !asset.optional() || path.exists() {
apk.add_asset(&path, asset.alignment().to_zip_file_options())?
}
}

for (target, lib) in libraries {
apk.add_lib(target, &lib)?;
}

apk.finish(env.target().signer().cloned())?;
}
}
Expand Down
17 changes: 8 additions & 9 deletions xbuild/src/gradle/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::cargo::CrateType;

Check failure on line 1 in xbuild/src/gradle/mod.rs

View workflow job for this annotation

GitHub Actions / lint

unused import: `crate::cargo::CrateType`

Check warning on line 1 in xbuild/src/gradle/mod.rs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

unused import: `crate::cargo::CrateType`

Check warning on line 1 in xbuild/src/gradle/mod.rs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

unused import: `crate::cargo::CrateType`

Check warning on line 1 in xbuild/src/gradle/mod.rs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

unused import: `crate::cargo::CrateType`
use crate::{task, BuildEnv, Format, Opt};
use anyhow::Result;
use std::path::Path;
use anyhow::{Context, Result};
use apk::Target;
use std::path::{Path, PathBuf};
use std::process::Command;

static BUILD_GRADLE: &[u8] = include_bytes!("./build.gradle");
Expand Down Expand Up @@ -33,7 +34,7 @@ pub fn prepare(env: &BuildEnv) -> Result<()> {
Ok(())
}

pub fn build(env: &BuildEnv, out: &Path) -> Result<()> {
pub fn build(env: &BuildEnv, libraries: Vec<(Target, PathBuf)>, out: &Path) -> Result<()> {
let platform_dir = env.platform_dir();
let gradle = platform_dir.join("gradle");
let app = gradle.join("app");
Expand Down Expand Up @@ -146,13 +147,11 @@ pub fn build(env: &BuildEnv, out: &Path) -> Result<()> {
}
}

for target in env.target().compile_targets() {
let arch_dir = platform_dir.join(target.arch().to_string());
let lib = env.cargo_artefact(&arch_dir.join("cargo"), target, CrateType::Cdylib)?;
let lib_name = lib.file_name().unwrap();
let lib_dir = jnilibs.join(target.android_abi().android_abi());
for (target, lib) in libraries {
let name = lib.file_name().context("invalid path")?;
let lib_dir = jnilibs.join(target.as_str());
std::fs::create_dir_all(&lib_dir)?;
std::fs::copy(&lib, lib_dir.join(lib_name))?;
std::fs::copy(&lib, lib_dir.join(name))?;
}

let opt = env.target().opt();
Expand Down

0 comments on commit 2a13bae

Please sign in to comment.