From 06e99e29902cc5ce3b7f7ba83e0b9aaf5f32755b Mon Sep 17 00:00:00 2001 From: Seth Flynn Date: Wed, 17 Dec 2025 04:53:39 -0500 Subject: [PATCH 1/4] build(linux): use `sharun` for appimage bundling This should fix issues with OpenGL, as well as help as avoid using some annoying (and fragile) hacks to locate our actual binary/other resources Signed-off-by: Seth Flynn --- .github/actions/package/linux/action.yml | 22 ++++++++++++++----- .../setup-dependencies/linux/action.yml | 14 ++++++------ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/.github/actions/package/linux/action.yml b/.github/actions/package/linux/action.yml index 3cc49fa02..5233f273b 100644 --- a/.github/actions/package/linux/action.yml +++ b/.github/actions/package/linux/action.yml @@ -58,9 +58,7 @@ runs: GPG_PRIVATE_KEY: ${{ inputs.gpg-private-key }} run: | - cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_APPIMAGE_DIR }}/usr - - cp ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/metainfo/org.prismlauncher.PrismLauncher.{metainfo,appdata}.xml + cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_APPIMAGE_DIR }} if [ '${{ inputs.gpg-private-key-id }}' != '' ]; then echo "$GPG_PRIVATE_KEY" > privkey.asc @@ -70,8 +68,22 @@ runs: echo ":warning: Skipped code signing for Linux AppImage, as gpg key was not present." >> $GITHUB_STEP_SUMMARY fi - appimagetool -s deploy "$INSTALL_APPIMAGE_DIR"/usr/share/applications/*.desktop - cp ~/bin/AppImageUpdate.AppImage "$INSTALL_APPIMAGE_DIR"/usr/bin/ + sharun lib4bin \ + --hard-links \ + --with-hooks \ + --dst-dir "$INSTALL_APPIMAGE_DIR" \ + "$INSTALL_APPIMAGE_DIR"/bin/* "$QT_PLUGIN_PATH"/*/*.so + + cp ~/bin/AppImageUpdate.AppImage "$INSTALL_APPIMAGE_DIR"/bin/ + # FIXME(@getchoo): gamemode doesn't seem to be very portable with DBus. Find a way to make it work! + find "$INSTALL_APPIMAGE_DIR" -name '*gamemode*' -exec rm {} + + + ln -s org.prismlauncher.PrismLauncher.metainfo.xml "$INSTALL_APPIMAGE_DIR"/share/metainfo/org.prismlauncher.PrismLauncher.appdata.xml + ln -s share/applications/org.prismlauncher.PrismLauncher.desktop "$INSTALL_APPIMAGE_DIR" + ln -s share/icons/hicolor/256x256/apps/org.prismlauncher.PrismLauncher.png "$INSTALL_APPIMAGE_DIR" + mv "$INSTALL_APPIMAGE_DIR"/{sharun,AppRun} + ls -la "$INSTALL_APPIMAGE_DIR" + # FIXME(@getchoo): Validate AppStream information when https://github.com/probonopd/go-appimage/pull/379 is merged mkappimage \ --no-appstream \ diff --git a/.github/actions/setup-dependencies/linux/action.yml b/.github/actions/setup-dependencies/linux/action.yml index 67a1a9826..fe75e23d0 100644 --- a/.github/actions/setup-dependencies/linux/action.yml +++ b/.github/actions/setup-dependencies/linux/action.yml @@ -56,19 +56,19 @@ runs: ;; esac - gh release download continuous \ - --repo probonopd/go-appimage \ - --pattern "appimagetool-*-$APPIMAGE_ARCH.AppImage" \ - --output ~/bin/appimagetool + gh release download \ + --repo VHSgunzo/sharun \ + --pattern "sharun-$APPIMAGE_ARCH-aio" \ + --output ~/bin/sharun + gh release download continuous \ --repo probonopd/go-appimage \ --pattern "mkappimage-*-$APPIMAGE_ARCH.AppImage" \ --output ~/bin/mkappimage - chmod +x ~/bin/appimagetool ~/bin/mkappimage - echo "$HOME/bin" >> "$GITHUB_PATH" gh release download \ --repo AppImageCommunity/AppImageUpdate \ --pattern "AppImageUpdate-$APPIMAGE_ARCH.AppImage" \ --output ~/bin/AppImageUpdate.AppImage - chmod +x ~/bin/AppImageUpdate.AppImage + chmod +x ~/bin/* + echo "$HOME/bin" >> "$GITHUB_PATH" From 1d8bf82ef82660b7a14dfc1c9a5c84ea68c48055 Mon Sep 17 00:00:00 2001 From: Seth Flynn Date: Wed, 17 Dec 2025 04:56:32 -0500 Subject: [PATCH 2/4] revert: "fix(appimage): launch external processes with bundled linker" Refs: c305ed4 Signed-off-by: Seth Flynn --- launcher/DesktopServices.cpp | 10 ---- launcher/DesktopServices.h | 5 -- launcher/FileSystem.cpp | 29 ---------- launcher/FileSystem.h | 11 ---- launcher/updater/PrismExternalUpdater.cpp | 57 +++++++++---------- .../updater/prismupdater/PrismUpdater.cpp | 25 ++------ 6 files changed, 32 insertions(+), 105 deletions(-) diff --git a/launcher/DesktopServices.cpp b/launcher/DesktopServices.cpp index b926dbca5..841c1399c 100644 --- a/launcher/DesktopServices.cpp +++ b/launcher/DesktopServices.cpp @@ -2,7 +2,6 @@ /* * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 dada513 - * Copyright (C) 2025 Seth Flynn * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -76,15 +75,6 @@ bool isFlatpak() #endif } -bool isSelfContained() -{ -#ifdef Q_OS_LINUX - return QFileInfo(QCoreApplication::applicationFilePath()).fileName().startsWith("ld-linux"); -#else - return false; -#endif -} - bool isSnap() { #ifdef Q_OS_LINUX diff --git a/launcher/DesktopServices.h b/launcher/DesktopServices.h index 5deb25872..6c6208e82 100644 --- a/launcher/DesktopServices.h +++ b/launcher/DesktopServices.h @@ -37,11 +37,6 @@ bool openUrl(const QUrl& url); */ bool isFlatpak(); -/** - * Determine whether the launcher is running in a self-contained Linux bundle - */ -bool isSelfContained(); - /** * Determine whether the launcher is running in a Snap environment */ diff --git a/launcher/FileSystem.cpp b/launcher/FileSystem.cpp index ab7c73493..30d0a9c4c 100644 --- a/launcher/FileSystem.cpp +++ b/launcher/FileSystem.cpp @@ -4,7 +4,6 @@ * Copyright (C) 2022 Sefa Eyeoglu * Copyright (C) 2022 TheKodeToad * Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> - * Copyright (C) 2025 Seth Flynn * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -773,34 +772,6 @@ QString ResolveExecutable(QString path) return pathInfo.absoluteFilePath(); } -std::unique_ptr createProcess(const QString& program, const QStringList& arguments) -{ - qDebug() << "Creating process for" << program; - auto proc = std::unique_ptr(new QProcess()); - -#if defined(Q_OS_LINUX) - if (DesktopServices::isSelfContained()) { - const auto linkerPath = QCoreApplication::applicationFilePath(); - qDebug() << "Wrapping" << program << "with self-contained linker at" << linkerPath; - - QStringList wrappedArguments; - wrappedArguments << "--inhibit-cache" << program; - wrappedArguments += arguments; - - proc->setProgram(linkerPath); - proc->setArguments(wrappedArguments); - } else { - proc->setProgram(program); - proc->setArguments(arguments); - } -#else - proc->setProgram(program); - proc->setArguments(arguments); -#endif - - return proc; -} - /** * Normalize path * diff --git a/launcher/FileSystem.h b/launcher/FileSystem.h index db8545fd2..f2676b147 100644 --- a/launcher/FileSystem.h +++ b/launcher/FileSystem.h @@ -4,7 +4,6 @@ * Copyright (C) 2022 Sefa Eyeoglu * Copyright (C) 2022 TheKodeToad * Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> - * Copyright (C) 2025 Seth Flynn * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,13 +42,11 @@ #include -#include #include #include #include #include #include -#include #include namespace FS { @@ -336,14 +333,6 @@ QString pathTruncate(const QString& path, int depth); */ QString ResolveExecutable(QString path); -/** - * Create a QProcess instance - * - * This wrapper is currently only required for wrapping binaries called in - * self-contained AppImages (like those created by `go-appimage`) - */ -std::unique_ptr createProcess(const QString& program, const QStringList& arguments); - /** * Normalize path * diff --git a/launcher/updater/PrismExternalUpdater.cpp b/launcher/updater/PrismExternalUpdater.cpp index 6b237d947..69774dc04 100644 --- a/launcher/updater/PrismExternalUpdater.cpp +++ b/launcher/updater/PrismExternalUpdater.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -34,7 +35,6 @@ #include "StringUtils.h" #include "BuildConfig.h" -#include "FileSystem.h" #include "ui/dialogs/UpdateAvailableDialog.h" @@ -97,9 +97,14 @@ void PrismExternalUpdater::checkForUpdates(bool triggeredByUser) progress.show(); QCoreApplication::processEvents(); + QProcess proc; auto exe_name = QStringLiteral("%1_updater").arg(BuildConfig.LAUNCHER_APP_BINARY_NAME); #if defined Q_OS_WIN32 exe_name.append(".exe"); + + auto env = QProcessEnvironment::systemEnvironment(); + env.insert("__COMPAT_LAYER", "RUNASINVOKER"); + proc.setProcessEnvironment(env); #else exe_name = QString("bin/%1").arg(exe_name); #endif @@ -108,21 +113,15 @@ void PrismExternalUpdater::checkForUpdates(bool triggeredByUser) if (priv->allowBeta) args.append("--pre-release"); - auto proc = FS::createProcess(priv->appDir.absoluteFilePath(exe_name), args); -#if defined Q_OS_WIN32 - auto env = QProcessEnvironment::systemEnvironment(); - env.insert("__COMPAT_LAYER", "RUNASINVOKER"); - proc->setProcessEnvironment(env); -#endif - proc->start(proc->program(), proc->arguments()); - auto result_start = proc->waitForStarted(5000); + proc.start(priv->appDir.absoluteFilePath(exe_name), args); + auto result_start = proc.waitForStarted(5000); if (!result_start) { - auto err = proc->error(); + auto err = proc.error(); qDebug() << "Failed to start updater after 5 seconds." - << "reason:" << err << proc->errorString(); + << "reason:" << err << proc.errorString(); auto msgBox = QMessageBox(QMessageBox::Information, tr("Update Check Failed"), - tr("Failed to start after 5 seconds\nReason: %1.").arg(proc->errorString()), QMessageBox::Ok, priv->parent); + tr("Failed to start after 5 seconds\nReason: %1.").arg(proc.errorString()), QMessageBox::Ok, priv->parent); msgBox.setMinimumWidth(460); msgBox.adjustSize(); msgBox.exec(); @@ -134,16 +133,16 @@ void PrismExternalUpdater::checkForUpdates(bool triggeredByUser) } QCoreApplication::processEvents(); - auto result_finished = proc->waitForFinished(60000); + auto result_finished = proc.waitForFinished(60000); if (!result_finished) { - proc->kill(); - auto err = proc->error(); - auto output = proc->readAll(); + proc.kill(); + auto err = proc.error(); + auto output = proc.readAll(); qDebug() << "Updater failed to close after 60 seconds." - << "reason:" << err << proc->errorString(); + << "reason:" << err << proc.errorString(); auto msgBox = QMessageBox(QMessageBox::Information, tr("Update Check Failed"), - tr("Updater failed to close 60 seconds\nReason: %1.").arg(proc->errorString()), QMessageBox::Ok, priv->parent); + tr("Updater failed to close 60 seconds\nReason: %1.").arg(proc.errorString()), QMessageBox::Ok, priv->parent); msgBox.setDetailedText(output); msgBox.setMinimumWidth(460); msgBox.adjustSize(); @@ -155,10 +154,10 @@ void PrismExternalUpdater::checkForUpdates(bool triggeredByUser) return; } - auto exit_code = proc->exitCode(); + auto exit_code = proc.exitCode(); - auto std_output = proc->readAllStandardOutput(); - auto std_error = proc->readAllStandardError(); + auto std_output = proc.readAllStandardOutput(); + auto std_error = proc.readAllStandardError(); progress.hide(); QCoreApplication::processEvents(); @@ -336,9 +335,14 @@ void PrismExternalUpdater::offerUpdate(const QString& version_name, const QStrin void PrismExternalUpdater::performUpdate(const QString& version_tag) { + QProcess proc; auto exe_name = QStringLiteral("%1_updater").arg(BuildConfig.LAUNCHER_APP_BINARY_NAME); #if defined Q_OS_WIN32 exe_name.append(".exe"); + + auto env = QProcessEnvironment::systemEnvironment(); + env.insert("__COMPAT_LAYER", "RUNASINVOKER"); + proc.setProcessEnvironment(env); #else exe_name = QString("bin/%1").arg(exe_name); #endif @@ -347,16 +351,9 @@ void PrismExternalUpdater::performUpdate(const QString& version_tag) if (priv->allowBeta) args.append("--pre-release"); - auto proc = FS::createProcess(exe_name, args); -#if defined Q_OS_WIN32 - auto env = QProcessEnvironment::systemEnvironment(); - env.insert("__COMPAT_LAYER", "RUNASINVOKER"); - proc->setProcessEnvironment(env); -#endif - - auto result = proc->startDetached(priv->appDir.absoluteFilePath(exe_name), args); + auto result = proc.startDetached(priv->appDir.absoluteFilePath(exe_name), args); if (!result) { - qDebug() << "Failed to start updater:" << proc->error() << proc->errorString(); + qDebug() << "Failed to start updater:" << proc.error() << proc.errorString(); } QCoreApplication::exit(); } diff --git a/launcher/updater/prismupdater/PrismUpdater.cpp b/launcher/updater/prismupdater/PrismUpdater.cpp index cc28bfc1d..b84bab13a 100644 --- a/launcher/updater/prismupdater/PrismUpdater.cpp +++ b/launcher/updater/prismupdater/PrismUpdater.cpp @@ -124,19 +124,7 @@ PrismUpdaterApp::PrismUpdaterApp(int& argc, char** argv) : QApplication(argc, ar logToConsole = parser.isSet("debug"); QString origCwdPath = QDir::currentPath(); -#if defined(Q_OS_LINUX) - // NOTE(@getchoo): In order for `go-appimage` to generate self-contained AppImages, it executes apps from a bundled linker at - // /lib64 - // This is not the path to our actual binary, which we want - QString binPath; - if (DesktopServices::isSelfContained()) { - binPath = FS::PathCombine(applicationDirPath(), "../usr/bin"); - } else { - binPath = applicationDirPath(); - } -#else QString binPath = applicationDirPath(); -#endif { // find data director // Root path is used for updates and portable data @@ -819,16 +807,13 @@ QFileInfo PrismUpdaterApp::downloadAsset(const GitHubReleaseAsset& asset) bool PrismUpdaterApp::callAppImageUpdate() { auto appimage_path = QProcessEnvironment::systemEnvironment().value(QStringLiteral("APPIMAGE")); + QProcess proc = QProcess(); qDebug() << "Calling: AppImageUpdate" << appimage_path; - const auto program = FS::PathCombine(m_rootPath, "bin", "AppImageUpdate.AppImage"); - auto proc = FS::createProcess(program, { appimage_path }); - if (!proc) { - qCritical() << "Unable to create process:" << program; - return false; - } - auto result = proc->startDetached(); + proc.setProgram(FS::PathCombine(m_rootPath, "bin", "AppImageUpdate.AppImage")); + proc.setArguments({ appimage_path }); + auto result = proc.startDetached(); if (!result) - qDebug() << "Failed to start AppImageUpdate reason:" << proc->errorString(); + qDebug() << "Failed to start AppImageUpdate reason:" << proc.errorString(); return result; } From e39e59acb6444be5b7539ae3c08817c3ba4775e9 Mon Sep 17 00:00:00 2001 From: Seth Flynn Date: Wed, 17 Dec 2025 04:57:30 -0500 Subject: [PATCH 3/4] revert: "fix(launcher): set correct bin path for self-contained appimages" Refs: b1b4b5d Signed-off-by: Seth Flynn --- launcher/Application.cpp | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 601ccaeff..67ddb53e8 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -371,25 +371,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) } QString origcwdPath = QDir::currentPath(); -#if defined(Q_OS_LINUX) - const QString binFilePath = applicationFilePath(); - const bool isAppImage = binFilePath.startsWith("/tmp/.mount_"); - // Yes, this can technically trigger the logic below if someone makes an AppImage with an actual launcher exe named "ld-linux" - // Please don't :) - const bool executedFromLinker = QFileInfo(binFilePath).fileName().startsWith("ld-linux"); - - // NOTE(@getchoo): In order for `go-appimage` to generate self-contained AppImages, it executes apps from a bundled linker at - // /lib64 - // This is not the path to our actual binary, which we want - QString binPath; - if (isAppImage && executedFromLinker) { - binPath = FS::PathCombine(applicationDirPath(), "../usr/bin"); - } else { - binPath = applicationDirPath(); - } -#else QString binPath = applicationDirPath(); -#endif { // Root path is used for updates and portable data From 5d5f22e6725036b16caa39b887eb25b144c67342 Mon Sep 17 00:00:00 2001 From: Seth Flynn Date: Wed, 17 Dec 2025 05:19:52 -0500 Subject: [PATCH 4/4] ci(linux): verify appstream info for appimages Signed-off-by: Seth Flynn --- .github/actions/package/linux/action.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/actions/package/linux/action.yml b/.github/actions/package/linux/action.yml index 5233f273b..97a58d019 100644 --- a/.github/actions/package/linux/action.yml +++ b/.github/actions/package/linux/action.yml @@ -84,9 +84,7 @@ runs: mv "$INSTALL_APPIMAGE_DIR"/{sharun,AppRun} ls -la "$INSTALL_APPIMAGE_DIR" - # FIXME(@getchoo): Validate AppStream information when https://github.com/probonopd/go-appimage/pull/379 is merged mkappimage \ - --no-appstream \ --updateinformation "gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|PrismLauncher-Linux-$APPIMAGE_ARCH.AppImage.zsync" \ "$INSTALL_APPIMAGE_DIR" \ "PrismLauncher-Linux-$VERSION-${{ inputs.build-type }}-$APPIMAGE_ARCH.AppImage"