Skip to content

Commit bd2052f

Browse files
committed
apk: Include recursive libraries via gradle as well
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.
1 parent f58cf19 commit bd2052f

File tree

4 files changed

+127
-129
lines changed

4 files changed

+127
-129
lines changed

apk/src/lib.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,10 @@ impl Apk {
9999
}
100100

101101
pub fn add_lib(&mut self, target: Target, path: &Path) -> Result<()> {
102-
let name = path
103-
.file_name()
104-
.context("invalid path")?
105-
.to_str()
106-
.context("invalid path")?;
102+
let name = path.file_name().context("invalid path")?;
107103
self.zip.add_file(
108104
path,
109-
&Path::new("lib").join(target.android_abi()).join(name),
105+
&Path::new("lib").join(target.as_str()).join(name),
110106
ZipFileOptions::Compressed,
111107
)
112108
}

apk/src/utils.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub enum Target {
1111

1212
impl Target {
1313
/// Identifier used in the NDK to refer to the ABI
14-
pub fn android_abi(self) -> &'static str {
14+
pub fn as_str(self) -> &'static str {
1515
match self {
1616
Self::Arm64V8a => "arm64-v8a",
1717
Self::ArmV7a => "armeabi-v7a",

xbuild/src/command/build.rs

+116-112
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::cargo::CrateType;
22
use crate::download::DownloadManager;
33
use crate::task::TaskRunner;
44
use crate::{BuildEnv, Format, Opt, Platform};
5-
use anyhow::{Context, Result};
5+
use anyhow::{ensure, Context, Result};
66
use apk::Apk;
77
use appbundle::AppBundle;
88
use appimage::AppImage;
@@ -71,116 +71,97 @@ pub fn build(env: &BuildEnv) -> Result<()> {
7171
}
7272
Platform::Android => {
7373
let out = platform_dir.join(format!("{}.{}", env.name(), env.target().format()));
74-
if env.config().android().gradle {
75-
crate::gradle::build(env, &out)?;
76-
runner.end_verbose_task();
77-
return Ok(());
78-
} else {
79-
let mut apk = Apk::new(
80-
out,
81-
env.config().android().manifest.clone(),
82-
env.target().opt() != Opt::Debug,
83-
)?;
84-
apk.add_res(env.icon(), &env.android_jar())?;
85-
86-
for asset in &env.config().android().assets {
87-
let path = env.cargo().package_root().join(asset.path());
88-
89-
if !asset.optional() || path.exists() {
90-
apk.add_asset(&path, asset.alignment().to_zip_file_options())?
74+
ensure!(has_lib, "Android APKs/AABs require a library");
75+
76+
let mut libraries = vec![];
77+
78+
for target in env.target().compile_targets() {
79+
let arch_dir = platform_dir.join(target.arch().to_string());
80+
let cargo_dir = arch_dir.join("cargo");
81+
let lib = env.cargo_artefact(&cargo_dir, target, CrateType::Cdylib)?;
82+
83+
let ndk = env.android_ndk();
84+
85+
let deps_dir = {
86+
let arch_dir = if target.is_host()? {
87+
cargo_dir.to_path_buf()
88+
} else {
89+
cargo_dir.join(target.rust_triple()?)
90+
};
91+
let opt_dir = arch_dir.join(target.opt().to_string());
92+
opt_dir.join("deps")
93+
};
94+
95+
let mut search_paths = env
96+
.cargo()
97+
.lib_search_paths(&cargo_dir, target)
98+
.with_context(|| {
99+
format!(
100+
"Finding libraries in `{}` for {:?}",
101+
cargo_dir.display(),
102+
target
103+
)
104+
})?;
105+
search_paths.push(deps_dir);
106+
let search_paths = search_paths.iter().map(AsRef::as_ref).collect::<Vec<_>>();
107+
108+
let ndk_sysroot_libs = ndk.join("usr/lib").join(target.ndk_triple());
109+
let provided_libs_paths = [
110+
ndk_sysroot_libs.as_path(),
111+
&*ndk_sysroot_libs.join(
112+
// Use libraries (symbols) from the lowest NDK that is supported by the application,
113+
// to prevent inadvertently making newer APIs available:
114+
// https://developer.android.com/ndk/guides/sdk-versions
115+
env.config()
116+
.android()
117+
.manifest
118+
.sdk
119+
.min_sdk_version
120+
.unwrap()
121+
.to_string(),
122+
),
123+
];
124+
125+
let mut explicit_libs = vec![lib];
126+
127+
// Collect the libraries the user wants to include
128+
for runtime_lib_path in env.config().runtime_libs(env.target().platform()) {
129+
let abi_dir = env
130+
.cargo()
131+
.package_root()
132+
.join(runtime_lib_path)
133+
.join(target.android_abi().as_str());
134+
let entries = std::fs::read_dir(abi_dir)?;
135+
for entry in entries {
136+
let entry = entry?;
137+
let path = entry.path();
138+
if !path.is_dir() && path.extension() == Some(OsStr::new("so")) {
139+
explicit_libs.push(path);
140+
}
91141
}
92142
}
93143

94-
if has_lib {
95-
for target in env.target().compile_targets() {
96-
let arch_dir = platform_dir.join(target.arch().to_string());
97-
let cargo_dir = arch_dir.join("cargo");
98-
let lib = env.cargo_artefact(&cargo_dir, target, CrateType::Cdylib)?;
99-
100-
let ndk = env.android_ndk();
101-
102-
let deps_dir = {
103-
let arch_dir = if target.is_host()? {
104-
cargo_dir.to_path_buf()
105-
} else {
106-
cargo_dir.join(target.rust_triple()?)
107-
};
108-
let opt_dir = arch_dir.join(target.opt().to_string());
109-
opt_dir.join("deps")
110-
};
111-
112-
let mut search_paths = env
113-
.cargo()
114-
.lib_search_paths(&cargo_dir, target)
115-
.with_context(|| {
116-
format!(
117-
"Finding libraries in `{}` for {:?}",
118-
cargo_dir.display(),
119-
target
120-
)
121-
})?;
122-
search_paths.push(deps_dir);
123-
let search_paths =
124-
search_paths.iter().map(AsRef::as_ref).collect::<Vec<_>>();
125-
126-
let ndk_sysroot_libs = ndk.join("usr/lib").join(target.ndk_triple());
127-
let provided_libs_paths = [
128-
ndk_sysroot_libs.as_path(),
129-
&*ndk_sysroot_libs.join(
130-
// Use libraries (symbols) from the lowest NDK that is supported by the application,
131-
// to prevent inadvertently making newer APIs available:
132-
// https://developer.android.com/ndk/guides/sdk-versions
133-
env.config()
134-
.android()
135-
.manifest
136-
.sdk
137-
.min_sdk_version
138-
.unwrap()
139-
.to_string(),
140-
),
141-
];
142-
143-
let mut explicit_libs = vec![lib];
144-
145-
// Collect the libraries the user wants to include
146-
for runtime_lib_path in env.config().runtime_libs(env.target().platform()) {
147-
let abi_dir = env
148-
.cargo()
149-
.package_root()
150-
.join(runtime_lib_path)
151-
.join(target.android_abi().android_abi());
152-
let entries = std::fs::read_dir(abi_dir)?;
153-
for entry in entries {
154-
let entry = entry?;
155-
let path = entry.path();
156-
if !path.is_dir() && path.extension() == Some(OsStr::new("so")) {
157-
explicit_libs.push(path);
158-
}
159-
}
160-
}
144+
// Collect the names of libraries provided by the user, and assume these
145+
// are available for other dependencies to link to, too.
146+
let mut included_libs = explicit_libs
147+
.iter()
148+
.map(|p| p.file_name().unwrap().to_owned())
149+
.collect::<HashSet<_>>();
161150

162-
// Collect the names of libraries provided by the user, and assume these
163-
// are available for other dependencies to link to, too.
164-
let mut included_libs = explicit_libs
165-
.iter()
166-
.map(|p| p.file_name().unwrap().to_owned())
167-
.collect::<HashSet<_>>();
168-
169-
// Collect the names of all libraries that are available on Android
170-
for provided_libs_path in provided_libs_paths {
171-
included_libs
172-
.extend(xcommon::llvm::find_libs_in_dir(provided_libs_path)?);
173-
}
151+
// Collect the names of all libraries that are available on Android
152+
for provided_libs_path in provided_libs_paths {
153+
included_libs.extend(xcommon::llvm::find_libs_in_dir(provided_libs_path)?);
154+
}
174155

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

178-
let mut needs_cpp_shared = false;
159+
let mut needs_cpp_shared = false;
179160

180-
for lib in explicit_libs {
181-
apk.add_lib(target.android_abi(), &lib)?;
161+
for lib in explicit_libs {
162+
libraries.push((target.android_abi(), lib.clone()));
182163

183-
let (extra_libs, cpp_shared) = xcommon::llvm::list_needed_libs_recursively(
164+
let (extra_libs, cpp_shared) = xcommon::llvm::list_needed_libs_recursively(
184165
&lib,
185166
&search_paths,
186167
&included_libs,
@@ -193,18 +174,41 @@ pub fn build(env: &BuildEnv) -> Result<()> {
193174
search_paths
194175
)
195176
})?;
196-
needs_cpp_shared |= cpp_shared;
197-
for lib in &extra_libs {
198-
apk.add_lib(target.android_abi(), lib)?;
199-
}
200-
}
201-
if needs_cpp_shared {
202-
let cpp_shared = ndk_sysroot_libs.join("libc++_shared.so");
203-
apk.add_lib(target.android_abi(), &cpp_shared)?;
204-
}
177+
needs_cpp_shared |= cpp_shared;
178+
for lib in extra_libs {
179+
libraries.push((target.android_abi(), lib));
180+
}
181+
}
182+
if needs_cpp_shared {
183+
let cpp_shared = ndk_sysroot_libs.join("libc++_shared.so");
184+
libraries.push((target.android_abi(), cpp_shared));
185+
}
186+
}
187+
188+
if env.config().android().gradle {
189+
crate::gradle::build(env, libraries, &out)?;
190+
runner.end_verbose_task();
191+
return Ok(());
192+
} else {
193+
let mut apk = Apk::new(
194+
out,
195+
env.config().android().manifest.clone(),
196+
env.target().opt() != Opt::Debug,
197+
)?;
198+
apk.add_res(env.icon(), &env.android_jar())?;
199+
200+
for asset in &env.config().android().assets {
201+
let path = env.cargo().package_root().join(asset.path());
202+
203+
if !asset.optional() || path.exists() {
204+
apk.add_asset(&path, asset.alignment().to_zip_file_options())?
205205
}
206206
}
207207

208+
for (target, lib) in libraries {
209+
apk.add_lib(target, &lib)?;
210+
}
211+
208212
apk.finish(env.target().signer().cloned())?;
209213
}
210214
}

xbuild/src/gradle/mod.rs

+8-10
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use crate::cargo::CrateType;
21
use crate::{task, BuildEnv, Format, Opt};
3-
use anyhow::Result;
4-
use std::path::Path;
2+
use anyhow::{Context, Result};
3+
use apk::Target;
4+
use std::path::{Path, PathBuf};
55
use std::process::Command;
66

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

36-
pub fn build(env: &BuildEnv, out: &Path) -> Result<()> {
36+
pub fn build(env: &BuildEnv, libraries: Vec<(Target, PathBuf)>, out: &Path) -> Result<()> {
3737
let platform_dir = env.platform_dir();
3838
let gradle = platform_dir.join("gradle");
3939
let app = gradle.join("app");
@@ -146,13 +146,11 @@ pub fn build(env: &BuildEnv, out: &Path) -> Result<()> {
146146
}
147147
}
148148

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

158156
let opt = env.target().opt();

0 commit comments

Comments
 (0)