Skip to content

Commit 5ecb46b

Browse files
fix: rpath missing from app, closes #7710 (#7773)
Co-authored-by: Lucas Nogueira <lucas@tauri.app> Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.studio> fix: codesign doesn't sign frameworks or sidecar, closes #7690 (#7774)
1 parent dcdbe3e commit 5ecb46b

4 files changed

Lines changed: 130 additions & 2 deletions

File tree

.changes/rpath.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri-build": patch:bug
3+
---
4+
5+
Automatically set rpath on macOS if frameworks are bundled and copy frameworks to `src-tauri/target/Frameworks` for usage in development.

core/tauri-build/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ heck = "0.4"
2828
json-patch = "1.0"
2929
tauri-winres = "0.1"
3030
semver = "1"
31+
walkdir = "2"
32+
dirs-next = "2"
3133

3234
[features]
3335
codegen = [ "tauri-codegen", "quote" ]

core/tauri-build/src/lib.rs

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#![cfg_attr(doc_cfg, feature(doc_cfg))]
66

7+
use anyhow::Context;
78
pub use anyhow::Result;
89
use cargo_toml::Manifest;
910
use heck::AsShoutySnakeCase;
@@ -80,6 +81,113 @@ fn copy_resources(resources: ResourcePaths<'_>, path: &Path) -> Result<()> {
8081
Ok(())
8182
}
8283

