diff --git a/Cargo.toml b/Cargo.toml index abe05b3..88f70ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -278,6 +278,18 @@ opt-level = 0 lto = "thin" codegen-units = 1 +# A release build that can say where it panicked: line tables, so a crash +# record's backtrace (`dr_plat::crash`) reads `file.rs:123` rather than bare +# addresses. The macOS build uses it (docs/dev/macos.md) — no one here can +# reproduce a Mac bug, so its reports carry what a debugger would have — at +# the price of a larger binary and no slower code. On macOS the tables land +# in a `.dSYM` beside the executable (rustc's default `packed`), and the +# bundle must carry that directory next to the binary for the backtrace to +# find it. +[profile.diagnostic] +inherits = "release" +debug = "line-tables-only" + # Three upstream crates carry a local patch: wgpu-hal and Slint's Skia # renderer so that the Android build can draw with wgpu on a rotated display # (technical-debt.md TD-1), and rawler so that a linear DNG wider than 16 700 diff --git a/apps/darkroom-desktop/src/main.rs b/apps/darkroom-desktop/src/main.rs index 589b34c..d7a5f75 100644 --- a/apps/darkroom-desktop/src/main.rs +++ b/apps/darkroom-desktop/src/main.rs @@ -15,6 +15,22 @@ use std::path::PathBuf; use dr_plat::diagnostics::Installed; +/// What the log keeps when `RUST_LOG` does not say. +#[cfg(not(target_os = "macos"))] +const DEFAULT_LOG: &str = + "info,wgpu_core=warn,wgpu_hal=warn,zbus=warn,tracing=warn,calloop=warn,rawler=warn"; + +/// The same, and `debug` from this application's own crates and from ONNX +/// Runtime, whose `debug` is how many nodes each provider took +/// (docs/dev/macos.md). Nobody here runs a Mac: every macOS build is in +/// the hands of someone who can send us a log and cannot attach a debugger, +/// so the log is written as if for a debug build. `dr_` is a prefix, and +/// `env_logger` matches directives by prefix, so it names every `dr-*` +/// crate — present and future — without naming a dependency. +#[cfg(target_os = "macos")] +const DEFAULT_LOG: &str = "info,dr_=debug,darkroom_desktop=debug,onnxruntime=debug,\ + wgpu_core=warn,wgpu_hal=warn,zbus=warn,tracing=warn,calloop=warn,rawler=warn"; + fn main() -> anyhow::Result<()> { // TRACES: FR-PLAT-WIN-3 // Before the logger, the crash hook and everything else: this exists so a @@ -33,10 +49,9 @@ fn main() -> anyhow::Result<()> { // (NFR-OPS-1). `filter()` is asked afterwards because the environment may // have overridden the default below, and the file must not be quieter than // the terminal. - let console = env_logger::Builder::from_env(env_logger::Env::default().default_filter_or( - "info,wgpu_core=warn,wgpu_hal=warn,zbus=warn,tracing=warn,calloop=warn,rawler=warn", - )) - .build(); + let console = + env_logger::Builder::from_env(env_logger::Env::default().default_filter_or(DEFAULT_LOG)) + .build(); let level = console.filter(); let logging = dr_plat::diagnostics::install(Box::new(console), level); diff --git a/platform/dr-plat/src/crash.rs b/platform/dr-plat/src/crash.rs index 988d1da..612a211 100644 --- a/platform/dr-plat/src/crash.rs +++ b/platform/dr-plat/src/crash.rs @@ -98,7 +98,8 @@ pub fn set_state_dir(dir: PathBuf) { /// Where this application keeps state that is neither configuration nor cache. /// -/// `$XDG_STATE_HOME/darkroom`, falling back to `~/.local/state/darkroom`. +/// `$XDG_STATE_HOME/darkroom`, falling back to `~/.local/state/darkroom` — +/// `~/Library/Logs/darkroom` on macOS (`dirs`). /// State rather than cache because a crash record must survive the sweep that /// a cache directory exists to permit, and rather than config because it is /// not something the user edits. diff --git a/platform/dr-plat/src/diagnostics.rs b/platform/dr-plat/src/diagnostics.rs index cef31a3..5ec5444 100644 --- a/platform/dr-plat/src/diagnostics.rs +++ b/platform/dr-plat/src/diagnostics.rs @@ -46,6 +46,8 @@ //! //! * Linux: `$XDG_STATE_HOME/darkroom/darkroom.log`, else //! `~/.local/state/darkroom/darkroom.log`. +//! * macOS: `$XDG_STATE_HOME/darkroom/darkroom.log`, else +//! `~/Library/Logs/darkroom/darkroom.log`, where Console.app lists it. //! * Android: `/sdcard/Android/data/paris.tourolle.darkroom/files/darkroom.log`, //! which `adb pull` reads from an ordinary release build. See //! [`crate::state`] for why not the internal directory, and diff --git a/platform/dr-plat/src/dirs.rs b/platform/dr-plat/src/dirs.rs index d39639e..5ebe17e 100644 --- a/platform/dr-plat/src/dirs.rs +++ b/platform/dr-plat/src/dirs.rs @@ -17,6 +17,11 @@ //! | Unix default | `~/.config` | `~/.local/share` | `~/.local/state` | //! | Windows | `%APPDATA%` | `%LOCALAPPDATA%` | `%LOCALAPPDATA%`, then `state` | //! | Windows default | `%USERPROFILE%\AppData\Roaming` | `…\AppData\Local` | `…\AppData\Local` | +//! | macOS default | `~/.config` | `~/.local/share` | `~/Library/Logs` | +//! +//! macOS follows the Unix rules except for the one directory a user is asked +//! to find by hand: the log. Finder hides `~/.local`, and `~/Library/Logs` +//! is where Console.app and a Mac user already look (docs/dev/macos.md). //! //! then `darkroom` under each. Config roams on Windows and the rest does not, //! which is the same split XDG makes between config and everything else, and @@ -100,11 +105,18 @@ fn resolve(kind: Base, env: impl Fn(&str) -> Option) -> PathBuf { } } +/// Where state goes under `$HOME` when `XDG_STATE_HOME` does not say. +const STATE_UNDER_HOME: &str = if cfg!(target_os = "macos") { + "Library/Logs" +} else { + ".local/state" +}; + fn xdg_base(kind: Base, env: &impl Fn(&str) -> Option) -> Option { let (var, under_home) = match kind { Base::Config => ("XDG_CONFIG_HOME", ".config"), Base::Data => ("XDG_DATA_HOME", ".local/share"), - Base::State => ("XDG_STATE_HOME", ".local/state"), + Base::State => ("XDG_STATE_HOME", STATE_UNDER_HOME), }; absolute(env(var)).or_else(|| absolute(env("HOME")).map(|h| h.join(under_home))) } @@ -150,7 +162,7 @@ mod tests { ); assert_eq!( xdg_base(Base::State, &e), - Some(PathBuf::from("/home/someone/.local/state")) + Some(PathBuf::from("/home/someone").join(STATE_UNDER_HOME)) ); } @@ -162,7 +174,7 @@ mod tests { let e = env(&[("XDG_STATE_HOME", "state"), ("HOME", "/home/someone")]); assert_eq!( xdg_base(Base::State, &e), - Some(PathBuf::from("/home/someone/.local/state")) + Some(PathBuf::from("/home/someone").join(STATE_UNDER_HOME)) ); assert_eq!(xdg_base(Base::State, &env(&[("HOME", "")])), None); }