Skip to content

Commit 828f710

Browse files
fix(cli): respect src/bin required-features (fix: #15325) (#15427)
1 parent ed8fd41 commit 828f710

2 files changed

Lines changed: 104 additions & 9 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri-cli": "patch:bug"
3+
---
4+
5+
Prevent binaries gated by disabled Cargo features from being re-added by the `src/bin` scan.

crates/tauri-cli/src/interface/rust.rs

Lines changed: 99 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,24 @@ impl BinarySettings {
690690
pub fn file_name(&self) -> &str {
691691
self.filename.as_ref().unwrap_or(&self.name)
692692
}
693+
694+
fn required_features_enabled(&self, enabled_features: &[String]) -> bool {
695+
match &self.required_features {
696+
Some(req_features) => req_features
697+
.iter()
698+
.all(|feat| enabled_features.contains(feat)),
699+
None => true,
700+
}
701+
}
702+
703+
fn matches_src_bin(&self, name: &str, path: &Path) -> bool {
704+
self.name == name
705+
|| self.file_name() == name
706+
|| self
707+
.path
708+
.as_ref()
709+
.is_some_and(|src_path| path.ends_with(src_path))
710+
}
693711
}
694712

695713
/// The package settings.
@@ -933,6 +951,7 @@ impl AppSettings for RustAppSettings {
933951

934952
fn get_binaries(&self, options: &Options, tauri_dir: &Path) -> crate::Result<Vec<BundleBinary>> {
935953
let mut binaries = Vec::new();
954+
let mut disabled_bins = Vec::new();
936955

937956
if let Some(bins) = &self.cargo_settings.bin {
938957
let default_run = self
@@ -941,14 +960,9 @@ impl AppSettings for RustAppSettings {
941960
.clone()
942961
.unwrap_or_default();
943962
for bin in bins {
944-
if let Some(req_features) = &bin.required_features {
945-
// Check if all required features are enabled.
946-
if !req_features
947-
.iter()
948-
.all(|feat| options.features.contains(feat))
949-
{
950-
continue;
951-
}
963+
if !bin.required_features_enabled(&options.features) {
964+
disabled_bins.push(bin);
965+
continue;
952966
}
953967
let file_name = bin.file_name();
954968
let is_main = file_name == self.cargo_package_settings.name || file_name == default_run;
@@ -996,7 +1010,10 @@ impl AppSettings for RustAppSettings {
9961010
let bin_exists = binaries
9971011
.iter()
9981012
.any(|bin| bin.name() == name || path.ends_with(bin.src_path().unwrap_or(&"".to_string())));
999-
if !bin_exists {
1013+
let bin_disabled = disabled_bins
1014+
.iter()
1015+
.any(|bin| bin.matches_src_bin(&name, &path));
1016+
if !bin_exists && !bin_disabled {
10001017
binaries.push(BundleBinary::new(name, false))
10011018
}
10021019
}
@@ -1730,6 +1747,44 @@ mod pkgconfig_utils {
17301747
#[cfg(test)]
17311748
mod tests {
17321749
use super::*;
1750+
use std::fs;
1751+
1752+
fn app_settings_with_manifest(cargo_toml: &str) -> (tempfile::TempDir, RustAppSettings) {
1753+
let temp_dir = tempfile::tempdir().unwrap();
1754+
let tauri_dir = temp_dir.path().to_path_buf();
1755+
fs::create_dir_all(tauri_dir.join("src/bin")).unwrap();
1756+
fs::write(tauri_dir.join("Cargo.toml"), cargo_toml).unwrap();
1757+
fs::write(tauri_dir.join("src/main.rs"), "").unwrap();
1758+
fs::write(tauri_dir.join("src/bin/generate-bindings.rs"), "").unwrap();
1759+
1760+
let cargo_settings = CargoSettings::load(&tauri_dir).unwrap();
1761+
let cargo_package_settings = cargo_settings.package.clone().unwrap();
1762+
let package_settings = PackageSettings {
1763+
product_name: cargo_package_settings.name.clone(),
1764+
version: "0.1.0".into(),
1765+
description: String::new(),
1766+
homepage: None,
1767+
authors: None,
1768+
default_run: cargo_package_settings.default_run.clone(),
1769+
};
1770+
1771+
let target_triple = "x86_64-unknown-linux-gnu".to_string();
1772+
1773+
(
1774+
temp_dir,
1775+
RustAppSettings {
1776+
manifest: Mutex::new(Manifest::default()),
1777+
cargo_settings,
1778+
cargo_package_settings,
1779+
cargo_ws_package_settings: None,
1780+
package_settings,
1781+
cargo_config: CargoConfig::default(),
1782+
target_triple: target_triple.clone(),
1783+
target_platform: TargetPlatform::from_triple(&target_triple),
1784+
workspace_dir: tauri_dir,
1785+
},
1786+
)
1787+
}
17331788

17341789
#[test]
17351790
fn parse_cargo_option() {
@@ -1750,6 +1805,41 @@ mod tests {
17501805
assert_eq!(get_cargo_option(&args, "--non-existent"), None);
17511806
}
17521807

1808+
#[test]
1809+
fn get_binaries_ignores_src_bin_with_disabled_required_features() {
1810+
let cargo_toml = r#"
1811+
[package]
1812+
name = "app"
1813+
version = "0.1.0"
1814+
default-run = "app"
1815+
1816+
[[bin]]
1817+
name = "generate-bindings"
1818+
path = "src/bin/generate-bindings.rs"
1819+
required-features = ["bindings"]
1820+
"#;
1821+
1822+
let (temp_dir, app_settings) = app_settings_with_manifest(cargo_toml);
1823+
let tauri_dir = temp_dir.path();
1824+
1825+
let binaries = app_settings
1826+
.get_binaries(&Options::default(), tauri_dir)
1827+
.unwrap();
1828+
assert!(binaries.iter().any(|bin| bin.name() == "app" && bin.main()));
1829+
assert!(!binaries.iter().any(|bin| bin.name() == "generate-bindings"));
1830+
1831+
let binaries = app_settings
1832+
.get_binaries(
1833+
&Options {
1834+
features: vec!["bindings".into()],
1835+
..Default::default()
1836+
},
1837+
tauri_dir,
1838+
)
1839+
.unwrap();
1840+
assert!(binaries.iter().any(|bin| bin.name() == "generate-bindings"));
1841+
}
1842+
17531843
#[test]
17541844
fn parse_profile_from_opts() {
17551845
let options = Options {

0 commit comments

Comments
 (0)