Skip to content

Commit 8e1e153

Browse files
authored
feat(cli): check if Rust lib contains required Android and iOS symbols #10094 (#10483)
* feat(cli): check if Rust lib contains required Android symbols #10094 * check for ios aswell
1 parent ca68689 commit 8e1e153

File tree

9 files changed

+88
-13
lines changed

9 files changed

+88
-13
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"tauri-cli": patch:enhance
3+
"@tauri-apps/cli": patch:enhance
4+
---
5+
6+
Check if the Rust library contains the symbols required at runtime for Android and iOS apps.

core/tauri-macros/src/mobile.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ pub fn entry_point(_attributes: TokenStream, item: TokenStream) -> TokenStream {
7676
stop_unwind(#function_name);
7777
}
7878

79+
// be careful when renaming this, the `start_app` symbol is checked by the CLI
7980
#[cfg(not(target_os = "android"))]
8081
#[no_mangle]
8182
#[inline(never)]

core/tauri/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ macro_rules! android_binding {
147147
::tauri::tao
148148
);
149149

150+
// be careful when renaming this, the `Java_app_tauri_plugin_PluginManager_handlePluginResponse` symbol is checked by the CLI
150151
::tauri::tao::platform::android::prelude::android_fn!(
151152
app_tauri,
152153
plugin,

tooling/cli/Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tooling/cli/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ oxc_ast = "0.16"
9999
magic_string = "0.3"
100100
phf = { version = "0.11", features = ["macros"] }
101101
walkdir = "2"
102+
elf = "0.7"
102103

103104
[target."cfg(windows)".dependencies.windows-sys]
104105
version = "0.52"

tooling/cli/src/migrate/migrations/v1/frontend.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ pub fn migrate(app_dir: &Path, tauri_dir: &Path) -> Result<()> {
8181
.current_package_version(pkg, app_dir)
8282
.unwrap_or_default()
8383
.unwrap_or_default();
84-
if version.starts_with("1") {
84+
if version.starts_with('1') {
8585
new_npm_packages.push(format!("{pkg}@^{npm_version}"));
8686
}
8787
}

tooling/cli/src/migrate/migrations/v2_rc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ fn migrate_npm_dependencies(app_dir: &Path) -> Result<()> {
7474
.current_package_version(pkg, app_dir)
7575
.unwrap_or_default()
7676
.unwrap_or_default();
77-
if version.starts_with("1") {
77+
if version.starts_with('1') {
7878
install_deps.push(format!("{pkg}@^2.0.0-rc.0"));
7979
}
8080
}

tooling/cli/src/mobile/android/android_studio_script.rs

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,15 @@ use crate::{
1010
};
1111
use clap::{ArgAction, Parser};
1212

13+
use anyhow::Context;
1314
use cargo_mobile2::{
1415
android::{adb, target::Target},
1516
opts::Profile,
1617
target::{call_for_targets_with_fallback, TargetTrait},
1718
};
1819

20+
use std::path::Path;
21+
1922
#[derive(Debug, Parser)]
2023
pub struct Options {
2124
/// Targets to build.
@@ -83,22 +86,61 @@ pub fn command(options: Options) -> Result<()> {
8386
}
8487
}
8588

89+
let mut validated_lib = false;
90+
8691
call_for_targets_with_fallback(
8792
options.targets.unwrap_or_default().iter(),
8893
&detect_target_ok,
8994
&env,
9095
|target: &Target| {
91-
target
92-
.build(
93-
&config,
94-
&metadata,
95-
&env,
96-
cli_options.noise_level,
97-
true,
98-
profile,
99-
)
100-
.map_err(Into::into)
96+
target.build(
97+
&config,
98+
&metadata,
99+
&env,
100+
cli_options.noise_level,
101+
true,
102+
profile,
103+
)?;
104+
105+
if !validated_lib {
106+
validated_lib = true;
107+
108+
let lib_path = config
109+
.app()
110+
.target_dir(target.triple, profile)
111+
.join(config.so_name());
112+
113+
validate_lib(&lib_path)?;
114+
}
115+
116+
Ok(())
101117
},
102118
)
103119
.map_err(|e| anyhow::anyhow!(e.to_string()))?
104120
}
121+
122+
fn validate_lib(path: &Path) -> Result<()> {
123+
let so_bytes = std::fs::read(path)?;
124+
let elf = elf::ElfBytes::<elf::endian::AnyEndian>::minimal_parse(&so_bytes)
125+
.context("failed to parse ELF")?;
126+
let (symbol_table, string_table) = elf
127+
.dynamic_symbol_table()
128+
.context("failed to read dynsym section")?
129+
.context("missing dynsym tables")?;
130+
131+
let mut symbols = Vec::new();
132+
for s in symbol_table.iter() {
133+
if let Ok(symbol) = string_table.get(s.st_name as usize) {
134+
symbols.push(symbol);
135+
}
136+
}
137+
138+
if !symbols.contains(&"Java_app_tauri_plugin_PluginManager_handlePluginResponse") {
139+
anyhow::bail!(
140+
"Library from {} does not include required runtime symbols. This means you are likely missing the tauri::mobile_entry_point macro usage, see the documentation for more information: https://v2.tauri.app/start/migrate/from-tauri-1",
141+
path.display()
142+
);
143+
}
144+
145+
Ok(())
146+
}

tooling/cli/src/mobile/ios/xcode_script.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ use std::{
1616
collections::HashMap,
1717
env::{current_dir, set_current_dir, var_os},
1818
ffi::OsStr,
19-
path::PathBuf,
19+
path::{Path, PathBuf},
20+
process::Command,
2021
};
2122

2223
#[derive(Debug, Parser)]
@@ -211,6 +212,8 @@ pub fn command(options: Options) -> Result<()> {
211212
return Err(anyhow::anyhow!("Library not found at {}. Make sure your Cargo.toml file has a [lib] block with `crate-type = [\"staticlib\", \"cdylib\", \"lib\"]`", lib_path.display()));
212213
}
213214

215+
validate_lib(&lib_path)?;
216+
214217
let project_dir = config.project_dir();
215218
let externals_lib_dir = project_dir.join(format!("Externals/{arch}/{}", profile.as_str()));
216219
std::fs::create_dir_all(&externals_lib_dir)?;
@@ -221,3 +224,17 @@ pub fn command(options: Options) -> Result<()> {
221224
}
222225
Ok(())
223226
}
227+
228+
fn validate_lib(path: &Path) -> Result<()> {
229+
// we ignore `nm` errors
230+
if let Ok(output) = Command::new("nm").arg(path).output() {
231+
let symbols = String::from_utf8_lossy(&output.stdout);
232+
if !symbols.contains("start_app") {
233+
anyhow::bail!(
234+
"Library from {} does not include required runtime symbols. This means you are likely missing the tauri::mobile_entry_point macro usage, see the documentation for more information: https://v2.tauri.app/start/migrate/from-tauri-1",
235+
path.display()
236+
);
237+
}
238+
}
239+
Ok(())
240+
}

0 commit comments

Comments
 (0)