From 5ecb46b3410afd1b5c82494c1e0a91d5a358c41a Mon Sep 17 00:00:00 2001 From: Trey Smith Date: Sun, 24 Sep 2023 18:11:20 -0400 Subject: [PATCH] fix: rpath missing from app, closes #7710 (#7773) Co-authored-by: Lucas Nogueira Co-authored-by: Lucas Fernandes Nogueira fix: codesign doesn't sign frameworks or sidecar, closes #7690 (#7774) --- .changes/rpath.md | 5 ++ core/tauri-build/Cargo.toml | 2 + core/tauri-build/src/lib.rs | 123 +++++++++++++++++++++++++++++- core/tauri-codegen/src/context.rs | 2 +- 4 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 .changes/rpath.md diff --git a/.changes/rpath.md b/.changes/rpath.md new file mode 100644 index 000000000000..1d041bfadcb3 --- /dev/null +++ b/.changes/rpath.md @@ -0,0 +1,5 @@ +--- +"tauri-build": patch:bug +--- + +Automatically set rpath on macOS if frameworks are bundled and copy frameworks to `src-tauri/target/Frameworks` for usage in development. diff --git a/core/tauri-build/Cargo.toml b/core/tauri-build/Cargo.toml index 4f92f8a467ab..9319920ff8ea 100644 --- a/core/tauri-build/Cargo.toml +++ b/core/tauri-build/Cargo.toml @@ -28,6 +28,8 @@ heck = "0.4" json-patch = "1.0" tauri-winres = "0.1" semver = "1" +walkdir = "2" +dirs-next = "2" [features] codegen = [ "tauri-codegen", "quote" ] diff --git a/core/tauri-build/src/lib.rs b/core/tauri-build/src/lib.rs index f5326c071636..045011dfe4e1 100644 --- a/core/tauri-build/src/lib.rs +++ b/core/tauri-build/src/lib.rs @@ -4,6 +4,7 @@ #![cfg_attr(doc_cfg, feature(doc_cfg))] +use anyhow::Context; pub use anyhow::Result; use cargo_toml::Manifest; use heck::AsShoutySnakeCase; @@ -80,6 +81,113 @@ fn copy_resources(resources: ResourcePaths<'_>, path: &Path) -> Result<()> { Ok(()) } +#[cfg(unix)] +fn symlink_dir(src: &Path, dst: &Path) -> std::io::Result<()> { + std::os::unix::fs::symlink(src, dst) +} + +/// Makes a symbolic link to a directory. +#[cfg(windows)] +fn symlink_dir(src: &Path, dst: &Path) -> std::io::Result<()> { + std::os::windows::fs::symlink_dir(src, dst) +} + +/// Makes a symbolic link to a file. +#[cfg(unix)] +fn symlink_file(src: &Path, dst: &Path) -> std::io::Result<()> { + std::os::unix::fs::symlink(src, dst) +} + +/// Makes a symbolic link to a file. +#[cfg(windows)] +fn symlink_file(src: &Path, dst: &Path) -> std::io::Result<()> { + std::os::windows::fs::symlink_file(src, dst) +} + +fn copy_dir(from: &Path, to: &Path) -> Result<()> { + for entry in walkdir::WalkDir::new(from) { + let entry = entry?; + debug_assert!(entry.path().starts_with(from)); + let rel_path = entry.path().strip_prefix(from)?; + let dest_path = to.join(rel_path); + if entry.file_type().is_symlink() { + let target = std::fs::read_link(entry.path())?; + if entry.path().is_dir() { + symlink_dir(&target, &dest_path)?; + } else { + symlink_file(&target, &dest_path)?; + } + } else if entry.file_type().is_dir() { + std::fs::create_dir(dest_path)?; + } else { + std::fs::copy(entry.path(), dest_path)?; + } + } + Ok(()) +} + +// Copies the framework under `{src_dir}/{framework}.framework` to `{dest_dir}/{framework}.framework`. +fn copy_framework_from(src_dir: &Path, framework: &str, dest_dir: &Path) -> Result { + let src_name = format!("{}.framework", framework); + let src_path = src_dir.join(&src_name); + if src_path.exists() { + copy_dir(&src_path, &dest_dir.join(&src_name))?; + Ok(true) + } else { + Ok(false) + } +} + +// Copies the macOS application bundle frameworks to the target folder +fn copy_frameworks(dest_dir: &Path, frameworks: &[String]) -> Result<()> { + std::fs::create_dir_all(dest_dir).with_context(|| { + format!( + "Failed to create frameworks output directory at {:?}", + dest_dir + ) + })?; + for framework in frameworks.iter() { + if framework.ends_with(".framework") { + let src_path = PathBuf::from(framework); + let src_name = src_path + .file_name() + .expect("Couldn't get framework filename"); + let dest_path = dest_dir.join(src_name); + copy_dir(&src_path, &dest_path)?; + continue; + } else if framework.ends_with(".dylib") { + let src_path = PathBuf::from(framework); + if !src_path.exists() { + return Err(anyhow::anyhow!("Library not found: {}", framework)); + } + let src_name = src_path.file_name().expect("Couldn't get library filename"); + let dest_path = dest_dir.join(src_name); + copy_file(&src_path, &dest_path)?; + continue; + } else if framework.contains('/') { + return Err(anyhow::anyhow!( + "Framework path should have .framework extension: {}", + framework + )); + } + if let Some(home_dir) = dirs_next::home_dir() { + if copy_framework_from(&home_dir.join("Library/Frameworks/"), framework, dest_dir)? { + continue; + } + } + if copy_framework_from(&PathBuf::from("/Library/Frameworks/"), framework, dest_dir)? + || copy_framework_from( + &PathBuf::from("/Network/Library/Frameworks/"), + framework, + dest_dir, + )? + { + continue; + } + } + Ok(()) +} + // checks if the given Cargo feature is enabled. fn has_feature(feature: &str) -> bool { // when a feature is enabled, Cargo sets the `CARGO_FEATURE_ Result<()> { } if target_triple.contains("darwin") { + if let Some(frameworks) = &config.tauri.bundle.macos.frameworks { + if !frameworks.is_empty() { + let frameworks_dir = target_dir.parent().unwrap().join("Frameworks"); + let _ = std::fs::remove_dir_all(&frameworks_dir); + // copy frameworks to the root `target` folder (instead of `target/debug` for instance) + // because the rpath is set to `@executable_path/../Frameworks`. + copy_frameworks(&frameworks_dir, frameworks)?; + + // If we have frameworks, we need to set the @rpath + // https://github.com/tauri-apps/tauri/issues/7710 + println!("cargo:rustc-link-arg=-Wl,-rpath,@executable_path/../Frameworks"); + } + } + if let Some(version) = &config.tauri.bundle.macos.minimum_system_version { println!("cargo:rustc-env=MACOSX_DEPLOYMENT_TARGET={version}"); } } if target_triple.contains("windows") { - use anyhow::Context; use semver::Version; use tauri_winres::{VersionInfo, WindowsResource}; diff --git a/core/tauri-codegen/src/context.rs b/core/tauri-codegen/src/context.rs index 0ccd8cf72440..2e95b0f250e1 100644 --- a/core/tauri-codegen/src/context.rs +++ b/core/tauri-codegen/src/context.rs @@ -351,7 +351,7 @@ pub fn context_codegen(data: ContextData) -> Result