84+
#[cfg(unix)]
85+
fn symlink_dir(src: &Path, dst: &Path) -> std::io::Result<()> {
86+
std::os::unix::fs::symlink(src, dst)
87+
}
88+
89+
/// Makes a symbolic link to a directory.
90+
#[cfg(windows)]
91+
fn symlink_dir(src: &Path, dst: &Path) -> std::io::Result<()> {
92+
std::os::windows::fs::symlink_dir(src, dst)
93+
}
94+
95+
/// Makes a symbolic link to a file.
96+
#[cfg(unix)]
97+
fn symlink_file(src: &Path, dst: &Path) -> std::io::Result<()> {
98+
std::os::unix::fs::symlink(src, dst)
99+
}
100+
101+
/// Makes a symbolic link to a file.
102+
#[cfg(windows)]
103+
fn symlink_file(src: &Path, dst: &Path) -> std::io::Result<()> {
104+
std::os::windows::fs::symlink_file(src, dst)
105+
}
106+
107+
fn copy_dir(from: &Path, to: &Path) -> Result<()> {
108+
for entry in walkdir::WalkDir::new(from) {
109+
let entry = entry?;
110+
debug_assert!(entry.path().starts_with(from));
111+
let rel_path = entry.path().strip_prefix(from)?;
112+
let dest_path = to.join(rel_path);
113+
if entry.file_type().is_symlink() {
114+
let target = std::fs::read_link(entry.path())?;
115+
if entry.path().is_dir() {
116+
symlink_dir(&target, &dest_path)?;
117+
} else {
118+
symlink_file(&target, &dest_path)?;
119+
}
120+
} else if entry.file_type().is_dir() {
121+
std::fs::create_dir(dest_path)?;
122+
} else {
123+
std::fs::copy(entry.path(), dest_path)?;
124+
}
125+
}
126+
Ok(())
127+
}
128+
129+
// Copies the framework under `{src_dir}/{framework}.framework` to `{dest_dir}/{framework}.framework`.
130+
fn copy_framework_from(src_dir: &Path, framework: &str, dest_dir: &Path) -> Result<bool> {
131+
let src_name = format!("{}.framework", framework);
132+
let src_path = src_dir.join(&src_name);
133+
if src_path.exists() {
134+
copy_dir(&src_path, &dest_dir.join(&src_name))?;
135+
Ok(true)
136+
} else {
137+
Ok(false)
138+
}
139+
}
140+
141+
// Copies the macOS application bundle frameworks to the target folder
142+
fn copy_frameworks(dest_dir: &Path, frameworks: &[String]) -> Result<()> {
143+
std::fs::create_dir_all(dest_dir).with_context(|| {
144+
format!(
145+
"Failed to create frameworks output directory at {:?}",
146+
dest_dir
147+
)
148+
})?;
149+
for framework in frameworks.iter() {
150+
if framework.ends_with(".framework") {
151+
let src_path = PathBuf::from(framework);
152+
let src_name = src_path
153+
.file_name()
154+
.expect("Couldn't get framework filename");
155+
let dest_path = dest_dir.join(src_name);
156+
copy_dir(&src_path, &dest_path)?;
157+
continue;
158+
} else if framework.ends_with(".dylib") {
159+
let src_path = PathBuf::from(framework);
160+
if !src_path.exists() {
161+
return Err(anyhow::anyhow!("Library not found: {}", framework));
162+
}
163+
let src_name = src_path.file_name().expect("Couldn't get library filename");
164+
let dest_path = dest_dir.join(src_name);
165+
copy_file(&src_path, &dest_path)?;
166+
continue;
167+
} else if framework.contains('/') {
168+
return Err(anyhow::anyhow!(
169+
"Framework path should have .framework extension: {}",
170+
framework
171+
));
172+
}
173+
if let Some(home_dir) = dirs_next::home_dir() {
174+
if copy_framework_from(&home_dir.join("Library/Frameworks/"), framework, dest_dir)? {
175+
continue;
176+
}
177+
}
178+
if copy_framework_from(&PathBuf::from("/Library/Frameworks/"), framework, dest_dir)?
179+
|| copy_framework_from(
180+
&PathBuf::from("/Network/Library/Frameworks/"),
181+
framework,
182+
dest_dir,
183+
)?
184+
{
185+
continue;
186+
}
187+
}
188+
Ok(())
189+
}
190+
83191
// checks if the given Cargo feature is enabled.
84192
fn has_feature(feature: &str) -> bool {
85193
// when a feature is enabled, Cargo sets the `CARGO_FEATURE_<name` env var to 1
@@ -370,13 +478,26 @@ pub fn try_build(attributes: Attributes) -> Result<()> {
370478
}
371479

372480
if target_triple.contains("darwin") {
481+
if let Some(frameworks) = &config.tauri.bundle.macos.frameworks {
482+
if !frameworks.is_empty() {
483+
let frameworks_dir = target_dir.parent().unwrap().join("Frameworks");
484+
let _ = std::fs::remove_dir_all(&frameworks_dir);
485+
// copy frameworks to the root `target` folder (instead of `target/debug` for instance)
486+
// because the rpath is set to `@executable_path/../Frameworks`.
487+
copy_frameworks(&frameworks_dir, frameworks)?;
488+
489+
// If we have frameworks, we need to set the @rpath
490+
// https://github.com/tauri-apps/tauri/issues/7710
491+
println!("cargo:rustc-link-arg=-Wl,-rpath,@executable_path/../Frameworks");
492+
}
493+
}
494+
373495
if let Some(version) = &config.tauri.bundle.macos.minimum_system_version {
374496
println!("cargo:rustc-env=MACOSX_DEPLOYMENT_TARGET={version}");
375497
}
376498
}
377499

378500
if target_triple.contains("windows") {
379-
use anyhow::Context;
380501
use semver::Version;
381502
use tauri_winres::{VersionInfo, WindowsResource};
382503

core/tauri-codegen/src/context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
351351
}
352352

353353
info_plist
354-
.to_file_xml(&out_dir.join("Info.plist"))
354+
.to_file_xml(out_dir.join("Info.plist"))
355355
.expect("failed to write Info.plist");
356356
quote!({
357357
tauri::embed_plist::embed_info_plist!(concat!(std::env!("OUT_DIR"), "/Info.plist"));

0 commit comments

Comments
 (0)