Skip to content

Commit 44614be

Browse files
committed
Make libfuse.dylib a weak runtime dependency on macOS
Add weak linking for libfuse on macOS so the binary can load even when macFUSE is not installed. The mount command now checks for libfuse availability at runtime using dlopen and provides a helpful error message if macFUSE is missing.
1 parent a7a0bf4 commit 44614be

2 files changed

Lines changed: 47 additions & 0 deletions

File tree

cli/build.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,12 @@ fn main() {
77
// libgcc_s provides _Unwind_RaiseException and other exception handling symbols
88
println!("cargo:rustc-link-lib=dylib=gcc_s");
99
}
10+
11+
// macOS: Weak-link libfuse so the binary can load without macFUSE installed.
12+
#[cfg(target_os = "macos")]
13+
{
14+
println!("cargo:rustc-link-arg=-Wl,-weak-lfuse");
15+
println!("cargo:rustc-link-search=/usr/local/lib");
16+
println!("cargo:rustc-link-search=/Library/Frameworks/macFUSE.framework/Versions/A");
17+
}
1018
}

cli/src/cmd/mount.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,20 @@ pub struct MountArgs {
2525

2626
/// Mount the agent filesystem using FUSE.
2727
pub fn mount(args: MountArgs) -> Result<()> {
28+
if !supports_fuse() {
29+
#[cfg(target_os = "macos")]
30+
{
31+
anyhow::bail!(
32+
"macFUSE is not installed. Please install it from https://osxfuse.github.io/ \n\
33+
or via Homebrew: brew install --cask macfuse"
34+
);
35+
}
36+
#[cfg(not(target_os = "macos"))]
37+
{
38+
anyhow::bail!("FUSE is not available on this system");
39+
}
40+
}
41+
2842
let opts = AgentFSOptions::resolve(&args.id_or_path)?;
2943

3044
let fsname = std::fs::canonicalize(&args.id_or_path)
@@ -83,3 +97,28 @@ fn is_mounted(path: &std::path::Path) -> bool {
8397
// Different device IDs means it's a mountpoint
8498
path_meta.dev() != parent_meta.dev()
8599
}
100+
101+
/// Check if macOS system supports FUSE.
102+
///
103+
/// The `libfuse` dynamic library is weakly linked so that users who don't have
104+
/// macFUSE installed can still run the other commands.
105+
#[cfg(target_os = "macos")]
106+
fn supports_fuse() -> bool {
107+
for lib_name in &[c"libfuse.2.dylib", c"libfuse.dylib"] {
108+
let handle = unsafe { libc::dlopen(lib_name.as_ptr(), libc::RTLD_LAZY) };
109+
if !handle.is_null() {
110+
unsafe { libc::dlclose(handle) };
111+
return true;
112+
}
113+
}
114+
false
115+
}
116+
117+
/// Check if Linux system supports FUSE.
118+
///
119+
/// The `fuser` crate does not even need `libfuse` so technically it always support FUSE.
120+
/// Of course, if FUSE is disabled in the kernel, we'll get an error, but that's life.
121+
#[cfg(target_os = "linux")]
122+
fn supports_fuse() -> bool {
123+
true
124+
}

0 commit comments

Comments
 (0)