diff --git a/qt/launcher/lin/build.sh b/qt/launcher/lin/build.sh index e4ddce243..de96a1b50 100755 --- a/qt/launcher/lin/build.sh +++ b/qt/launcher/lin/build.sh @@ -1,9 +1,15 @@ #!/bin/bash +# +# This script currently only supports universal builds on x86_64. +# set -e # Add Linux cross-compilation target rustup target add aarch64-unknown-linux-gnu +# Detect host architecture +HOST_ARCH=$(uname -m) + # Define output paths OUTPUT_DIR="../../../out/launcher" @@ -12,11 +18,18 @@ LAUNCHER_DIR="$OUTPUT_DIR/anki-launcher" # Clean existing output directory rm -rf "$LAUNCHER_DIR" -# Build binaries for both Linux architectures -cargo build -p launcher --release --target x86_64-unknown-linux-gnu -CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ +# Build binaries based on host architecture +if [ "$HOST_ARCH" = "aarch64" ]; then + # On aarch64 host, only build for aarch64 cargo build -p launcher --release --target aarch64-unknown-linux-gnu -(cd ../../.. && ./ninja extract:uv_lin_arm) +else + # On other hosts, build for both architectures + cargo build -p launcher --release --target x86_64-unknown-linux-gnu + CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ + cargo build -p launcher --release --target aarch64-unknown-linux-gnu + # Extract uv_lin_arm for cross-compilation + (cd ../../.. && ./ninja extract:uv_lin_arm) +fi # Create output directory mkdir -p "$LAUNCHER_DIR" @@ -24,13 +37,21 @@ mkdir -p "$LAUNCHER_DIR" # Copy binaries and support files TARGET_DIR=${CARGO_TARGET_DIR:-../../../target} -# Copy launcher binaries with architecture suffixes -cp "$TARGET_DIR/x86_64-unknown-linux-gnu/release/launcher" "$LAUNCHER_DIR/launcher.amd64" -cp "$TARGET_DIR/aarch64-unknown-linux-gnu/release/launcher" "$LAUNCHER_DIR/launcher.arm64" - -# Copy uv binaries with architecture suffixes -cp "../../../out/extracted/uv/uv" "$LAUNCHER_DIR/uv.amd64" -cp "../../../out/extracted/uv_lin_arm/uv" "$LAUNCHER_DIR/uv.arm64" +# Copy binaries with architecture suffixes +if [ "$HOST_ARCH" = "aarch64" ]; then + # On aarch64 host, copy arm64 binary to both locations + cp "$TARGET_DIR/aarch64-unknown-linux-gnu/release/launcher" "$LAUNCHER_DIR/launcher.amd64" + cp "$TARGET_DIR/aarch64-unknown-linux-gnu/release/launcher" "$LAUNCHER_DIR/launcher.arm64" + # Copy uv binary to both locations + cp "../../../out/extracted/uv/uv" "$LAUNCHER_DIR/uv.amd64" + cp "../../../out/extracted/uv/uv" "$LAUNCHER_DIR/uv.arm64" +else + # On other hosts, copy architecture-specific binaries + cp "$TARGET_DIR/x86_64-unknown-linux-gnu/release/launcher" "$LAUNCHER_DIR/launcher.amd64" + cp "$TARGET_DIR/aarch64-unknown-linux-gnu/release/launcher" "$LAUNCHER_DIR/launcher.arm64" + cp "../../../out/extracted/uv/uv" "$LAUNCHER_DIR/uv.amd64" + cp "../../../out/extracted/uv_lin_arm/uv" "$LAUNCHER_DIR/uv.arm64" +fi # Copy support files from lin directory for file in README.md anki.1 anki.desktop anki.png anki.xml anki.xpm install.sh uninstall.sh anki; do diff --git a/qt/launcher/src/platform/mac.rs b/qt/launcher/src/platform/mac.rs index 57d6bcc73..2369f538a 100644 --- a/qt/launcher/src/platform/mac.rs +++ b/qt/launcher/src/platform/mac.rs @@ -15,6 +15,7 @@ use anyhow::Result; // Re-export Unix functions that macOS uses pub use super::unix::{ + ensure_terminal_shown, exec_anki, get_anki_binary_path, initial_terminal_setup, @@ -36,20 +37,7 @@ pub fn launch_anki_detached(anki_bin: &std::path::Path, _config: &crate::Config) Ok(()) } -pub fn ensure_terminal_shown() -> Result<()> { - let stdout_is_terminal = std::io::IsTerminal::is_terminal(&std::io::stdout()); - if !stdout_is_terminal { - // If launched from GUI, relaunch in Terminal.app - relaunch_in_terminal()?; - } - - // Set terminal title to "Anki Launcher" - print!("\x1b]0;Anki Launcher\x07"); - - Ok(()) -} - -fn relaunch_in_terminal() -> Result<()> { +pub fn relaunch_in_terminal() -> Result<()> { let current_exe = std::env::current_exe().context("Failed to get current executable path")?; Command::new("open") .args(["-a", "Terminal"]) diff --git a/qt/launcher/src/platform/unix.rs b/qt/launcher/src/platform/unix.rs index 65a223f30..324bf5aa3 100644 --- a/qt/launcher/src/platform/unix.rs +++ b/qt/launcher/src/platform/unix.rs @@ -3,6 +3,7 @@ #![allow(dead_code)] +use std::io::IsTerminal; use std::path::PathBuf; use std::process::Command; @@ -17,8 +18,58 @@ pub fn initial_terminal_setup(_config: &mut Config) { } pub fn ensure_terminal_shown() -> Result<()> { - // Skip terminal relaunch on non-macOS Unix systems as we don't know which - // terminal is installed + let stdout_is_terminal = IsTerminal::is_terminal(&std::io::stdout()); + if !stdout_is_terminal { + // If launched from GUI, try to relaunch in a terminal + crate::platform::relaunch_in_terminal()?; + } + + // Set terminal title to "Anki Launcher" + print!("\x1b]2;Anki Launcher\x07"); + + Ok(()) +} + +#[cfg(not(target_os = "macos"))] +pub fn relaunch_in_terminal() -> Result<()> { + let current_exe = std::env::current_exe().context("Failed to get current executable path")?; + + // Try terminals in order of preference + let terminals = [ + ("x-terminal-emulator", vec!["-e"]), + ("gnome-terminal", vec!["--"]), + ("konsole", vec!["-e"]), + ("xfce4-terminal", vec!["-e"]), + ("alacritty", vec!["-e"]), + ("kitty", vec![]), + ("foot", vec![]), + ("urxvt", vec!["-e"]), + ("xterm", vec!["-e"]), + ]; + + for (terminal_cmd, args) in &terminals { + // Check if terminal exists + if Command::new("which") + .arg(terminal_cmd) + .output() + .map(|o| o.status.success()) + .unwrap_or(false) + { + // Try to launch the terminal + let mut cmd = Command::new(terminal_cmd); + if args.is_empty() { + cmd.arg(¤t_exe); + } else { + cmd.args(args).arg(¤t_exe); + } + + if cmd.spawn().is_ok() { + std::process::exit(0); + } + } + } + + // If no terminal worked, continue without relaunching Ok(()) }