diff --git a/.ci/pack.sh b/.ci/pack.sh index ecd304cf7..8be6418da 100755 --- a/.ci/pack.sh +++ b/.ci/pack.sh @@ -6,7 +6,7 @@ GITREV="`git show -s --format='%h'`" REV_NAME="lime3ds-$OS-$TARGET-$GITDATE-$GITREV" # Determine the name of the release being built. -if [[ "$GITHUB_REF_TYPE" == "tag" ]]; then +if [ "$GITHUB_REF_TYPE" = "tag" ]; then RELEASE_NAME=lime3ds-$GITHUB_REF_NAME REV_NAME="lime3ds-$GITHUB_REF_NAME-$OS-$TARGET" else @@ -50,7 +50,10 @@ function pack_artifacts() { rm -rf "$REV_NAME" } -if [ -n "$UNPACKED" ]; then +if [ "$OS" = "windows" ] && [ "$GITHUB_REF_TYPE" = "tag" ]; then + # Move the installer to the artifacts directory + mv src/installer/bin/*.exe artifacts/ +elif [ -n "$UNPACKED" ]; then # Copy the artifacts to be uploaded unpacked. for ARTIFACT in build/bundle/*; do FILENAME=$(basename "$ARTIFACT") diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8272bc48b..3bf5509df 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -174,10 +174,23 @@ jobs: pacboy: >- toolchain:p ccache:p cmake:p ninja:p spirv-tools:p qt6-base:p qt6-multimedia:p qt6-multimedia-wmf:p qt6-tools:p qt6-translations:p + - name: Install NSIS + run: | + Invoke-WebRequest https://deac-riga.dl.sourceforge.net/project/nsis/NSIS%203/3.10/nsis-3.10-setup.exe?viasf=1 -OutFile C:\WINDOWS\Temp\nsis-3.10-setup.exe + Invoke-Expression "& C:\WINDOWS\Temp\nsis-3.10-setup.exe \S" + shell: pwsh - name: Disable line ending translation run: git config --global core.autocrlf input - name: Build run: ./.ci/windows.sh + - name: Generate installer + if: ${{ github.ref_type == 'tag' }} + run: | + cd src\installer + "C:\Program Files (x86)\NSIS\makensis.exe" /DPRODUCT_VARIANT=${{ matrix.target }} /DPRODUCT_VERSION=${{ github.ref_name }} lime3ds.nsi + mkdir bin + move /y *.exe bin\ + shell: cmd - name: Pack run: ./.ci/pack.sh - name: Upload @@ -256,4 +269,4 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - asset_paths: '["./**/*.tar.*","./**/*.AppImage","./**/*.zip","./**/*.apk","./**/*.aab"]' + asset_paths: '["./**/*.tar.*","./**/*.AppImage","./**/*.zip","./**/*.apk","./**/*.aab","./**/*.exe"]' diff --git a/.gitignore b/.gitignore index c02fca12a..fb892e695 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,9 @@ doc-build/ build-*/ +# NSIS built executables +src/installer/*.exe + # Generated source files src/common/scm_rev.cpp .travis.descriptor.json diff --git a/src/installer/lime3ds.nsi b/src/installer/lime3ds.nsi new file mode 100644 index 000000000..9ca2a3be1 --- /dev/null +++ b/src/installer/lime3ds.nsi @@ -0,0 +1,201 @@ +; Copyright Dolphin Emulator Project +; Licensed under GPLv2 or any later version +; Refer to the license.txt file included. + +; Usage: +; get the latest nsis: https://nsis.sourceforge.io/Download +; probably also want vscode extension: https://marketplace.visualstudio.com/items?itemName=idleberg.nsis +; makensis /DPRODUCT_VERSION= /DPRODUCT_VARIANT= + +; Require /DPRODUCT_VERSION= to makensis. +!ifndef PRODUCT_VERSION + !error "PRODUCT_VERSION must be defined" +!endif + +; Require /DPRODUCT_VARIANT= to makensis. +!ifndef PRODUCT_VARIANT + !error "PRODUCT_VARIANT must be defined" +!endif + +!define PRODUCT_NAME "Lime3DS" +!define PRODUCT_PUBLISHER "Lime3DS Emulator Developers" +!define PRODUCT_WEB_SITE "https://lime3ds.github.io/" +!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\${PRODUCT_NAME}.exe" +!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" + +!define BINARY_SOURCE_DIR "..\..\build\bundle" + +Name "${PRODUCT_NAME}" +OutFile "lime3ds-${PRODUCT_VERSION}-windows-${PRODUCT_VARIANT}.exe" +SetCompressor /SOLID lzma +ShowInstDetails show +ShowUnInstDetails show + +; Setup MultiUser support: +; If launched without ability to elevate, user will not see any extra options. +; If user has ability to elevate, they can choose to install system-wide, with default to CurrentUser. +!define MULTIUSER_EXECUTIONLEVEL Highest +!define MULTIUSER_INSTALLMODE_INSTDIR "${PRODUCT_NAME}" +!define MULTIUSER_MUI +!define MULTIUSER_INSTALLMODE_COMMANDLINE +!define MULTIUSER_USE_PROGRAMFILES64 +!include "MultiUser.nsh" + +!include "MUI2.nsh" + +; MUI Settings +!define MUI_ICON "../../dist/lime.ico" +!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico" + +; License page +!insertmacro MUI_PAGE_LICENSE "..\..\license.txt" +; All/Current user selection page +!insertmacro MULTIUSER_PAGE_INSTALLMODE +; Directory page +!insertmacro MUI_PAGE_DIRECTORY +; Instfiles page +!insertmacro MUI_PAGE_INSTFILES +; Finish page +!insertmacro MUI_PAGE_FINISH + +; Uninstaller pages +!insertmacro MUI_UNPAGE_INSTFILES + +; Language files +!insertmacro MUI_LANGUAGE "English" +!insertmacro MUI_LANGUAGE "SimpChinese" +!insertmacro MUI_LANGUAGE "TradChinese" +!insertmacro MUI_LANGUAGE "Danish" +!insertmacro MUI_LANGUAGE "Dutch" +!insertmacro MUI_LANGUAGE "Finnish" +!insertmacro MUI_LANGUAGE "French" +!insertmacro MUI_LANGUAGE "German" +!insertmacro MUI_LANGUAGE "Greek" +!insertmacro MUI_LANGUAGE "Hungarian" +!insertmacro MUI_LANGUAGE "Indonesian" +!insertmacro MUI_LANGUAGE "Italian" +!insertmacro MUI_LANGUAGE "Japanese" +!insertmacro MUI_LANGUAGE "Korean" +!insertmacro MUI_LANGUAGE "Lithuanian" +!insertmacro MUI_LANGUAGE "Norwegian" +!insertmacro MUI_LANGUAGE "Polish" +!insertmacro MUI_LANGUAGE "PortugueseBR" +!insertmacro MUI_LANGUAGE "Romanian" +!insertmacro MUI_LANGUAGE "Spanish" +!insertmacro MUI_LANGUAGE "Turkish" +!insertmacro MUI_LANGUAGE "Vietnamese" + +; MUI end ------ + +!include "WinVer.nsh" +; Declare the installer itself as win10/win11 compatible, so WinVer.nsh works correctly. +ManifestSupportedOS {8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a} + +Function .onInit + !insertmacro MULTIUSER_INIT + + ; Keep in sync with build_info.txt + !define MIN_WIN10_VERSION 1703 + ${IfNot} ${AtLeastwin10} + ${OrIfNot} ${AtLeastWaaS} ${MIN_WIN10_VERSION} + MessageBox MB_OK "At least Windows 10 version ${MIN_WIN10_VERSION} is required." + Abort + ${EndIf} + + !insertmacro MUI_LANGDLL_DISPLAY +FunctionEnd + +Function un.onInit + !insertmacro MULTIUSER_UNINIT +FunctionEnd + +Var DisplayName +!macro UPDATE_DISPLAYNAME + ${If} $MultiUser.InstallMode == "CurrentUser" + StrCpy $DisplayName "$(^Name) (User)" + ${Else} + StrCpy $DisplayName "$(^Name)" + ${EndIf} +!macroend + +Section "Base" + ExecWait '"$INSTDIR\uninst.exe" /S _?=$INSTDIR' + + SectionIn RO + + SetOutPath "$INSTDIR" + + ; The binplaced build output will be included verbatim. + File /r "${BINARY_SOURCE_DIR}\*" + + !insertmacro UPDATE_DISPLAYNAME + + ; Create start menu and desktop shortcuts + ; This needs to be done after Dolphin.exe is copied + CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}" + CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\$DisplayName.lnk" "$INSTDIR\lime3ds.exe" + CreateShortCut "$DESKTOP\$DisplayName.lnk" "$INSTDIR\lime3ds.exe" + + ; ?? + SetOutPath "$TEMP" +SectionEnd + +Section -AdditionalIcons + ; Create start menu shortcut for the uninstaller + CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall $DisplayName.lnk" "$INSTDIR\uninst.exe" "/$MultiUser.InstallMode" +SectionEnd + +!include "FileFunc.nsh" + +Section -Post + WriteUninstaller "$INSTDIR\uninst.exe" + + WriteRegStr SHCTX "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\lime3ds.exe" + + ; Write metadata for add/remove programs applet + WriteRegStr SHCTX "${PRODUCT_UNINST_KEY}" "DisplayName" "$DisplayName" + WriteRegStr SHCTX "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe /$MultiUser.InstallMode" + WriteRegStr SHCTX "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\lime3ds.exe" + WriteRegStr SHCTX "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}" + WriteRegStr SHCTX "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}" + WriteRegStr SHCTX "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}" + WriteRegStr SHCTX "${PRODUCT_UNINST_KEY}" "InstallLocation" "$INSTDIR" + ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 + IntFmt $0 "0x%08X" $0 + WriteRegDWORD SHCTX "${PRODUCT_UNINST_KEY}" "EstimatedSize" "$0" + WriteRegStr SHCTX "${PRODUCT_UNINST_KEY}" "Comments" "3DS emulator based on Citra" +SectionEnd + +Section Uninstall + !insertmacro UPDATE_DISPLAYNAME + + Delete "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall $DisplayName.lnk" + + Delete "$DESKTOP\$DisplayName.lnk" + Delete "$SMPROGRAMS\${PRODUCT_NAME}\$DisplayName.lnk" + RMDir "$SMPROGRAMS\${PRODUCT_NAME}" + + ; Be a bit careful to not delete files a user may have put into the install directory. + Delete "$INSTDIR\*.dll" + Delete "$INSTDIR\lime3ds.exe" + Delete "$INSTDIR\lime3ds-room.exe" + Delete "$INSTDIR\license.txt" + Delete "$INSTDIR\qt.conf" + Delete "$INSTDIR\README.md" + Delete "$INSTDIR\uninst.exe" + RMDir /r "$INSTDIR\dist" + RMDir /r "$INSTDIR\plugins" + RMDir /r "$INSTDIR\scripting" + ; In case user is upgrading from 2117.1 or earlier + Delete "$INSTDIR\lime3ds-cli.exe" + Delete "$INSTDIR\lime3ds-gui.exe" + ; This should never be distributed via the installer, but just in case it is + Delete "$INSTDIR\tests.exe" + ; Delete the installation directory if there are no files left + RMDir "$INSTDIR" + + DeleteRegKey SHCTX "${PRODUCT_UNINST_KEY}" + DeleteRegKey SHCTX "${PRODUCT_DIR_REGKEY}" + + SetAutoClose true +SectionEnd