Skip to content

Commit 5662af2

Browse files
authored
apk: Include recursive libraries via gradle as well (#140)
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 f25a8bb commit 5662af2

File tree

4 files changed

+132
-134
lines changed

4 files changed

+132
-134
lines changed

apk/src/lib.rs

Lines changed: 2 additions & 6 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 121 additions & 117 deletions
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,121 +71,102 @@ 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).with_context(|| {
135+
format!(
136+
"Runtime libraries for current ABI not found at `{}`",
137+
abi_dir.display()
138+
)
139+
})?;
140+
for entry in entries {
141+
let entry = entry?;
142+
let path = entry.path();
143+
if !path.is_dir() && path.extension() == Some(OsStr::new("so")) {
144+
explicit_libs.push(path);
145+
}
91146
}
92147
}
93148

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).with_context(|| {
153-
format!(
154-
"Runtime libraries for current ABI not found at `{}`",
155-
abi_dir.display()
156-
)
157-
})?;
158-
for entry in entries {
159-
let entry = entry?;
160-
let path = entry.path();
161-
if !path.is_dir() && path.extension() == Some(OsStr::new("so")) {
162-
explicit_libs.push(path);
163-
}
164-
}
165-
}
149+
// Collect the names of libraries provided by the user, and assume these
150+
// are available for other dependencies to link to, too.
151+
let mut included_libs = explicit_libs
152+
.iter()
153+
.map(|p| p.file_name().unwrap().to_owned())
154+
.collect::<HashSet<_>>();
166155

167-
// Collect the names of libraries provided by the user, and assume these
168-
// are available for other dependencies to link to, too.
169-
let mut included_libs = explicit_libs
170-
.iter()
171-
.map(|p| p.file_name().unwrap().to_owned())
172-
.collect::<HashSet<_>>();
173-
174-
// Collect the names of all libraries that are available on Android
175-
for provided_libs_path in provided_libs_paths {
176-
included_libs
177-
.extend(xcommon::llvm::find_libs_in_dir(provided_libs_path)?);
178-
}
156+
// Collect the names of all libraries that are available on Android
157+
for provided_libs_path in provided_libs_paths {
158+
included_libs.extend(xcommon::llvm::find_libs_in_dir(provided_libs_path)?);
159+
}
179160

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

183-
let mut needs_cpp_shared = false;
164+
let mut needs_cpp_shared = false;
184165

185-
for lib in explicit_libs {
186-
apk.add_lib(target.android_abi(), &lib)?;
166+
for lib in explicit_libs {
167+
libraries.push((target.android_abi(), lib.clone()));
187168

188-
let (extra_libs, cpp_shared) = xcommon::llvm::list_needed_libs_recursively(
169+
let (extra_libs, cpp_shared) = xcommon::llvm::list_needed_libs_recursively(
189170
&lib,
190171
&search_paths,
191172
&included_libs,
@@ -198,18 +179,41 @@ pub fn build(env: &BuildEnv) -> Result<()> {
198179
search_paths
199180
)
200181
})?;
201-
needs_cpp_shared |= cpp_shared;
202-
for lib in &extra_libs {
203-
apk.add_lib(target.android_abi(), lib)?;
204-
}
205-
}
206-
if needs_cpp_shared {
207-
let cpp_shared = ndk_sysroot_libs.join("libc++_shared.so");
208-
apk.add_lib(target.android_abi(), &cpp_shared)?;
209-
}
182+
needs_cpp_shared |= cpp_shared;
183+
for lib in extra_libs {
184+
libraries.push((target.android_abi(), lib));
185+
}
186+
}
187+
if needs_cpp_shared {
188+
let cpp_shared = ndk_sysroot_libs.join("libc++_shared.so");
189+
libraries.push((target.android_abi(), cpp_shared));
190+
}
191+
}
192+
193+
if env.config().android().gradle {
194+
crate::gradle::build(env, libraries, &out)?;
195+
runner.end_verbose_task();
196+
return Ok(());
197+
} else {
198+
let mut apk = Apk::new(
199+
out,
200+
env.config().android().manifest.clone(),
201+
env.target().opt() != Opt::Debug,
202+
)?;
203+
apk.add_res(env.icon(), &env.android_jar())?;
204+
205+
for asset in &env.config().android().assets {
206+
let path = env.cargo().package_root().join(asset.path());
207+
208+
if !asset.optional() || path.exists() {
209+
apk.add_asset(&path, asset.alignment().to_zip_file_options())?
210210
}
211211
}
212212

213+
for (target, lib) in libraries {
214+
apk.add_lib(target, &lib)?;
215+
}
216+
213217
apk.finish(env.target().signer().cloned())?;
214218
}
215219
}

xbuild/src/gradle/mod.rs

Lines changed: 8 additions & 10 deletions
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)