Since 2.10.0 the whole app sits behind one all-or-nothing initialization gate, and that gate discarded the only evidence of its own failure. It caught the error, logged nothing but `error.runtimeType`, rendered an icon plus the word "Error" plus Retry, and never reported the error because catching it kept the crash reporter from ever seeing it. There is no log file on any platform, the buffer is in memory only, a double-clicked Windows release build has no console, and the log viewer lives in Settings, behind the gate that just failed. #1732 is the result: a Windows 11 user whose app will not boot and who cannot produce a single byte of diagnostic detail. The gate now names its phases. Each step is wrapped so a throw carries the phase it came from, replacing a `Future.wait` that discarded every error but the first and could not attribute it to any of four concurrent steps. The failure screen renders the phase, the exception type, the message and an expandable stack, plus copy and upload actions that reuse the existing log-relay flow. The record is persisted next to the database so the next successful launch can surface it in Settings > Logs, and it is reported to the crash reporter explicitly. Only preferences and the database still gate the launch. Window chrome, locale, crash-reporting init, TV/performance detection, the image-cache budget and download storage are best-effort and time-bounded, so a stalled platform thread degrades instead of holding the splash forever. Sentry no longer receives the startup work as its `appRunner`: that made a startup failure indistinguishable from a Sentry failure, and the guard would then have re-run migrations and the database open a second time. The two remaining fatal steps become recoverable. Preference reads tolerate a value whose stored type no longer matches, dropping the key and defaulting instead of failing the boot. A store that cannot be parsed is detected before either desktop plugin backend can memoise it, which is what makes an in-process repair possible at all. Repair is never automatic: it states what it will cost, salvages the credential-vault key and every tracker and Seerr session it can validate out of the damaged bytes, reseeds them, and moves the original aside rather than deleting it. Servers and profiles survive a salvaged key because their tokens are ciphertext in the database; tracker and Seerr sessions are plaintext preference entries, so the copy says they may still need reconnecting. Nothing derived from the store reaches a diagnostic. `FormatException` prints an excerpt of whatever it failed to parse, and during startup that document holds the vault key, refresh tokens and session cookies while the redaction manager still has nothing registered, so the wrapper keeps only the cause's type and offset and the record is an allowlist of already-redacted fields. The quarantined copy is labelled as containing credentials, is never offered for upload, and can be deleted from the dialog. Also self-heals orphaned WAL/SHM sidecars on desktop rather than only tvOS, makes every `createTable` migration step idempotent, keeps MSVC link by-products out of the Windows bundle, and asserts bundle contents in CI. Refs #1732
200 lines
7.6 KiB
CMake
200 lines
7.6 KiB
CMake
# Project-level configuration.
|
|
cmake_minimum_required(VERSION 3.14)
|
|
project(plezy LANGUAGES CXX)
|
|
|
|
# Download and extract mpv-dev (architecture-dependent)
|
|
set(MPV_VERSION "20251228")
|
|
set(MPV_GIT_HASH "a58dd8a")
|
|
|
|
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64")
|
|
# ARM64: use file(DOWNLOAD) + 7z extraction (CMake's built-in libarchive
|
|
# can't handle LZMA2 on ARM64)
|
|
set(MPV_FILENAME "mpv-dev-aarch64-${MPV_VERSION}-git-${MPV_GIT_HASH}.7z")
|
|
set(MPV_URL "https://sourceforge.net/projects/mpv-player-windows/files/libmpv/${MPV_FILENAME}/download")
|
|
set(MPV_DOWNLOAD_DIR "${CMAKE_BINARY_DIR}/mpv-dev-arm64")
|
|
set(MPV_ARCHIVE "${MPV_DOWNLOAD_DIR}/${MPV_FILENAME}")
|
|
|
|
if(NOT EXISTS "${MPV_DOWNLOAD_DIR}/libmpv-2.dll")
|
|
message(STATUS "Downloading MPV for ARM64...")
|
|
file(DOWNLOAD "${MPV_URL}" "${MPV_ARCHIVE}" SHOW_PROGRESS STATUS MPV_DL_STATUS)
|
|
list(GET MPV_DL_STATUS 0 MPV_DL_RESULT)
|
|
if(NOT MPV_DL_RESULT EQUAL 0)
|
|
message(FATAL_ERROR "Failed to download MPV: ${MPV_DL_STATUS}")
|
|
endif()
|
|
|
|
find_program(7Z_EXECUTABLE 7z REQUIRED HINTS "C:/Program Files/7-Zip")
|
|
message(STATUS "Extracting MPV with ${7Z_EXECUTABLE}...")
|
|
execute_process(
|
|
COMMAND "${7Z_EXECUTABLE}" x "${MPV_ARCHIVE}" "-o${MPV_DOWNLOAD_DIR}" -y
|
|
RESULT_VARIABLE MPV_EXTRACT_RESULT
|
|
)
|
|
if(NOT MPV_EXTRACT_RESULT EQUAL 0)
|
|
message(FATAL_ERROR "Failed to extract MPV archive")
|
|
endif()
|
|
file(REMOVE "${MPV_ARCHIVE}")
|
|
endif()
|
|
|
|
set(MPV_INCLUDE_DIR "${MPV_DOWNLOAD_DIR}/include")
|
|
set(MPV_LIB_DIR "${MPV_DOWNLOAD_DIR}")
|
|
else()
|
|
# x64 (AMD64): use FetchContent (existing behavior)
|
|
include(FetchContent)
|
|
FetchContent_Declare(
|
|
mpv_dev
|
|
URL https://sourceforge.net/projects/mpv-player-windows/files/libmpv/mpv-dev-x86_64-${MPV_VERSION}-git-${MPV_GIT_HASH}.7z/download
|
|
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
|
|
)
|
|
FetchContent_MakeAvailable(mpv_dev)
|
|
|
|
set(MPV_INCLUDE_DIR "${mpv_dev_SOURCE_DIR}/include")
|
|
set(MPV_LIB_DIR "${mpv_dev_SOURCE_DIR}")
|
|
endif()
|
|
|
|
# Fetch simdutf for SIMD-accelerated UTF-8 validation.
|
|
# mpv strings are not guaranteed to be valid UTF-8; invalid bytes sent through
|
|
# Flutter's StandardMessageCodec cause FormatException crashes.
|
|
include(FetchContent)
|
|
FetchContent_Declare(
|
|
simdutf
|
|
URL https://github.com/simdutf/simdutf/releases/download/v6.4.2/singleheader.zip
|
|
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
|
|
)
|
|
FetchContent_MakeAvailable(simdutf)
|
|
|
|
# The name of the executable created for the application. Change this to change
|
|
# the on-disk name of your application.
|
|
set(BINARY_NAME "plezy")
|
|
|
|
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
|
|
# versions of CMake.
|
|
cmake_policy(VERSION 3.14...3.25)
|
|
|
|
# Define build configuration option.
|
|
get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
|
if(IS_MULTICONFIG)
|
|
set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
|
|
CACHE STRING "" FORCE)
|
|
else()
|
|
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
|
set(CMAKE_BUILD_TYPE "Debug" CACHE
|
|
STRING "Flutter build mode" FORCE)
|
|
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
|
|
"Debug" "Profile" "Release")
|
|
endif()
|
|
endif()
|
|
# Define settings for the Profile build mode.
|
|
set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
|
|
set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
|
|
set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}")
|
|
set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
|
|
|
|
# Use Unicode for all projects.
|
|
add_definitions(-DUNICODE -D_UNICODE)
|
|
|
|
# Compilation settings that should be applied to most targets.
|
|
#
|
|
# Be cautious about adding new options here, as plugins use this function by
|
|
# default. In most cases, you should add new options to specific targets instead
|
|
# of modifying this function.
|
|
function(APPLY_STANDARD_SETTINGS TARGET)
|
|
target_compile_features(${TARGET} PUBLIC cxx_std_17)
|
|
target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100")
|
|
target_compile_options(${TARGET} PRIVATE /EHsc)
|
|
target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0")
|
|
target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>")
|
|
endfunction()
|
|
|
|
# Flutter library and tool build rules.
|
|
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
|
|
add_subdirectory(${FLUTTER_MANAGED_DIR})
|
|
|
|
# Application build; see runner/CMakeLists.txt.
|
|
add_subdirectory("runner")
|
|
|
|
# Keep MSVC link by-products out of the runnable bundle directory. CI uploads
|
|
# the executable output directory directly, so import and static libraries
|
|
# emitted there would otherwise be packaged with the application.
|
|
set_target_properties(
|
|
${BINARY_NAME}
|
|
simdutf
|
|
PROPERTIES
|
|
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/link-artifacts/$<CONFIG>"
|
|
)
|
|
|
|
|
|
# Sentry native crash capture: use the in-process handler instead of
|
|
# crashpad. Crashpad uploads minidumps straight to the DSN's /minidump
|
|
# endpoint, which our self-hosted tracker does not implement — every native
|
|
# Windows crash (e.g. faults inside libmpv threads) was silently dropped.
|
|
# The inproc handler stackwalks at crash time and reports through the
|
|
# regular envelope endpoint on next launch. sentry-native.cmake gives this
|
|
# environment variable highest precedence over the plugin's forced default.
|
|
set(ENV{SENTRY_NATIVE_BACKEND} "inproc")
|
|
|
|
# Generated plugin build rules, which manage building the plugins and adding
|
|
# them to the application.
|
|
include(flutter/generated_plugins.cmake)
|
|
|
|
if(TARGET os_media_controls_plugin)
|
|
# MSVC 14.51 makes C++/WinRT's experimental coroutine include a hard error.
|
|
target_compile_definitions(
|
|
os_media_controls_plugin
|
|
PRIVATE _SILENCE_EXPERIMENTAL_COROUTINE_DEPRECATION_WARNINGS
|
|
)
|
|
endif()
|
|
|
|
|
|
# === Installation ===
|
|
# Support files are copied into place next to the executable, so that it can
|
|
# run in place. This is done instead of making a separate bundle (as on Linux)
|
|
# so that building and running from within Visual Studio will work.
|
|
set(BUILD_BUNDLE_DIR "$<TARGET_FILE_DIR:${BINARY_NAME}>")
|
|
# Make the "install" step default, as it's required to run.
|
|
set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)
|
|
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
|
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
|
|
endif()
|
|
|
|
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
|
|
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")
|
|
|
|
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
|
|
COMPONENT Runtime)
|
|
|
|
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
|
|
COMPONENT Runtime)
|
|
|
|
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
|
COMPONENT Runtime)
|
|
|
|
if(PLUGIN_BUNDLED_LIBRARIES)
|
|
install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
|
|
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
|
COMPONENT Runtime)
|
|
endif()
|
|
|
|
# Copy the native assets provided by the build.dart from all packages.
|
|
set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/")
|
|
install(DIRECTORY "${NATIVE_ASSETS_DIR}"
|
|
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
|
COMPONENT Runtime)
|
|
|
|
# Fully re-copy the assets directory on each build to avoid having stale files
|
|
# from a previous install.
|
|
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
|
|
install(CODE "
|
|
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
|
|
" COMPONENT Runtime)
|
|
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
|
|
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
|
|
|
|
# Install the AOT library on non-Debug builds only.
|
|
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
|
|
CONFIGURATIONS Profile;Release
|
|
COMPONENT Runtime)
|
|
|
|
# Install mpv DLL
|
|
install(FILES "${MPV_LIB_DIR}/libmpv-2.dll"
|
|
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
|
COMPONENT Runtime)
|