diff --git a/CMakeLists.txt b/CMakeLists.txt
index 83c499f89..59a1739c4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -24,6 +24,8 @@ option(ENABLE_OPENGL "Build with OpenGL renderer" ON)
option(ENABLE_VULKAN "Build with Vulkan renderer" ON)
# Global options.
+option(DISABLE_GEN_SCM_VERSION "Disable generation of SCM version, must manually populate" OFF)
+mark_as_advanced(DISABLE_GEN_SCM_VERSION)
if(NOT ANDROID)
option(BUILD_NOGUI_FRONTEND "Build the NoGUI frontend" OFF)
option(BUILD_QT_FRONTEND "Build the Qt frontend" ON)
diff --git a/scripts/flatpak/flathub.json b/scripts/flatpak/flathub.json
new file mode 100644
index 000000000..fc3ec0938
--- /dev/null
+++ b/scripts/flatpak/flathub.json
@@ -0,0 +1,69 @@
+{
+ "app-id": "org.duckstation.duckstation",
+ "runtime": "org.kde.Platform",
+ "runtime-version": "6.5",
+ "sdk": "org.kde.Sdk",
+ "sdk-extensions": [
+ "org.freedesktop.Sdk.Extension.llvm16"
+ ],
+ "command": "duckstation-qt",
+ "finish-args": [
+ "--device=all",
+ "--allow=bluetooth",
+ "--share=network",
+ "--share=ipc",
+ "--socket=fallback-x11",
+ "--socket=wayland",
+ "--socket=pulseaudio",
+ "--talk-name=org.freedesktop.ScreenSaver"
+ ],
+ "modules": [
+ "modules/20-sdl2.json",
+ "modules/21-libbacktrace.json",
+ {
+ "name": "duckstation",
+ "buildsystem": "cmake",
+ "build-options": {
+ "strip": false,
+ "no-debuginfo": true,
+ "config-opts": [
+ "-DCMAKE_BUILD_TYPE=Release",
+ "-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON",
+ "-DBUILD_NOGUI_FRONTEND=OFF",
+ "-DBUILD_QT_FRONTEND=ON",
+ "-DBUILD_TESTS=OFF",
+ "-DCMAKE_C_COMPILER=/usr/lib/sdk/llvm16/bin/clang",
+ "-DCMAKE_CXX_COMPILER=/usr/lib/sdk/llvm16/bin/clang++",
+ "-DCMAKE_EXE_LINKER_FLAGS_INIT=-fuse-ld=lld",
+ "-DCMAKE_MODULE_LINKER_FLAGS_INIT=-fuse-ld=lld",
+ "-DCMAKE_SHARED_LINKER_FLAGS_INIT=-fuse-ld=lld",
+ "-DDISABLE_GEN_SCM_VERSION=ON"
+ ]
+ },
+ "sources": [
+ {
+ "type": "git",
+ "url": "https://github.com/stenzek/duckstation.git",
+ "branch": "master",
+ "commit": "@GIT_HASH@"
+ },
+ {
+ "type": "file",
+ "path": "org.duckstation.duckstation.metainfo.xml"
+ },
+ {
+ "type": "file",
+ "path": "scmversion.cpp",
+ "dest": "src/scmversion"
+ }
+ ],
+ "post-install": [
+ "cp -a \"${FLATPAK_BUILDER_BUILDDIR}/bin\" ${FLATPAK_DEST}",
+ "install -Dm644 scripts/duckstation-qt.png ${FLATPAK_DEST}/share/icons/hicolor/512x512/apps/org.duckstation.duckstation.png",
+ "install -Dm644 scripts/duckstation-qt.desktop ${FLATPAK_DEST}/share/applications/org.duckstation.duckstation.desktop",
+ "desktop-file-edit --set-key=Icon --set-value=org.duckstation.duckstation ${FLATPAK_DEST}/share/applications/org.duckstation.duckstation.desktop",
+ "install -Dm644 org.duckstation.duckstation.metainfo.xml ${FLATPAK_DEST}/share/metainfo/org.duckstation.duckstation.metainfo.xml"
+ ]
+ }
+ ]
+}
diff --git a/scripts/flatpak/update-flathub.sh b/scripts/flatpak/update-flathub.sh
new file mode 100755
index 000000000..6c2d1443f
--- /dev/null
+++ b/scripts/flatpak/update-flathub.sh
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+
+APPID=org.duckstation.DuckStation
+SCRIPTDIR=$(realpath $(dirname "${BASH_SOURCE[0]}"))
+
+if [[ $# -lt 1 ]]; then
+ echo "Output directory must be provided as a parameter"
+ exit 1
+fi
+
+OUTDIR=$(realpath "$1")
+
+rm -fr "${OUTDIR}/modules"
+cp -a "${SCRIPTDIR}/modules" "${OUTDIR}/modules"
+cp "${SCRIPTDIR}/flathub.json" "${OUTDIR}/${APPID}.json"
+
+pushd "${SCRIPTDIR}"
+GIT_DATE=$(git log -1 --pretty=%cd --date=short)
+GIT_VERSION=$(git tag --points-at HEAD)
+GIT_HASH=$(git rev-parse HEAD)
+
+if [[ "${GIT_VERSION}" == "" ]]; then
+ GIT_VERSION=$(git describe --tags --dirty --exclude latest --exclude preview --exclude legacy --exclude previous-latest | tr -d '\r\n')
+ if [[ "${GIT_VERSION}" == "" ]]; then
+ GIT_VERSION=$(git rev-parse HEAD)
+ fi
+fi
+"${SCRIPTDIR}/../../scripts/generate-metainfo.sh" "${OUTDIR}/${APPID}.metainfo.xml"
+popd
+
+# Change App ID, because flathub uses the wrong name.
+sed -i -e "s/org.duckstation.duckstation/org.duckstation.DuckStation/g" "${OUTDIR}/${APPID}.json" "${OUTDIR}/${APPID}.metainfo.xml"
+
+# Fill in version details.
+sed -i -e "s/@GIT_VERSION@/${GIT_VERSION}/" "${OUTDIR}/${APPID}.json"
+sed -i -e "s/@GIT_DATE@/${GIT_DATE}/" "${OUTDIR}/${APPID}.json"
+sed -i -e "s/@GIT_HASH@/${GIT_HASH}/" "${OUTDIR}/${APPID}.json"
+
+# Apparently we don't have git history.
+pushd "${OUTDIR}"
+"${SCRIPTDIR}/../../src/scmversion/gen_scmversion.sh"
+popd
diff --git a/scripts/generate-metainfo.sh b/scripts/generate-metainfo.sh
index c3b65d311..31f8f251f 100755
--- a/scripts/generate-metainfo.sh
+++ b/scripts/generate-metainfo.sh
@@ -1,13 +1,15 @@
#!/usr/bin/env bash
-SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
+SCRIPTDIR=$(realpath $(dirname "${BASH_SOURCE[0]}"))
if [[ $# -lt 1 ]]; then
echo "Output file must be provided as a parameter"
exit 1
fi
-OUTFILE=$1
+OUTFILE="$1"
+
+pushd "${SCRIPTDIR}"
GIT_DATE=$(git log -1 --pretty=%cd --date=short)
GIT_VERSION=$(git tag --points-at HEAD)
GIT_HASH=$(git rev-parse HEAD)
@@ -18,6 +20,7 @@ if [[ "${GIT_VERSION}" == "" ]]; then
GIT_VERSION=$(git rev-parse HEAD)
fi
fi
+popd
echo "GIT_DATE: ${GIT_DATE}"
echo "GIT_VERSION: ${GIT_VERSION}"
diff --git a/scripts/org.duckstation.duckstation.metainfo.xml.in b/scripts/org.duckstation.duckstation.metainfo.xml.in
index a3f52b933..5c6121679 100644
--- a/scripts/org.duckstation.duckstation.metainfo.xml.in
+++ b/scripts/org.duckstation.duckstation.metainfo.xml.in
@@ -28,7 +28,4 @@
-
- https://raw.githubusercontent.com/stenzek/duckstation/@GIT_HASH@/scripts/flatpak/org.duckstation.duckstation.json
-
diff --git a/src/scmversion/CMakeLists.txt b/src/scmversion/CMakeLists.txt
index 7a5129298..903ecdfdc 100644
--- a/src/scmversion/CMakeLists.txt
+++ b/src/scmversion/CMakeLists.txt
@@ -1,11 +1,13 @@
-# _scmversion.cpp is a dummy file that will never be created, so the command will always be run
-if(WIN32)
- add_custom_command(OUTPUT scmversion.cpp _scmversion.cpp
- COMMAND cmd /k "${CMAKE_CURRENT_SOURCE_DIR}/gen_scmversion.bat"
- WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
-else()
- add_custom_command(OUTPUT scmversion.cpp PRE_BUILD
- COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/gen_scmversion.sh")
+if(NOT DISABLE_GEN_SCM_VERSION)
+ if(WIN32)
+ # _scmversion.cpp is a dummy file that will never be created, so the command will always be run
+ add_custom_command(OUTPUT scmversion.cpp _scmversion.cpp
+ COMMAND cmd /k "${CMAKE_CURRENT_SOURCE_DIR}/gen_scmversion.bat"
+ WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+ else()
+ add_custom_command(OUTPUT scmversion.cpp PRE_BUILD
+ COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/gen_scmversion.sh")
+ endif()
endif()
add_library(scmversion