diff --git a/qt/launcher/Cargo.toml b/qt/launcher/Cargo.toml index fd6f2230c..32fb15991 100644 --- a/qt/launcher/Cargo.toml +++ b/qt/launcher/Cargo.toml @@ -14,6 +14,9 @@ anyhow.workspace = true camino.workspace = true dirs.workspace = true +[target.'cfg(all(unix, not(target_os = "macos")))'.dependencies] +libc.workspace = true + [target.'cfg(windows)'.dependencies] windows.workspace = true widestring.workspace = true diff --git a/qt/launcher/mac/Info.plist b/qt/launcher/mac/Info.plist index 59b67605f..6e19087d6 100644 --- a/qt/launcher/mac/Info.plist +++ b/qt/launcher/mac/Info.plist @@ -7,7 +7,7 @@ CFBundleShortVersionString 1.0 LSMinimumSystemVersion - 11 + 12 CFBundleDocumentTypes diff --git a/qt/launcher/src/main.rs b/qt/launcher/src/main.rs index c8cd7e052..2df5ccd15 100644 --- a/qt/launcher/src/main.rs +++ b/qt/launcher/src/main.rs @@ -22,6 +22,7 @@ use anki_process::CommandExt as AnkiCommandExt; use anyhow::Context; use anyhow::Result; +use crate::platform::ensure_os_supported; use crate::platform::ensure_terminal_shown; use crate::platform::get_exe_and_resources_dirs; use crate::platform::get_uv_binary_name; @@ -143,6 +144,8 @@ fn run() -> Result<()> { print!("\x1B[2J\x1B[H"); // Clear screen and move cursor to top println!("\x1B[1mAnki Launcher\x1B[0m\n"); + ensure_os_supported()?; + check_versions(&mut state); main_menu_loop(&state)?; diff --git a/qt/launcher/src/platform/mod.rs b/qt/launcher/src/platform/mod.rs index bbb42df10..50a303656 100644 --- a/qt/launcher/src/platform/mod.rs +++ b/qt/launcher/src/platform/mod.rs @@ -128,3 +128,10 @@ pub fn ensure_terminal_shown() -> Result<()> { print!("\x1b]2;Anki Launcher\x07"); Ok(()) } + +pub fn ensure_os_supported() -> Result<()> { + #[cfg(all(unix, not(target_os = "macos")))] + unix::ensure_glibc_supported()?; + + Ok(()) +} diff --git a/qt/launcher/src/platform/unix.rs b/qt/launcher/src/platform/unix.rs index f37ec81eb..235919106 100644 --- a/qt/launcher/src/platform/unix.rs +++ b/qt/launcher/src/platform/unix.rs @@ -65,3 +65,34 @@ pub fn finalize_uninstall() { let mut input = String::new(); let _ = stdin().read_line(&mut input); } + +pub fn ensure_glibc_supported() -> Result<()> { + use std::ffi::CStr; + let get_glibc_version = || -> Option<(u32, u32)> { + let version_ptr = unsafe { libc::gnu_get_libc_version() }; + if version_ptr.is_null() { + return None; + } + + let version_cstr = unsafe { CStr::from_ptr(version_ptr) }; + let version_str = version_cstr.to_str().ok()?; + + // Parse version string (format: "2.36" or "2.36.1") + let version_parts: Vec<&str> = version_str.split('.').collect(); + if version_parts.len() < 2 { + return None; + } + + let major: u32 = version_parts[0].parse().ok()?; + let minor: u32 = version_parts[1].parse().ok()?; + + Some((major, minor)) + }; + + let (major, minor) = get_glibc_version().unwrap_or_default(); + if major < 3 || (major == 2 && minor < 36) { + anyhow::bail!("Anki requires a modern Linux distro with glibc 2.36 or later."); + } + + Ok(()) +}