diff --git a/.github/ISSUE_TEMPLATE/crash.yml b/.github/ISSUE_TEMPLATE/crash.yml index 13dcd33d..c8b4804e 100644 --- a/.github/ISSUE_TEMPLATE/crash.yml +++ b/.github/ISSUE_TEMPLATE/crash.yml @@ -33,7 +33,7 @@ body: attributes: label: Minidump description: | - Attach `minidump.dmp` here. If it is too big to upload, compress it. + Attach `minidump.dmp.log` here. If it is too big to upload, compress it. You may skip this step if quickshell crashed while processing a password or other sensitive information. If you skipped it write why instead. @@ -44,7 +44,7 @@ body: attributes: label: Log file description: | - Attach `log.qslog` here. If it is too big to upload, compress it. + Attach `log.qslog.log` here. If it is too big to upload, compress it. You can preview the log if you'd like using `quickshell read-log `. validations: @@ -70,3 +70,13 @@ body: in the crash reporter. 2. Once it loads, type `bt -full` (then enter) 3. Copy the output and attach it as a file or in a spoiler. + - type: textarea + id: exe + attributes: + label: Executable + description: | + If the crash folder contains a executable.txt file, upload it here. If not you can ignore this field. + If it is too big to upload, compress it. + + Note: executable.txt is the quickshell binary. It has a .txt extension due to github's limitations on + filetypes. diff --git a/BUILD.md b/BUILD.md index f32a2335..4650d1ff 100644 --- a/BUILD.md +++ b/BUILD.md @@ -2,6 +2,29 @@ Instructions for building from source and distro packagers. We highly recommend distro packagers read through this page fully. +## Packaging +If you are packaging quickshell for official or unofficial distribution channels, +such as a distro package repository, user repository, or other shared build location, +please set the following CMake flags. + +`-DDISTRIBUTOR="your distribution platform"` + +Please make this descriptive enough to identify your specific package, for example: +- `Official Nix Flake` +- `AUR (quickshell-git)` +- `Nixpkgs` +- `Fedora COPR (errornointernet/quickshell)` + +`-DDISTRIBUTOR_DEBUGINFO_AVAILABLE=YES/NO` + +If we can retrieve binaries and debug information for the package without actually running your +distribution (e.g. from an website), and you would like to strip the binary, please set this to `YES`. + +If we cannot retrieve debug information, please set this to `NO` and +**ensure you aren't distributing stripped (non debuggable) binaries**. + +In both cases you should build with `-DCMAKE_BUILD_TYPE=RelWithDebInfo` (then split or keep the debuginfo). + ## Dependencies Quickshell has a set of base dependencies you will always need, names vary by distro: @@ -18,12 +41,6 @@ At least Qt 6.6 is required. All features are enabled by default and some have their own dependencies. -### QML Library -If you wish to use a linter or similar tools, you will need the QML Modules for it -to pick up on the types. - -To disable: `-DINSTALL_QML_LIB=OFF` - ### Crash Reporter The crash reporter catches crashes, restarts quickshell when it crashes, and collects useful crash information in one place. Leaving this enabled will @@ -169,9 +186,6 @@ or quickshell will fail to build. Additionally, note that clang builds much faster than gcc if you care. -You may disable debug information but it's only a couple megabytes and is extremely helpful -for helping us fix problems when they do arise. - #### Building ```sh $ cmake --build build diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fe5387e..c0b7e574 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,58 +5,64 @@ set(QT_MIN_VERSION "6.6.0") set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) -option(BUILD_TESTING "Build tests" OFF) -option(ASAN "Enable ASAN" OFF) # note: better output with gcc than clang -option(FRAME_POINTERS "Always keep frame pointers" ${ASAN}) +set(QS_BUILD_OPTIONS "") -option(INSTALL_QML_LIB "Installing the QML lib" ON) -option(CRASH_REPORTER "Enable the crash reporter" ON) -option(USE_JEMALLOC "Use jemalloc over the system malloc implementation" ON) -option(SOCKETS "Enable unix socket support" ON) -option(WAYLAND "Enable wayland support" ON) -option(WAYLAND_WLR_LAYERSHELL "Support the zwlr_layer_shell_v1 wayland protocol" ON) -option(WAYLAND_SESSION_LOCK "Support the ext_session_lock_v1 wayland protocol" ON) -option(WAYLAND_TOPLEVEL_MANAGEMENT "Support the zwlr_foreign_toplevel_management_v1 wayland protocol" ON) -option(X11 "Enable X11 support" ON) -option(HYPRLAND "Support hyprland specific features" ON) -option(HYPRLAND_IPC "Hyprland IPC" ON) -option(HYPRLAND_GLOBAL_SHORTCUTS "Hyprland Global Shortcuts" ON) -option(HYPRLAND_FOCUS_GRAB "Hyprland Focus Grabbing" ON) -option(SERVICE_STATUS_NOTIFIER "StatusNotifierItem service" ON) -option(SERVICE_PIPEWIRE "PipeWire service" ON) -option(SERVICE_MPRIS "Mpris service" ON) -option(SERVICE_PAM "Pam service" ON) -option(SERVICE_GREETD "Greet service" ON) -option(SERVICE_UPOWER "UPower service" ON) -option(SERVICE_NOTIFICATIONS "Notification server" ON) +function(boption VAR NAME DEFAULT) + cmake_parse_arguments(PARSE_ARGV 3 arg "" "REQUIRES" "") + + option(${VAR} ${NAME} ${DEFAULT}) + + set(STATUS "${VAR}_status") + set(EFFECTIVE "${VAR}_effective") + set(${STATUS} ${${VAR}}) + set(${EFFECTIVE} ${${VAR}}) + + if (${${VAR}} AND DEFINED arg_REQUIRES) + set(REQUIRED_EFFECTIVE "${arg_REQUIRES}_effective") + if (NOT ${${REQUIRED_EFFECTIVE}}) + set(${STATUS} "OFF (Requires ${arg_REQUIRES})") + set(${EFFECTIVE} OFF) + endif() + endif() + + set(${EFFECTIVE} "${${EFFECTIVE}}" PARENT_SCOPE) + + message(STATUS " ${NAME}: ${${STATUS}}") + + string(APPEND QS_BUILD_OPTIONS "\\n ${NAME}: ${${STATUS}}") + set(QS_BUILD_OPTIONS "${QS_BUILD_OPTIONS}" PARENT_SCOPE) +endfunction() + +set(DISTRIBUTOR "Unset" CACHE STRING "Distributor") +string(APPEND QS_BUILD_OPTIONS " Distributor: ${DISTRIBUTOR}") message(STATUS "Quickshell configuration") -message(STATUS " QML lib installation: ${INSTALL_QML_LIB}") -message(STATUS " Crash reporter: ${CRASH_REPORTER}") -message(STATUS " Jemalloc: ${USE_JEMALLOC}") -message(STATUS " Build tests: ${BUILD_TESTING}") -message(STATUS " Sockets: ${SOCKETS}") -message(STATUS " Wayland: ${WAYLAND}") -if (WAYLAND) - message(STATUS " Wlroots Layershell: ${WAYLAND_WLR_LAYERSHELL}") - message(STATUS " Session Lock: ${WAYLAND_SESSION_LOCK}") - message(STATUS " Toplevel Management: ${WAYLAND_TOPLEVEL_MANAGEMENT}") -endif () -message(STATUS " X11: ${X11}") -message(STATUS " Services") -message(STATUS " StatusNotifier: ${SERVICE_STATUS_NOTIFIER}") -message(STATUS " PipeWire: ${SERVICE_PIPEWIRE}") -message(STATUS " Mpris: ${SERVICE_MPRIS}") -message(STATUS " Pam: ${SERVICE_PAM}") -message(STATUS " Greetd: ${SERVICE_GREETD}") -message(STATUS " UPower: ${SERVICE_UPOWER}") -message(STATUS " Notifications: ${SERVICE_NOTIFICATIONS}") -message(STATUS " Hyprland: ${HYPRLAND}") -if (HYPRLAND) - message(STATUS " IPC: ${HYPRLAND_IPC}") - message(STATUS " Focus Grabbing: ${HYPRLAND_FOCUS_GRAB}") - message(STATUS " Global Shortcuts: ${HYPRLAND_GLOBAL_SHORTCUTS}") -endif() +message(STATUS " Distributor: ${DISTRIBUTOR}") +boption(DISTRIBUTOR_DEBUGINFO_AVAILABLE "Distributor provided debuginfo" NO) +boption(NO_PCH "Disable precompild headers (dev)" OFF) +boption(BUILD_TESTING "Build tests (dev)" OFF) +boption(ASAN "ASAN (dev)" OFF) # note: better output with gcc than clang +boption(FRAME_POINTERS "Keep Frame Pointers (dev)" ${ASAN}) + +boption(CRASH_REPORTER "Crash Handling" ON) +boption(USE_JEMALLOC "Use jemalloc" ON) +boption(SOCKETS "Unix Sockets" ON) +boption(WAYLAND "Wayland" ON) +boption(WAYLAND_WLR_LAYERSHELL " Wlroots Layer-Shell" ON REQUIRES WAYLAND) +boption(WAYLAND_SESSION_LOCK " Session Lock" ON REQUIRES WAYLAND) +boption(WAYLAND_TOPLEVEL_MANAGEMENT " Foreign Toplevel Management" ON REQUIRES WAYLAND) +boption(HYPRLAND " Hyprland" ON REQUIRES WAYLAND) +boption(HYPRLAND_IPC " Hyprland IPC" ON REQUIRES HYPRLAND) +boption(HYPRLAND_GLOBAL_SHORTCUTS " Hyprland Global Shortcuts" ON REQUIRES HYPRLAND) +boption(HYPRLAND_FOCUS_GRAB " Hyprland Focus Grabbing" ON REQUIRES HYPRLAND) +boption(X11 "X11" ON) +boption(SERVICE_STATUS_NOTIFIER "System Tray" ON) +boption(SERVICE_PIPEWIRE "PipeWire" ON) +boption(SERVICE_MPRIS "Mpris" ON) +boption(SERVICE_PAM "Pam" ON) +boption(SERVICE_GREETD "Greetd" ON) +boption(SERVICE_UPOWER "UPower" ON) +boption(SERVICE_NOTIFICATIONS "Notifications" ON) if (NOT DEFINED GIT_REVISION) execute_process( @@ -157,13 +163,11 @@ if (USE_JEMALLOC) target_link_libraries(quickshell PRIVATE ${JEMALLOC_LIBRARIES}) endif() -if (INSTALL_QML_LIB) - install( - DIRECTORY ${CMAKE_BINARY_DIR}/qml_modules/ - DESTINATION ${CMAKE_INSTALL_LIBDIR}/qt-6/qml - FILES_MATCHING PATTERN "*" - ) -endif() +install( + DIRECTORY ${CMAKE_BINARY_DIR}/qml_modules/ + DESTINATION ${CMAKE_INSTALL_LIBDIR}/qt-6/qml + FILES_MATCHING PATTERN "*" +) install(CODE " execute_process( diff --git a/default.nix b/default.nix index 3016a313..88c0e3b5 100644 --- a/default.nix +++ b/default.nix @@ -37,7 +37,6 @@ withPipewire ? true, withPam ? true, withHyprland ? true, - withQMLLib ? true, }: buildStdenv.mkDerivation { pname = "quickshell${lib.optionalString debug "-debug"}"; version = "0.1.0"; @@ -71,6 +70,8 @@ cmakeBuildType = if debug then "Debug" else "RelWithDebInfo"; cmakeFlags = [ + (lib.cmakeFeature "DISTRIBUTOR" "Official-Nix-Flake") + (lib.cmakeBool "DISTRIBUTOR_DEBUGINFO_AVAILABLE" true) (lib.cmakeFeature "GIT_REVISION" gitRev) (lib.cmakeBool "CRASH_REPORTER" withCrashReporter) (lib.cmakeBool "USE_JEMALLOC" withJemalloc) @@ -78,7 +79,6 @@ (lib.cmakeBool "SERVICE_PIPEWIRE" withPipewire) (lib.cmakeBool "SERVICE_PAM" withPam) (lib.cmakeBool "HYPRLAND" withHyprland) - (lib.cmakeBool "INSTALL_QML_LIB" withQMLLib) ]; # How to get debuginfo in gdb from a release build: diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 75c16537..811965e7 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -52,8 +52,16 @@ else() set(CRASH_REPORTER_DEF 0) endif() +if (DISTRIBUTOR_DEBUGINFO_AVAILABLE) + set(DEBUGINFO_AVAILABLE 1) +else() + set(DEBUGINFO_AVAILABLE 0) +endif() + add_library(quickshell-build INTERFACE) -configure_file(build.hpp.in build.hpp) + +configure_file(build.hpp.in build.hpp @ONLY ESCAPE_QUOTES) + target_include_directories(quickshell-build INTERFACE ${CMAKE_CURRENT_BINARY_DIR}) target_link_libraries(quickshell-core PRIVATE quickshell-build) diff --git a/src/core/build.hpp.in b/src/core/build.hpp.in index ecf5dfc4..075abd17 100644 --- a/src/core/build.hpp.in +++ b/src/core/build.hpp.in @@ -2,5 +2,11 @@ // NOLINTBEGIN #define GIT_REVISION "@GIT_REVISION@" +#define DISTRIBUTOR "@DISTRIBUTOR@" +#define DISTRIBUTOR_DEBUGINFO_AVAILABLE @DEBUGINFO_AVAILABLE@ #define CRASH_REPORTER @CRASH_REPORTER_DEF@ +#define BUILD_TYPE "@CMAKE_BUILD_TYPE@" +#define COMPILER "@CMAKE_CXX_COMPILER_ID@ (@CMAKE_CXX_COMPILER_VERSION@)" +#define COMPILE_FLAGS "@CMAKE_CXX_FLAGS@" +#define BUILD_CONFIGURATION "@QS_BUILD_OPTIONS@" // NOLINTEND diff --git a/src/core/main.cpp b/src/core/main.cpp index 57bdfb85..287af3b1 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,7 @@ #include #include #include +#include #include #include "../io/ipccomm.hpp" @@ -425,7 +427,21 @@ int runCommand(int argc, char** argv, QCoreApplication* coreApplication) { } if (state.misc.printVersion) { - qCInfo(logBare).noquote() << "quickshell pre-release, revision" << GIT_REVISION; + qCInfo(logBare).noquote().nospace() << "quickshell pre-release, revision " << GIT_REVISION + << ", distributed by: " << DISTRIBUTOR; + + if (state.log.verbosity > 1) { + qCInfo(logBare).noquote() << "\nBuildtime Qt Version:" << QT_VERSION_STR; + qCInfo(logBare).noquote() << "Runtime Qt Version:" << qVersion(); + qCInfo(logBare).noquote() << "Compiler:" << COMPILER; + qCInfo(logBare).noquote() << "Compile Flags:" << COMPILE_FLAGS; + } + + if (state.log.verbosity > 0) { + qCInfo(logBare).noquote() << "\nBuild Type:" << BUILD_TYPE; + qCInfo(logBare).noquote() << "Build configuration:"; + qCInfo(logBare).noquote().nospace() << BUILD_CONFIGURATION; + } } else if (*state.subcommand.log) { return readLogFile(state); } else if (*state.subcommand.list) { diff --git a/src/crash/interface.cpp b/src/crash/interface.cpp index 3d296580..7691b260 100644 --- a/src/crash/interface.cpp +++ b/src/crash/interface.cpp @@ -54,7 +54,7 @@ CrashReporterGui::CrashReporterGui(QString reportFolder, int pid) mainLayout->addWidget(new ReportLabel( "Github:", - "https://github.com/outfoxxed/quickshell/issues/new?template=crash.yml", + "https://github.com/quickshell-mirror/quickshell/issues/new?template=crash.yml", this )); diff --git a/src/crash/main.cpp b/src/crash/main.cpp index 9f56d894..08c38892 100644 --- a/src/crash/main.cpp +++ b/src/crash/main.cpp @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include @@ -111,39 +113,53 @@ void recordCrashInfo(const QDir& crashDir, const InstanceInfo& instance) { auto logFd = qEnvironmentVariable("__QUICKSHELL_CRASH_LOG_FD").toInt(); qCDebug(logCrashReporter) << "Saving minidump from fd" << dumpFd; - auto dumpDupStatus = tryDup(dumpFd, crashDir.filePath("minidump.dmp")); + auto dumpDupStatus = tryDup(dumpFd, crashDir.filePath("minidump.dmp.log")); if (dumpDupStatus != 0) { qCCritical(logCrashReporter) << "Failed to write minidump:" << dumpDupStatus; } qCDebug(logCrashReporter) << "Saving log from fd" << logFd; - auto logDupStatus = tryDup(logFd, crashDir.filePath("log.qslog")); + auto logDupStatus = tryDup(logFd, crashDir.filePath("log.qslog.log")); if (logDupStatus != 0) { qCCritical(logCrashReporter) << "Failed to save log:" << logDupStatus; } + auto copyBinStatus = 0; + if (!DISTRIBUTOR_DEBUGINFO_AVAILABLE) { + qCDebug(logCrashReporter) << "Copying binary to crash folder"; + if (!QFile(QCoreApplication::applicationFilePath()).copy(crashDir.filePath("executable.txt"))) { + copyBinStatus = 1; + qCCritical(logCrashReporter) << "Failed to copy binary."; + } + } + { auto extraInfoFile = QFile(crashDir.filePath("info.txt")); if (!extraInfoFile.open(QFile::WriteOnly)) { qCCritical(logCrashReporter) << "Failed to open crash info file for writing."; } else { auto stream = QTextStream(&extraInfoFile); - stream << "===== Quickshell Crash =====\n"; + stream << "===== Build Information =====\n"; stream << "Git Revision: " << GIT_REVISION << '\n'; + stream << "Buildtime Qt Version: " << QT_VERSION_STR << "\n"; + stream << "Build Type: " << BUILD_TYPE << '\n'; + stream << "Compiler: " << COMPILER << '\n'; + stream << "Complie Flags: " << COMPILE_FLAGS << "\n\n"; + stream << "Build configuration:\n" << BUILD_CONFIGURATION << "\n"; + + stream << "\n===== Runtime Information =====\n"; + stream << "Runtime Qt Version: " << qVersion() << '\n'; stream << "Crashed process ID: " << crashProc << '\n'; stream << "Run ID: " << instance.instanceId << '\n'; - - stream << "\n===== Shell Information =====\n"; stream << "Shell ID: " << instance.shellId << '\n'; stream << "Config Path: " << instance.configPath << '\n'; stream << "\n===== Report Integrity =====\n"; stream << "Minidump save status: " << dumpDupStatus << '\n'; stream << "Log save status: " << logDupStatus << '\n'; + stream << "Binary copy status: " << copyBinStatus << '\n'; - stream << "\n===== System Information =====\n"; - stream << "Qt Version: " << QT_VERSION_STR << "\n\n"; - + stream << "\n===== System Information =====\n\n"; stream << "/etc/os-release:"; auto osReleaseFile = QFile("/etc/os-release"); if (osReleaseFile.open(QFile::ReadOnly)) { @@ -156,7 +172,7 @@ void recordCrashInfo(const QDir& crashDir, const InstanceInfo& instance) { stream << "/etc/lsb-release:"; auto lsbReleaseFile = QFile("/etc/lsb-release"); if (lsbReleaseFile.open(QFile::ReadOnly)) { - stream << '\n' << lsbReleaseFile.readAll() << '\n'; + stream << '\n' << lsbReleaseFile.readAll(); lsbReleaseFile.close(); } else { stream << "FAILED TO OPEN\n";