From 4c2dd0ad7090010b9f46f702806b6c87a548e7d6 Mon Sep 17 00:00:00 2001 From: amrbashir Date: Thu, 12 Sep 2024 23:30:30 +0300 Subject: [PATCH] feat: add `mainBinaryName` option --- .changes/main_binary_name.md | 8 +++ .../src/bundle/linux/appimage.rs | 2 +- .../tauri-bundler/src/bundle/linux/debian.rs | 6 +-- .../src/bundle/linux/freedesktop.rs | 8 +-- crates/tauri-bundler/src/bundle/linux/rpm.rs | 4 +- .../src/bundle/linux/templates/appimage | 14 ++--- crates/tauri-bundler/src/bundle/macos/app.rs | 2 +- crates/tauri-bundler/src/bundle/macos/ios.rs | 2 +- crates/tauri-bundler/src/bundle/settings.rs | 53 +++++++------------ .../src/bundle/windows/msi/wix.rs | 23 +++----- .../tauri-bundler/src/bundle/windows/nsis.rs | 16 +----- .../src/bundle/windows/templates/main.wxs | 2 +- crates/tauri-cli/config.schema.json | 7 +++ crates/tauri-cli/src/build.rs | 9 ++-- crates/tauri-cli/src/bundle.rs | 5 +- crates/tauri-cli/src/interface/mod.rs | 10 +++- crates/tauri-cli/src/interface/rust.rs | 47 +++++++--------- .../tauri-cli/src/interface/rust/desktop.rs | 38 ++++++++++--- crates/tauri-cli/src/mobile/android/build.rs | 5 +- crates/tauri-cli/src/mobile/android/dev.rs | 5 +- crates/tauri-cli/src/mobile/ios/build.rs | 3 +- crates/tauri-cli/src/mobile/ios/dev.rs | 3 +- .../tauri-cli/src/mobile/ios/xcode_script.rs | 13 ++--- crates/tauri-cli/src/mobile/mod.rs | 7 ++- .../schemas/config.schema.json | 7 +++ crates/tauri-utils/src/config.rs | 5 ++ crates/tauri-utils/src/platform.rs | 9 ++-- crates/tauri/src/test/mod.rs | 1 + crates/tauri/src/window/mod.rs | 2 +- 29 files changed, 161 insertions(+), 155 deletions(-) create mode 100644 .changes/main_binary_name.md diff --git a/.changes/main_binary_name.md b/.changes/main_binary_name.md new file mode 100644 index 000000000000..6867eda42d42 --- /dev/null +++ b/.changes/main_binary_name.md @@ -0,0 +1,8 @@ +--- +"tauri": "patch:feat" +"tauri-utils": "patch:feat" +"tauri-cli": "patch:feat" +"tauri-bundler": "patch:feat" +--- + +Add `mainBinaryName` config option to set the file name for the main binary. diff --git a/crates/tauri-bundler/src/bundle/linux/appimage.rs b/crates/tauri-bundler/src/bundle/linux/appimage.rs index f4e2881f9ed2..ed8a730edf72 100644 --- a/crates/tauri-bundler/src/bundle/linux/appimage.rs +++ b/crates/tauri-bundler/src/bundle/linux/appimage.rs @@ -56,7 +56,7 @@ pub fn bundle_project(settings: &Settings) -> crate::Result> { // setup data to insert into shell script let mut sh_map = BTreeMap::new(); sh_map.insert("arch", settings.target().split('-').next().unwrap()); - sh_map.insert("crate_name", settings.main_binary_name()); + sh_map.insert("product_name", settings.product_name()); sh_map.insert("appimage_filename", &appimage_filename); let tauri_tools_path = settings diff --git a/crates/tauri-bundler/src/bundle/linux/debian.rs b/crates/tauri-bundler/src/bundle/linux/debian.rs index 4baeba7a8f91..cdb1248d701b 100644 --- a/crates/tauri-bundler/src/bundle/linux/debian.rs +++ b/crates/tauri-bundler/src/bundle/linux/debian.rs @@ -133,8 +133,8 @@ pub fn generate_data( fn generate_changelog_file(settings: &Settings, data_dir: &Path) -> crate::Result<()> { if let Some(changelog_src_path) = &settings.deb().changelog { let mut src_file = File::open(changelog_src_path)?; - let bin_name = settings.main_binary_name(); - let dest_path = data_dir.join(format!("usr/share/doc/{}/changelog.gz", bin_name)); + let product_name = settings.product_name(); + let dest_path = data_dir.join(format!("usr/share/doc/{product_name}/changelog.gz")); let changelog_file = common::create_file(&dest_path)?; let mut gzip_encoder = GzEncoder::new(changelog_file, Compression::new(9)); @@ -306,7 +306,7 @@ fn generate_md5sums(control_dir: &Path, data_dir: &Path) -> crate::Result<()> { /// Copy the bundle's resource files into an appropriate directory under the /// `data_dir`. fn copy_resource_files(settings: &Settings, data_dir: &Path) -> crate::Result<()> { - let resource_dir = data_dir.join("usr/lib").join(settings.main_binary_name()); + let resource_dir = data_dir.join("usr/lib").join(settings.product_name()); settings.copy_resources(&resource_dir) } diff --git a/crates/tauri-bundler/src/bundle/linux/freedesktop.rs b/crates/tauri-bundler/src/bundle/linux/freedesktop.rs index c55967bf654e..5f369a7c2fdf 100644 --- a/crates/tauri-bundler/src/bundle/linux/freedesktop.rs +++ b/crates/tauri-bundler/src/bundle/linux/freedesktop.rs @@ -44,13 +44,14 @@ pub fn list_icon_files( data_dir: &Path, ) -> crate::Result> { let base_dir = data_dir.join("usr/share/icons/hicolor"); + let main_binary_name = settings.main_binary_name()?; let get_dest_path = |width: u32, height: u32, is_high_density: bool| { base_dir.join(format!( "{}x{}{}/apps/{}.png", width, height, if is_high_density { "@2" } else { "" }, - settings.main_binary_name() + main_binary_name )) }; let mut icons = BTreeMap::new(); @@ -97,8 +98,9 @@ pub fn generate_desktop_file( custom_template_path: &Option, data_dir: &Path, ) -> crate::Result<(PathBuf, PathBuf)> { - let bin_name = settings.main_binary_name(); - let desktop_file_name = format!("{bin_name}.desktop"); + let bin_name = settings.main_binary_name()?; + let product_name = settings.product_name(); + let desktop_file_name = format!("{product_name}.desktop"); let path = PathBuf::from("usr/share/applications").join(desktop_file_name); let dest_path = PathBuf::from("/").join(&path); let file_path = data_dir.join(&path); diff --git a/crates/tauri-bundler/src/bundle/linux/rpm.rs b/crates/tauri-bundler/src/bundle/linux/rpm.rs index 901cd64a4223..35d517587a8e 100644 --- a/crates/tauri-bundler/src/bundle/linux/rpm.rs +++ b/crates/tauri-bundler/src/bundle/linux/rpm.rs @@ -141,12 +141,12 @@ pub fn bundle_project(settings: &Settings) -> crate::Result> { // Add resources if settings.resource_files().count() > 0 { - let resource_dir = Path::new("/usr/lib").join(settings.main_binary_name()); + let resource_dir = Path::new("/usr/lib").join(settings.product_name()); // Create an empty file, needed to add a directory to the RPM package // (cf https://github.com/rpm-rs/rpm/issues/177) let empty_file_path = &package_dir.join("empty"); File::create(empty_file_path)?; - // Then add the resource directory `/usr/lib/` to the package. + // Then add the resource directory `/usr/lib/` to the package. builder = builder.with_file( empty_file_path, FileOptions::new(resource_dir.to_string_lossy()).mode(FileMode::Dir { permissions: 0o755 }), diff --git a/crates/tauri-bundler/src/bundle/linux/templates/appimage b/crates/tauri-bundler/src/bundle/linux/templates/appimage index e808755c87b9..8e447a0048b3 100644 --- a/crates/tauri-bundler/src/bundle/linux/templates/appimage +++ b/crates/tauri-bundler/src/bundle/linux/templates/appimage @@ -17,10 +17,10 @@ else linuxdeploy_arch="$ARCH" fi -mkdir -p "{{crate_name}}.AppDir" -cp -r ../appimage_deb/data/usr "{{crate_name}}.AppDir" +mkdir -p "{{product_name}}.AppDir" +cp -r ../appimage_deb/data/usr "{{product_name}}.AppDir" -cd "{{crate_name}}.AppDir" +cd "{{product_name}}.AppDir" mkdir -p "usr/bin" mkdir -p "usr/lib" @@ -56,14 +56,14 @@ find -L /usr/lib* -name libwebkit2gtkinjectedbundle.so -exec mkdir -p "$(dirname ( cd "{{tauri_tools_path}}" && ( wget -q -4 -N https://github.com/AppImage/AppImageKit/releases/download/continuous/AppRun-${ARCH} || wget -q -4 -N https://github.com/AppImage/AppImageKit/releases/download/12/AppRun-${ARCH} ) ) chmod +x "{{tauri_tools_path}}/AppRun-${ARCH}" -# We need AppRun to be installed as {{crate_name}}.AppDir/AppRun. +# We need AppRun to be installed as {{product_name}}.AppDir/AppRun. # Otherwise the linuxdeploy scripts will default to symlinking our main bin instead and will crash on trying to launch. cp "{{tauri_tools_path}}/AppRun-${ARCH}" AppRun cp "{{icon_path}}" .DirIcon -ln -sf "{{icon_path}}" "{{crate_name}}.png" +ln -sf "{{icon_path}}" "{{product_name}}.png" -ln -sf "usr/share/applications/{{crate_name}}.desktop" "{{crate_name}}.desktop" +ln -sf "usr/share/applications/{{product_name}}.desktop" "{{product_name}}.desktop" cd .. @@ -83,4 +83,4 @@ chmod +x "{{tauri_tools_path}}/linuxdeploy-${linuxdeploy_arch}.AppImage" dd if=/dev/zero bs=1 count=3 seek=8 conv=notrunc of="{{tauri_tools_path}}/linuxdeploy-${linuxdeploy_arch}.AppImage" -OUTPUT="{{appimage_filename}}" "{{tauri_tools_path}}/linuxdeploy-${linuxdeploy_arch}.AppImage" --appimage-extract-and-run --appdir "{{crate_name}}.AppDir" --plugin gtk ${gst_plugin} --output appimage +OUTPUT="{{appimage_filename}}" "{{tauri_tools_path}}/linuxdeploy-${linuxdeploy_arch}.AppImage" --appimage-extract-and-run --appdir "{{product_name}}.AppDir" --plugin gtk ${gst_plugin} --output appimage diff --git a/crates/tauri-bundler/src/bundle/macos/app.rs b/crates/tauri-bundler/src/bundle/macos/app.rs index b91e43c5df48..785235126e50 100644 --- a/crates/tauri-bundler/src/bundle/macos/app.rs +++ b/crates/tauri-bundler/src/bundle/macos/app.rs @@ -200,7 +200,7 @@ fn create_info_plist( plist.insert("CFBundleDisplayName".into(), settings.product_name().into()); plist.insert( "CFBundleExecutable".into(), - settings.main_binary_name().into(), + settings.main_binary_name()?.into(), ); if let Some(path) = bundle_icon_file { plist.insert( diff --git a/crates/tauri-bundler/src/bundle/macos/ios.rs b/crates/tauri-bundler/src/bundle/macos/ios.rs index 77e534a734fb..8e0fa77ec1a4 100644 --- a/crates/tauri-bundler/src/bundle/macos/ios.rs +++ b/crates/tauri-bundler/src/bundle/macos/ios.rs @@ -170,7 +170,7 @@ fn generate_info_plist( writeln!( file, " CFBundleExecutable\n {}", - settings.main_binary_name() + settings.main_binary_name()? )?; writeln!( file, diff --git a/crates/tauri-bundler/src/bundle/settings.rs b/crates/tauri-bundler/src/bundle/settings.rs index fcf60980555c..ee010085976c 100644 --- a/crates/tauri-bundler/src/bundle/settings.rs +++ b/crates/tauri-bundler/src/bundle/settings.rs @@ -5,6 +5,7 @@ use super::category::AppCategory; use crate::bundle::{common, platform::target_triple}; +use anyhow::Context; pub use tauri_utils::config::WebviewInstallMode; use tauri_utils::{ config::{BundleType, DeepLinkProtocol, FileAssociation, NSISInstallerMode, NsisCompression}, @@ -617,34 +618,13 @@ pub struct BundleSettings { #[derive(Clone, Debug)] pub struct BundleBinary { name: String, - src_path: Option, main: bool, } impl BundleBinary { /// Creates a new bundle binary. pub fn new(name: String, main: bool) -> Self { - Self { - name, - src_path: None, - main, - } - } - - /// Creates a new bundle binary with path. - pub fn with_path(name: String, main: bool, src_path: Option) -> Self { - Self { - name, - src_path, - main, - } - } - - /// Sets the src path of the binary. - #[must_use] - pub fn set_src_path(mut self, src_path: Option) -> Self { - self.src_path = src_path; - self + Self { name, main } } /// Mark the binary as the main executable. @@ -657,19 +637,14 @@ impl BundleBinary { self.name = name; } - /// Returns the binary name. - pub fn name(&self) -> &str { - &self.name - } - /// Returns the binary `main` flag. pub fn main(&self) -> bool { self.main } - /// Returns the binary source path. - pub fn src_path(&self) -> Option<&String> { - self.src_path.as_ref() + /// Returns the binary name. + pub fn name(&self) -> &str { + &self.name } } @@ -852,14 +827,24 @@ impl Settings { } /// Returns the file name of the binary being bundled. - pub fn main_binary_name(&self) -> &str { + pub fn main_binary(&self) -> crate::Result<&BundleBinary> { + self + .binaries + .iter() + .find(|bin| bin.main) + .context("failed to find main binary") + .map_err(Into::into) + } + + /// Returns the file name of the binary being bundled. + pub fn main_binary_name(&self) -> crate::Result<&str> { self .binaries .iter() .find(|bin| bin.main) - .expect("failed to find main binary") - .name - .as_str() + .context("failed to find main binary") + .map(|b| b.name.as_str()) + .map_err(Into::into) } /// Returns the path to the specified binary. diff --git a/crates/tauri-bundler/src/bundle/windows/msi/wix.rs b/crates/tauri-bundler/src/bundle/windows/msi/wix.rs index 362ca1ff87f1..ba8a368bec0b 100644 --- a/crates/tauri-bundler/src/bundle/windows/msi/wix.rs +++ b/crates/tauri-bundler/src/bundle/windows/msi/wix.rs @@ -304,11 +304,7 @@ fn run_candle( } }; - let main_binary = settings - .binaries() - .iter() - .find(|bin| bin.main()) - .ok_or_else(|| anyhow::anyhow!("Failed to get main binary"))?; + let main_binary = settings.main_binary()?; let mut args = vec![ "-arch".to_string(), @@ -404,13 +400,6 @@ pub fn build_wix_app_installer( // target only supports x64. log::info!("Target: {}", arch); - let main_binary = settings - .binaries() - .iter() - .find(|bin| bin.main()) - .ok_or_else(|| anyhow::anyhow!("Failed to get main binary"))?; - let app_exe_source = settings.binary_path(main_binary); - let output_path = settings.project_out_directory().join("wix").join(arch); if output_path.exists() { @@ -540,9 +529,6 @@ pub fn build_wix_app_installer( let shortcut_guid = generate_package_guid(settings).to_string(); data.insert("shortcut_guid", to_json(shortcut_guid.as_str())); - let app_exe_name = settings.main_binary_name().to_string(); - data.insert("app_exe_name", to_json(app_exe_name)); - let binaries = generate_binaries_data(settings)?; let binaries_json = to_json(binaries); @@ -565,7 +551,12 @@ pub fn build_wix_app_installer( let merge_modules = get_merge_modules(settings)?; data.insert("merge_modules", to_json(merge_modules)); - data.insert("app_exe_source", to_json(app_exe_source)); + let main_binary_name = settings.main_binary_name()?; + data.insert("main_binary_name", to_json(main_binary_name)); + + let main_binary = settings.main_binary()?; + let main_binary_path = settings.binary_path(main_binary); + data.insert("main_binary_path", to_json(main_binary_path)); // copy icon from `settings.windows().icon_path` folder to resource folder near msi let icon_path = copy_icon(settings, "icon.ico", &settings.windows().icon_path)?; diff --git a/crates/tauri-bundler/src/bundle/windows/nsis.rs b/crates/tauri-bundler/src/bundle/windows/nsis.rs index 5571b2308288..51fdc6c74567 100644 --- a/crates/tauri-bundler/src/bundle/windows/nsis.rs +++ b/crates/tauri-bundler/src/bundle/windows/nsis.rs @@ -336,21 +336,9 @@ fn build_nsis_app_installer( } data.insert("language_files", to_json(language_files_paths)); - let main_binary = settings - .binaries() - .iter() - .find(|bin| bin.main()) - .ok_or_else(|| anyhow::anyhow!("Failed to get main binary"))?; + let main_binary = settings.main_binary()?; let main_binary_path = settings.binary_path(main_binary).with_extension("exe"); - data.insert( - "main_binary_name", - to_json( - main_binary_path - .file_stem() - .and_then(|file_name| file_name.to_str()) - .unwrap_or_else(|| main_binary.name()), - ), - ); + data.insert("main_binary_name", to_json(main_binary.name())); data.insert("main_binary_path", to_json(&main_binary_path)); let out_file = "nsis-output.exe"; diff --git a/crates/tauri-bundler/src/bundle/windows/templates/main.wxs b/crates/tauri-bundler/src/bundle/windows/templates/main.wxs index 047b0926e1a4..1a5db6cc5868 100644 --- a/crates/tauri-bundler/src/bundle/windows/templates/main.wxs +++ b/crates/tauri-bundler/src/bundle/windows/templates/main.wxs @@ -139,7 +139,7 @@ {{/each~}} - + {{#each file_associations as |association| ~}} {{#each association.ext as |ext| ~}} diff --git a/crates/tauri-cli/config.schema.json b/crates/tauri-cli/config.schema.json index 4cc3b65b1ce3..9b9c43f47e81 100644 --- a/crates/tauri-cli/config.schema.json +++ b/crates/tauri-cli/config.schema.json @@ -22,6 +22,13 @@ ], "pattern": "^[^/\\:*?\"<>|]+$" }, + "mainBinaryName": { + "description": "App main binary filename. Defaults to the name of your cargo crate.", + "type": [ + "string", + "null" + ] + }, "version": { "description": "App version. It is a semver version number or a path to a `package.json` file containing the `version` field. If removed the version number from `Cargo.toml` is used.\n\n By default version 1.0 is used on Android.", "type": [ diff --git a/crates/tauri-cli/src/build.rs b/crates/tauri-cli/src/build.rs index dd3f7c93ed53..46ace0f95ec3 100644 --- a/crates/tauri-cli/src/build.rs +++ b/crates/tauri-cli/src/build.rs @@ -9,7 +9,7 @@ use crate::{ app_paths::tauri_dir, config::{get as get_config, ConfigHandle, FrontendDist}, }, - interface::{AppInterface, AppSettings, Interface}, + interface::{AppInterface, Interface}, ConfigValue, Result, }; use anyhow::Context; @@ -83,10 +83,9 @@ pub fn command(mut options: Options, verbosity: u8) -> Result<()> { let app_settings = interface.app_settings(); let interface_options = options.clone().into(); - let bin_path = app_settings.app_binary_path(&interface_options)?; - let out_dir = bin_path.parent().unwrap(); + let out_dir = app_settings.out_dir(&interface_options)?; - interface.build(interface_options)?; + let bin_path = interface.build(interface_options)?; log::info!(action ="Built"; "application at: {}", tauri_utils::display_path(&bin_path)); @@ -100,7 +99,7 @@ pub fn command(mut options: Options, verbosity: u8) -> Result<()> { &interface, &app_settings, config_, - out_dir, + &out_dir, )?; } diff --git a/crates/tauri-cli/src/bundle.rs b/crates/tauri-cli/src/bundle.rs index d3b428c27207..6ccd56f07f39 100644 --- a/crates/tauri-cli/src/bundle.rs +++ b/crates/tauri-cli/src/bundle.rs @@ -121,8 +121,7 @@ pub fn command(options: Options, verbosity: u8) -> crate::Result<()> { let app_settings = interface.app_settings(); let interface_options = options.clone().into(); - let bin_path = app_settings.app_binary_path(&interface_options)?; - let out_dir = bin_path.parent().unwrap(); + let out_dir = app_settings.out_dir(&interface_options)?; bundle( &options, @@ -131,7 +130,7 @@ pub fn command(options: Options, verbosity: u8) -> crate::Result<()> { &interface, &app_settings, config_, - out_dir, + &out_dir, ) } diff --git a/crates/tauri-cli/src/interface/mod.rs b/crates/tauri-cli/src/interface/mod.rs index 775b4a44984d..3dc3dd58ed5f 100644 --- a/crates/tauri-cli/src/interface/mod.rs +++ b/crates/tauri-cli/src/interface/mod.rs @@ -55,10 +55,16 @@ pub trait AppSettings { tauri_utils::platform::target_triple()? }; + let mut bins = self.get_binaries(&target)?; + if let Some(main_binary_name) = &config.main_binary_name { + let main = bins.iter_mut().find(|b| b.main()).context("no main bin?")?; + main.set_name(main_binary_name.to_owned()); + } + let mut settings_builder = SettingsBuilder::new() .package_settings(self.get_package_settings()) .bundle_settings(self.get_bundle_settings(config, &enabled_features)?) - .binaries(self.get_binaries(&target)?) + .binaries(bins) .project_out_directory(out_dir) .target(target) .package_types(package_types); @@ -91,7 +97,7 @@ pub trait Interface: Sized { fn new(config: &Config, target: Option) -> crate::Result; fn app_settings(&self) -> Arc; fn env(&self) -> HashMap<&str, String>; - fn build(&mut self, options: Options) -> crate::Result<()>; + fn build(&mut self, options: Options) -> crate::Result; fn dev, ExitReason) + Send + Sync + 'static>( &mut self, options: Options, diff --git a/crates/tauri-cli/src/interface/rust.rs b/crates/tauri-cli/src/interface/rust.rs index b18759d6307e..33d0ce7df311 100644 --- a/crates/tauri-cli/src/interface/rust.rs +++ b/crates/tauri-cli/src/interface/rust.rs @@ -115,6 +115,7 @@ pub struct Rust { app_settings: Arc, config_features: Vec, available_targets: Option>, + main_binary_name: Option, } impl Interface for Rust { @@ -160,6 +161,7 @@ impl Interface for Rust { Ok(Self { app_settings: Arc::new(app_settings), config_features: config.build.features.clone().unwrap_or_default(), + main_binary_name: config.main_binary_name.clone(), available_targets: None, }) } @@ -168,14 +170,14 @@ impl Interface for Rust { self.app_settings.clone() } - fn build(&mut self, options: Options) -> crate::Result<()> { + fn build(&mut self, options: Options) -> crate::Result { desktop::build( options, &self.app_settings, &mut self.available_targets, self.config_features.clone(), - )?; - Ok(()) + self.main_binary_name.as_deref(), + ) } fn dev, ExitReason) + Send + Sync + 'static>( @@ -498,6 +500,7 @@ impl Rust { &mut self.available_targets, self.config_features.clone(), &self.app_settings, + self.main_binary_name.clone(), on_exit, ) .map(|c| Box::new(c) as Box) @@ -665,7 +668,6 @@ struct WorkspacePackageSettings { #[derive(Clone, Debug, Deserialize)] struct BinarySettings { name: String, - path: Option, } /// The package settings. @@ -865,32 +867,30 @@ impl AppSettings for RustAppSettings { let bin_name = binaries .iter() .find(|x| x.main()) - .expect("failed to find main binary") + .context("failed to find main binary")? .name(); let out_dir = self .out_dir(options) - .with_context(|| "failed to get project out directory")?; + .context("failed to get project out directory")?; - let binary_extension: String = if self.target_triple.contains("windows") { + let ext = if self.target_triple.contains("windows") { "exe" } else { "" - } - .into(); + }; - Ok(out_dir.join(bin_name).with_extension(binary_extension)) + Ok(out_dir.join(bin_name).with_extension(ext)) } fn get_binaries(&self, target: &str) -> crate::Result> { let mut binaries: Vec = vec![]; - let binary_extension: String = if target.contains("windows") { + let ext = if target.contains("windows") { ".exe" } else { "" - } - .into(); + }; if let Some(bins) = &self.cargo_settings.bin { let default_run = self @@ -899,10 +899,9 @@ impl AppSettings for RustAppSettings { .clone() .unwrap_or_default(); for bin in bins { - let name = format!("{}{}", bin.name, binary_extension); - let is_main = - bin.name == self.cargo_package_settings.name || bin.name.as_str() == default_run; - binaries.push(BundleBinary::with_path(name, is_main, bin.path.clone())) + let name = format!("{}{}", bin.name, ext); + let is_main = bin.name == self.cargo_package_settings.name || bin.name == default_run; + binaries.push(BundleBinary::new(name, is_main)) } } @@ -912,12 +911,9 @@ impl AppSettings for RustAppSettings { for entry in fs_bins { let path = entry?.path(); if let Some(name) = path.file_stem() { - let bin_exists = binaries.iter().any(|bin| { - bin.name() == name || path.ends_with(bin.src_path().unwrap_or(&"".to_string())) - }); - if !bin_exists { + if !binaries.iter().any(|bin| bin.name() == name) { binaries.push(BundleBinary::new( - format!("{}{}", name.to_string_lossy(), &binary_extension), + format!("{}{}", name.to_string_lossy(), ext), false, )) } @@ -927,16 +923,13 @@ impl AppSettings for RustAppSettings { if let Some(default_run) = self.package_settings.default_run.as_ref() { if !binaries.iter_mut().any(|bin| bin.name() == default_run) { - binaries.push(BundleBinary::new( - format!("{}{}", default_run, binary_extension), - true, - )); + binaries.push(BundleBinary::new(format!("{}{}", default_run, ext), true)); } } match binaries.len() { 0 => binaries.push(BundleBinary::new( - format!("{}{}", self.cargo_package_settings.name, &binary_extension), + format!("{}{}", self.cargo_package_settings.name, ext), true, )), 1 => binaries.get_mut(0).unwrap().set_main(true), diff --git a/crates/tauri-cli/src/interface/rust/desktop.rs b/crates/tauri-cli/src/interface/rust/desktop.rs index c640392afd4c..8cef75f6f67f 100644 --- a/crates/tauri-cli/src/interface/rust/desktop.rs +++ b/crates/tauri-cli/src/interface/rust/desktop.rs @@ -8,7 +8,9 @@ use crate::CommandExt; use anyhow::Context; use shared_child::SharedChild; use std::{ + fs, io::{BufReader, ErrorKind, Write}, + path::PathBuf, process::{Command, ExitStatus, Stdio}, sync::{ atomic::{AtomicBool, Ordering}, @@ -64,6 +66,7 @@ pub fn run_dev, ExitReason) + Send + Sync + 'static>( available_targets: &mut Option>, config_features: Vec, app_settings: &RustAppSettings, + main_binary_name: Option, on_exit: F, ) -> crate::Result { let bin_path = app_settings.app_binary_path(&options)?; @@ -79,6 +82,9 @@ pub fn run_dev, ExitReason) + Send + Sync + 'static>( config_features, move |status, reason| { if status == Some(0) { + let main_binary_name = main_binary_name.as_deref(); + let bin_path = rename_app(bin_path, main_binary_name).expect("failed to rename app"); + let mut app = Command::new(bin_path); app.stdout(os_pipe::dup_stdout().unwrap()); app.stderr(os_pipe::dup_stderr().unwrap()); @@ -119,18 +125,19 @@ pub fn build( app_settings: &RustAppSettings, available_targets: &mut Option>, config_features: Vec, -) -> crate::Result<()> { + main_binary_name: Option<&str>, +) -> crate::Result { + let out_dir = app_settings.out_dir(&options)?; let bin_path = app_settings.app_binary_path(&options)?; - let out_dir = bin_path.parent().unwrap(); - - let bin_name = bin_path.file_stem().unwrap(); if !std::env::var("STATIC_VCRUNTIME").map_or(false, |v| v == "false") { std::env::set_var("STATIC_VCRUNTIME", "true"); } if options.target == Some("universal-apple-darwin".into()) { - std::fs::create_dir_all(out_dir).with_context(|| "failed to create project out directory")?; + std::fs::create_dir_all(&out_dir).with_context(|| "failed to create project out directory")?; + + let bin_name = bin_path.file_stem().unwrap(); let mut lipo_cmd = Command::new("lipo"); lipo_cmd @@ -162,7 +169,7 @@ pub fn build( .with_context(|| "failed to build app")?; } - Ok(()) + rename_app(bin_path, main_binary_name) } fn build_dev_app, ExitReason) + Send + 'static>( @@ -363,6 +370,25 @@ fn validate_target( Ok(()) } +fn rename_app(bin_path: PathBuf, main_binary_name: Option<&str>) -> crate::Result { + if let Some(main_binary_name) = main_binary_name { + let new_path = bin_path + .with_file_name(main_binary_name) + .with_extension(bin_path.extension().unwrap_or_default()); + + fs::rename(&bin_path, &new_path).with_context(|| { + format!( + "failed to rename `{}` to `{}`", + tauri_utils::display_path(bin_path), + tauri_utils::display_path(&new_path), + ) + })?; + Ok(new_path) + } else { + Ok(bin_path) + } +} + // taken from https://github.com/rust-lang/cargo/blob/78b10d4e611ab0721fc3aeaf0edd5dd8f4fdc372/src/cargo/core/shell.rs#L514 #[cfg(unix)] mod terminal { diff --git a/crates/tauri-cli/src/mobile/android/build.rs b/crates/tauri-cli/src/mobile/android/build.rs index 4e5e69ad1bda..f6ccf7eaf3a6 100644 --- a/crates/tauri-cli/src/mobile/android/build.rs +++ b/crates/tauri-cli/src/mobile/android/build.rs @@ -13,7 +13,7 @@ use crate::{ config::{get as get_tauri_config, ConfigHandle}, flock, }, - interface::{AppInterface, AppSettings, Interface, Options as InterfaceOptions}, + interface::{AppInterface, Interface, Options as InterfaceOptions}, mobile::{write_options, CliOptions}, ConfigValue, Result, }; @@ -191,8 +191,7 @@ fn run_build( }; let app_settings = interface.app_settings(); - let bin_path = app_settings.app_binary_path(&interface_options)?; - let out_dir = bin_path.parent().unwrap(); + let out_dir = app_settings.out_dir(&interface_options)?; let _lock = flock::open_rw(out_dir.join("lock").with_extension("android"), "Android")?; let cli_options = CliOptions { diff --git a/crates/tauri-cli/src/mobile/android/dev.rs b/crates/tauri-cli/src/mobile/android/dev.rs index 664076d0c8bc..312f9f2b409d 100644 --- a/crates/tauri-cli/src/mobile/android/dev.rs +++ b/crates/tauri-cli/src/mobile/android/dev.rs @@ -13,7 +13,7 @@ use crate::{ config::{get as get_tauri_config, ConfigHandle}, flock, }, - interface::{AppInterface, AppSettings, Interface, MobileOptions, Options as InterfaceOptions}, + interface::{AppInterface, Interface, MobileOptions, Options as InterfaceOptions}, mobile::{write_options, CliOptions, DevChild, DevProcess, TargetDevice}, ConfigValue, Result, }; @@ -186,8 +186,7 @@ fn run_dev( }; let app_settings = interface.app_settings(); - let bin_path = app_settings.app_binary_path(&interface_options)?; - let out_dir = bin_path.parent().unwrap(); + let out_dir = app_settings.out_dir(&interface_options)?; let _lock = flock::open_rw(out_dir.join("lock").with_extension("android"), "Android")?; configure_cargo(&mut env, config)?; diff --git a/crates/tauri-cli/src/mobile/ios/build.rs b/crates/tauri-cli/src/mobile/ios/build.rs index 4eacfa72c7a4..8f12c5d5fd5e 100644 --- a/crates/tauri-cli/src/mobile/ios/build.rs +++ b/crates/tauri-cli/src/mobile/ios/build.rs @@ -271,12 +271,11 @@ fn run_build( crate::build::setup(&interface, &mut build_options, tauri_config.clone(), true)?; let app_settings = interface.app_settings(); - let bin_path = app_settings.app_binary_path(&InterfaceOptions { + let out_dir = app_settings.out_dir(&InterfaceOptions { debug: build_options.debug, target: build_options.target.clone(), ..Default::default() })?; - let out_dir = bin_path.parent().unwrap(); let _lock = flock::open_rw(out_dir.join("lock").with_extension("ios"), "iOS")?; let cli_options = CliOptions { diff --git a/crates/tauri-cli/src/mobile/ios/dev.rs b/crates/tauri-cli/src/mobile/ios/dev.rs index 1814f499f56d..24ae6bf309e0 100644 --- a/crates/tauri-cli/src/mobile/ios/dev.rs +++ b/crates/tauri-cli/src/mobile/ios/dev.rs @@ -377,12 +377,11 @@ fn run_dev( crate::dev::setup(&interface, &mut dev_options, tauri_config.clone())?; let app_settings = interface.app_settings(); - let bin_path = app_settings.app_binary_path(&InterfaceOptions { + let out_dir = app_settings.out_dir(&InterfaceOptions { debug: !dev_options.release_mode, target: dev_options.target.clone(), ..Default::default() })?; - let out_dir = bin_path.parent().unwrap(); let _lock = flock::open_rw(out_dir.join("lock").with_extension("ios"), "iOS")?; let set_host = options.host.is_some(); diff --git a/crates/tauri-cli/src/mobile/ios/xcode_script.rs b/crates/tauri-cli/src/mobile/ios/xcode_script.rs index fb566861e61c..29ab3541bf26 100644 --- a/crates/tauri-cli/src/mobile/ios/xcode_script.rs +++ b/crates/tauri-cli/src/mobile/ios/xcode_script.rs @@ -215,14 +215,11 @@ pub fn command(options: Options) -> Result<()> { target_env, )?; - let bin_path = interface - .app_settings() - .app_binary_path(&InterfaceOptions { - debug: matches!(profile, Profile::Debug), - target: Some(rust_triple.into()), - ..Default::default() - })?; - let out_dir = bin_path.parent().unwrap(); + let out_dir = interface.app_settings().out_dir(&InterfaceOptions { + debug: matches!(profile, Profile::Debug), + target: Some(rust_triple.into()), + ..Default::default() + })?; let lib_path = out_dir.join(format!("lib{}.a", config.app().lib_name())); if !lib_path.exists() { diff --git a/crates/tauri-cli/src/mobile/mod.rs b/crates/tauri-cli/src/mobile/mod.rs index b4292a285bd2..fda97d51261f 100644 --- a/crates/tauri-cli/src/mobile/mod.rs +++ b/crates/tauri-cli/src/mobile/mod.rs @@ -282,14 +282,13 @@ pub fn get_app(target: Target, config: &TauriConfig, interface: &AppInterface) - App::from_raw(tauri_dir().to_path_buf(), raw) .unwrap() .with_target_dir_resolver(move |target, profile| { - let bin_path = app_settings - .app_binary_path(&InterfaceOptions { + app_settings + .out_dir(&InterfaceOptions { debug: matches!(profile, Profile::Debug), target: Some(target.into()), ..Default::default() }) - .expect("failed to resolve target directory"); - bin_path.parent().unwrap().to_path_buf() + .expect("failed to resolve target directory") }) } diff --git a/crates/tauri-schema-generator/schemas/config.schema.json b/crates/tauri-schema-generator/schemas/config.schema.json index 4cc3b65b1ce3..9b9c43f47e81 100644 --- a/crates/tauri-schema-generator/schemas/config.schema.json +++ b/crates/tauri-schema-generator/schemas/config.schema.json @@ -22,6 +22,13 @@ ], "pattern": "^[^/\\:*?\"<>|]+$" }, + "mainBinaryName": { + "description": "App main binary filename. Defaults to the name of your cargo crate.", + "type": [ + "string", + "null" + ] + }, "version": { "description": "App version. It is a semver version number or a path to a `package.json` file containing the `version` field. If removed the version number from `Cargo.toml` is used.\n\n By default version 1.0 is used on Android.", "type": [ diff --git a/crates/tauri-utils/src/config.rs b/crates/tauri-utils/src/config.rs index 75b25c7b3e77..612eb919bfe1 100644 --- a/crates/tauri-utils/src/config.rs +++ b/crates/tauri-utils/src/config.rs @@ -2242,6 +2242,9 @@ pub struct Config { #[serde(alias = "product-name")] #[cfg_attr(feature = "schema", validate(regex(pattern = "^[^/\\:*?\"<>|]+$")))] pub product_name: Option, + /// App main binary filename. Defaults to the name of your cargo crate. + #[serde(alias = "main-binary-name")] + pub main_binary_name: Option, /// App version. It is a semver version number or a path to a `package.json` file containing the `version` field. If removed the version number from `Cargo.toml` is used. /// /// By default version 1.0 is used on Android. @@ -2836,6 +2839,7 @@ mod build { fn to_tokens(&self, tokens: &mut TokenStream) { let schema = quote!(None); let product_name = opt_str_lit(self.product_name.as_ref()); + let main_binary_name = opt_str_lit(self.main_binary_name.as_ref()); let version = opt_str_lit(self.version.as_ref()); let identifier = str_lit(&self.identifier); let app = &self.app; @@ -2848,6 +2852,7 @@ mod build { ::tauri::utils::config::Config, schema, product_name, + main_binary_name, version, identifier, app, diff --git a/crates/tauri-utils/src/platform.rs b/crates/tauri-utils/src/platform.rs index fcf47a9703d6..162539c9692b 100644 --- a/crates/tauri-utils/src/platform.rs +++ b/crates/tauri-utils/src/platform.rs @@ -312,7 +312,7 @@ fn resource_dir_from>( res = if curr_dir.ends_with("/data/usr/bin") { // running from the deb bundle dir exe_dir - .join(format!("../lib/{}", package_info.crate_name)) + .join(format!("../lib/{}", package_info.name)) .canonicalize() .map_err(Into::into) } else if let Some(appdir) = &env.appdir { @@ -320,14 +320,11 @@ fn resource_dir_from>( Ok(PathBuf::from(format!( "{}/usr/lib/{}", appdir.display(), - package_info.crate_name + package_info.name ))) } else { // running bundle - Ok(PathBuf::from(format!( - "/usr/lib/{}", - package_info.crate_name - ))) + Ok(PathBuf::from(format!("/usr/lib/{}", package_info.name))) }; } diff --git a/crates/tauri/src/test/mod.rs b/crates/tauri/src/test/mod.rs index fa0c99e4fe59..ad2bd5ef352e 100644 --- a/crates/tauri/src/test/mod.rs +++ b/crates/tauri/src/test/mod.rs @@ -110,6 +110,7 @@ pub fn mock_context>(assets: A) -> crate::Context { config: Config { schema: None, product_name: Default::default(), + main_binary_name: Default::default(), version: Default::default(), identifier: Default::default(), app: AppConfig { diff --git a/crates/tauri/src/window/mod.rs b/crates/tauri/src/window/mod.rs index cecc7917bef1..076d3cbfe0c2 100644 --- a/crates/tauri/src/window/mod.rs +++ b/crates/tauri/src/window/mod.rs @@ -1980,7 +1980,7 @@ tauri::Builder::default() .set_progress_bar(crate::runtime::ProgressBarState { status: progress_state.status, progress: progress_state.progress, - desktop_filename: Some(format!("{}.desktop", self.package_info().crate_name)), + desktop_filename: Some(format!("{}.desktop", self.package_info().name)), }) .map_err(Into::into) }