shithub: candycrisis

Download patch

ref: 9cfde203bbe109f41b25d02b5c9602345c986fff
parent: 6f5ffce93e1675d7a4fa094adf1ecdac191d8290
author: Iliyas Jorio <[email protected]>
date: Sat Feb 11 06:22:13 EST 2023

CI: Back to prebuilt SDL dll

--- /dev/null
+++ b/.github/workflows/metarelease.yml
@@ -1,0 +1,12 @@
+name: Meta Release Big 3
+
+on: [workflow_dispatch]
+
+jobs:
+  appimage-x86_64:
+    uses: ./.github/workflows/release-appimage-x86_64.yml
+  mac:
+    uses: ./.github/workflows/release-mac.yml
+    secrets: inherit
+  windows:
+    uses: ./.github/workflows/release-windows.yml
--- a/.github/workflows/release-aarch64.yml
+++ /dev/null
@@ -1,84 +1,0 @@
-name: Make Release Builds (linux/aarch64)
-
-on: [workflow_dispatch]
-
-jobs:
-  build-linux-appimage-aarch64:
-    runs-on: ubuntu-20.04
-    timeout-minutes: 100  # this job may take up to an hour
-
-    steps:
-      - uses: actions/checkout@v3
-        with:
-          submodules: 'recursive'
-
-      # Create shared directory ON HOST. (If it's done within qemu, it'll be created with root permissions)
-      - name: Create artifacts directory shared with docker
-        run: |
-          mkdir -p "artifacts"
-
-      # QEMU can't run appimagetool-aarch64, so we have to build the AppImage on x86_64
-      - name: Download appimagetool
-        run : |
-          pushd artifacts
-          wget -q https://github.com/AppImage/AppImageKit/releases/download/13/appimagetool-x86_64.AppImage
-          wget -q https://github.com/AppImage/AppImageKit/releases/download/13/runtime-aarch64
-          chmod +x appimagetool-x86_64.AppImage
-          chmod +x runtime-aarch64
-          popd
-
-      - uses: uraimo/run-on-arch-action@v2
-        name: Build game via QEMU
-        id: buildgame
-        with:
-          arch: aarch64
-
-          # Distro must be kept in sync with `runs-on` above.
-          # See: https://github.com/uraimo/run-on-arch-action#supported-platforms
-          distro: ubuntu20.04
-
-          # (Optional) Speeds up builds by storing container images in a GitHub package registry.
-          githubToken: ${{ github.token }}
-
-          # Mount the artifacts directory as /artifacts in the container
-          dockerRunArgs: |
-            --volume "${PWD}/artifacts:/artifacts"
-
-          # Install build tools for the game and SDL build dependencies.
-          # See: https://github.com/libsdl-org/SDL/blob/main/docs/README-linux.md (last updated for SDL 2.26.0)
-          install: |
-            apt update -y
-            apt install -y build-essential cmake
-            #apt install -y libsdl2-dev  #----- for quick testing
-            apt install -y libasound2-dev libpulse-dev \
-              libaudio-dev libjack-dev libsndio-dev libsamplerate0-dev libx11-dev libxext-dev \
-              libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev libwayland-dev \
-              libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev \
-              libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev fcitx-libs-dev
-
-          # Build the aarch64 version under dist/, then tar it up and move it to /artifacts.
-          # (We're not building directly in /artifacts as this would cause permission issues when moving back to the x86_64 host)
-          run: |
-            cmake -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
-            cmake --build build
-            bash packaging/prepare_appimage_appdir.sh build/CandyCrisis
-            cd build
-            tar cvf /artifacts/aarch64-dist.tar ./*.AppDir
-
-      # QEMU can't run appimagetool-aarch64, so we have to build the AppImage on x86_64
-      - name: Create AppImage on x86_64 host
-        run: |
-          cd artifacts
-          tar xvf aarch64-dist.tar
-
-          APPIMAGE_INPUT=$(ls -d --indicator-style=none *.AppDir)
-          APPIMAGE_OUTPUT=${APPIMAGE_INPUT%.AppDir}.AppImage
-          echo "APPIMAGE_OUTPUT=$APPIMAGE_OUTPUT" >> $GITHUB_ENV
-
-          ./appimagetool-x86_64.AppImage -v --runtime-file runtime-aarch64 --no-appstream $APPIMAGE_INPUT $APPIMAGE_OUTPUT
-
-      - name: Upload
-        uses: actions/upload-artifact@v3
-        with:
-          name: ${{ env.APPIMAGE_OUTPUT }}
-          path: artifacts/${{ env.APPIMAGE_OUTPUT }}
--- /dev/null
+++ b/.github/workflows/release-appimage-aarch64.yml
@@ -1,0 +1,96 @@
+name: Release AppImage aarch64
+
+on: [workflow_dispatch, workflow_call]
+
+env:
+  SDL2_VERSION: "2.26.3"
+  APPIMAGETOOL_VERSION: "13"
+  GAME_SHORTNAME: "CandyCrisis"
+  GAME_LONGNAME: "Candy Crisis"
+
+jobs:
+  release-appimage-aarch64:
+    runs-on: ubuntu-20.04
+    timeout-minutes: 100  # this job may take up to an hour
+
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          submodules: 'recursive'
+
+      # Create shared directory ON HOST. (If it's done within qemu, it'll be created with root permissions)
+      - name: Create artifacts directory shared with docker
+        run: |
+          mkdir -p "artifacts"
+
+      # QEMU can't run appimagetool-aarch64, so we have to build the AppImage on x86_64
+      - name: Download appimagetool
+        run : |
+          pushd artifacts
+          wget -q https://github.com/AppImage/AppImageKit/releases/download/13/appimagetool-x86_64.AppImage
+          wget -q https://github.com/AppImage/AppImageKit/releases/download/13/runtime-aarch64
+          chmod +x appimagetool-x86_64.AppImage
+          chmod +x runtime-aarch64
+          popd
+
+      - name: Get SDL source
+        run: |
+          git clone --depth 1 --branch release-${{env.SDL2_VERSION}} https://github.com/libsdl-org/SDL
+
+      - uses: uraimo/run-on-arch-action@v2
+        name: Build game via QEMU
+        id: buildgame
+        with:
+          arch: aarch64
+
+          # Distro must be kept in sync with `runs-on` above.
+          # See: https://github.com/uraimo/run-on-arch-action#supported-platforms
+          distro: ubuntu20.04
+
+          # (Optional) Speeds up builds by storing container images in a GitHub package registry.
+          githubToken: ${{ github.token }}
+
+          # Mount the artifacts directory as /artifacts in the container
+          dockerRunArgs: |
+            --volume "${PWD}/artifacts:/artifacts"
+
+          # Install build tools for the game and SDL build dependencies.
+          # See: https://github.com/libsdl-org/SDL/blob/main/docs/README-linux.md (last updated for SDL 2.26.0)
+          install: |
+            apt update -y
+            apt install -y build-essential cmake
+            #apt install -y libsdl2-dev  #----- for quick testing
+            apt install -y libasound2-dev libpulse-dev \
+              libaudio-dev libjack-dev libsndio-dev libsamplerate0-dev libx11-dev libxext-dev \
+              libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev libwayland-dev \
+              libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev \
+              libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev fcitx-libs-dev
+
+          # Build the aarch64 version under dist/, then tar it up and move the tarball to /artifacts.
+          # (We're not building directly in /artifacts as this would cause permission issues when moving back to the x86_64 host)
+          run: |
+            #cmake -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo  #----- for quick testing
+            cmake -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SDL_FROM_SOURCE=1 -DSTATIC_SDL=1
+            cmake --build build
+            bash packaging/prepare_appimage_appdir.sh build/${{env.GAME_SHORTNAME}}
+            cd build
+            tar cvf /artifacts/aarch64-dist.tar ./*.AppDir ./version.txt
+
+      # QEMU can't run appimagetool-aarch64, so we have to build the AppImage on x86_64
+      - name: Create AppImage on x86_64 host
+        run: |
+          cd artifacts
+          tar xvf aarch64-dist.tar
+
+          GAME_VERSION=$(cat version.txt)
+          ARTIFACT_NAME="${{env.GAME_SHORTNAME}}-$GAME_VERSION-linux-aarch64.AppImage"
+          echo "ARTIFACT_NAME=$ARTIFACT_NAME" >> $GITHUB_ENV
+
+          APPIMAGE_INPUT=$(ls -d --indicator-style=none *.AppDir)
+          ./appimagetool-x86_64.AppImage -v --runtime-file runtime-aarch64 --no-appstream $APPIMAGE_INPUT $ARTIFACT_NAME
+
+      - name: Upload
+        uses: actions/upload-artifact@v3
+        with:
+          name: ${{ env.ARTIFACT_NAME }}
+          path: artifacts/${{ env.ARTIFACT_NAME }}
--- /dev/null
+++ b/.github/workflows/release-appimage-x86_64.yml
@@ -1,0 +1,68 @@
+name: Release AppImage x86_64
+
+on: [workflow_dispatch, workflow_call]
+
+env:
+  SDL2_VERSION: "2.26.3"
+  APPIMAGETOOL_VERSION: "13"
+  GAME_SHORTNAME: "CandyCrisis"
+  GAME_LONGNAME: "Candy Crisis"
+
+jobs:
+  release-appimage-x86_64:
+    runs-on: ubuntu-20.04  # Use oldest distro still supported by GitHub to cover the oldest possible glibc
+    timeout-minutes: 20
+
+    steps:
+      - name: Get CPU count
+        run: |
+          NPROC=$(python3 -c 'import multiprocessing; print(multiprocessing.cpu_count())')
+          echo "NPROC=$NPROC" >> $GITHUB_ENV
+          echo CPU count = $NPROC
+
+      - name: Checkout
+        uses: actions/checkout@v3
+        with:
+          submodules: 'recursive'
+
+      # cf. https://github.com/libsdl-org/SDL/blob/main/docs/README-linux.md
+      - name: Get build dependencies for SDL from APT  
+        run: |
+          sudo apt update
+          sudo apt install -y libasound2-dev libpulse-dev \
+            libaudio-dev libjack-dev libsndio-dev libsamplerate0-dev libx11-dev libxext-dev \
+            libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev libwayland-dev \
+            libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev \
+            libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev fcitx-libs-dev
+
+      - name: Get SDL source
+        run: |
+          git clone --depth 1 --branch release-${{ env.SDL2_VERSION }} https://github.com/libsdl-org/SDL
+
+      - name: Configure
+        run: cmake -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SDL_FROM_SOURCE=1 -DSTATIC_SDL=1
+
+      - name: Prepare artifact names
+        run: |
+          GAME_VERSION=$(cat build/version.txt)
+          ARTIFACT_NAME="${{env.GAME_SHORTNAME}}-$GAME_VERSION-linux-x86_64.AppImage"
+          echo "GAME_VERSION=$GAME_VERSION" >> $GITHUB_ENV
+          echo "ARTIFACT_NAME=$ARTIFACT_NAME" >> $GITHUB_ENV
+
+      - name: Build
+        run: cmake --build build -- -j ${{ env.NPROC }}
+
+      - name: Prepare AppDir
+        run: bash packaging/prepare_appimage_appdir.sh build/${{env.GAME_SHORTNAME}}
+
+      - name: Make AppImage
+        run: |
+          wget https://github.com/AppImage/AppImageKit/releases/download/${{env.APPIMAGETOOL_VERSION}}/appimagetool-x86_64.AppImage
+          chmod +x appimagetool-x86_64.AppImage
+          ./appimagetool-x86_64.AppImage --no-appstream build/${{env.GAME_SHORTNAME}}.AppDir build/${{env.ARTIFACT_NAME}}
+
+      - name: Upload
+        uses: actions/upload-artifact@v3
+        with:
+          name: ${{env.ARTIFACT_NAME}}
+          path: build/${{env.ARTIFACT_NAME}}
--- /dev/null
+++ b/.github/workflows/release-mac.yml
@@ -1,0 +1,78 @@
+name: Release Mac
+
+on: [workflow_dispatch, workflow_call]
+
+env:
+  SDL2_VERSION: "2.26.3"
+  GAME_SHORTNAME: "CandyCrisis"
+  GAME_LONGNAME: "Candy Crisis"
+
+jobs:
+  release-mac:
+    runs-on: macos-11
+    timeout-minutes: 20
+
+    steps:
+      - name: Get CPU count
+        run: |
+          NPROC=$(python3 -c 'import multiprocessing; print(multiprocessing.cpu_count())')
+          echo "NPROC=$NPROC" >> $GITHUB_ENV
+          echo CPU count = $NPROC
+
+      - name: Import codesigning certs
+        uses: apple-actions/import-codesign-certs@v1
+        with:
+          p12-file-base64: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 }}
+          p12-password: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_PASSWORD }}
+
+      - name: Checkout
+        uses: actions/checkout@v3
+        with:
+          submodules: 'recursive'
+
+      - name: Get SDL2.framework
+        run: |
+          curl -LO https://github.com/libsdl-org/SDL/releases/download/release-${{env.SDL2_VERSION}}/SDL2-${{env.SDL2_VERSION}}.dmg
+          hdiutil attach SDL2-*.dmg
+          cp -a /Volumes/SDL2/SDL2.framework SDL2.framework
+          hdiutil detach /Volumes/SDL2
+
+      - name: Configure
+        run: cmake -S . -B build -G Xcode -DCODE_SIGN_IDENTITY=${{ secrets.APPLE_CODE_SIGN_IDENTITY }}
+
+      - name: Prepare artifact names
+        run: |
+          GAME_VERSION=$(cat build/version.txt)
+          FOLDER_NAME="${{env.GAME_LONGNAME}} $GAME_VERSION"
+          ARTIFACT_NAME="${{env.GAME_SHORTNAME}}-$GAME_VERSION-mac.dmg"
+          echo "GAME_VERSION=$GAME_VERSION" >> $GITHUB_ENV
+          echo "FOLDER_NAME=$FOLDER_NAME" >> $GITHUB_ENV
+          echo "ARTIFACT_NAME=$ARTIFACT_NAME" >> $GITHUB_ENV
+
+      - name: Build
+        run: cmake --build build --config RelWithDebInfo -- -j ${{ env.NPROC }}
+
+      #- name: Force codesigning (not necessary since we tell Xcode to do it for us)
+      #  run: codesign --force --sign ${{ secrets.APPLE_DEVELOPMENT_TEAM }} --options runtime "build/RelWithDebInfo/${{env.GAME_LONGNAME}}.app"
+
+      - name: Check codesigning
+        run: codesign -vvv --deep --strict "build/RelWithDebInfo/${{env.GAME_LONGNAME}}.app"
+
+      - name: Create dmg
+        run: |
+          cp build/ReadMe.txt build/RelWithDebInfo
+          hdiutil create -fs HFS+ -srcfolder build/RelWithDebInfo -volname "${{env.FOLDER_NAME}}" build/${{env.ARTIFACT_NAME}}
+
+      - name: Notarize
+        run: |
+          xcrun notarytool store-credentials GameNotarizationProfile --apple-id ${{ secrets.APPLE_NOTARIZATION_USERNAME }} --password ${{ secrets.APPLE_NOTARIZATION_PASSWORD }} --team-id ${{ secrets.APPLE_DEVELOPMENT_TEAM }}
+          xcrun notarytool submit build/${{env.ARTIFACT_NAME}} --keychain-profile GameNotarizationProfile --wait
+
+      - name: Staple
+        run: xcrun stapler staple build/${{env.ARTIFACT_NAME}}
+
+      - name: Upload
+        uses: actions/upload-artifact@v3
+        with:
+          name: ${{env.ARTIFACT_NAME}}
+          path: build/${{env.ARTIFACT_NAME}}
--- /dev/null
+++ b/.github/workflows/release-windows.yml
@@ -1,0 +1,58 @@
+name: Release Windows
+
+on: [workflow_dispatch, workflow_call]
+
+env:
+  SDL2_VERSION: "2.26.3"
+  GAME_SHORTNAME: "CandyCrisis"
+  GAME_LONGNAME: "Candy Crisis"
+
+jobs:
+  release-windows:
+    runs-on: windows-2022
+    timeout-minutes: 20
+
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+        with:
+          submodules: 'recursive'
+
+      - name: Get SDL
+        run: |
+          Invoke-WebRequest -OutFile SDL2-VC.zip -Uri https://github.com/libsdl-org/SDL/releases/download/release-${{env.SDL2_VERSION}}/SDL2-devel-${{env.SDL2_VERSION}}-VC.zip
+          Expand-Archive SDL2-VC.zip
+          move SDL2-VC/SDL2-* SDL2
+
+      - name: Configure
+        run: cmake -S . -B build -G 'Visual Studio 17 2022'
+
+      - name: Prepare artifact names
+        run: |
+          $GAME_VERSION = Get-Content build/version.txt
+          $FOLDER_NAME = "${{env.GAME_LONGNAME}} $GAME_VERSION"
+          $ARTIFACT_NAME = "${{env.GAME_SHORTNAME}}-$GAME_VERSION-windows-x64.zip"
+          echo "GAME_VERSION=$GAME_VERSION" >> $env:GITHUB_ENV
+          echo "FOLDER_NAME=$FOLDER_NAME" >> $env:GITHUB_ENV
+          echo "ARTIFACT_NAME=$ARTIFACT_NAME" >> $env:GITHUB_ENV
+
+      - name: Build
+        run: cmake --build build --config Release -- -m
+
+      # Note: if the game contains C++, you should also copy msvcp140.dll and vcruntime140_1.dll
+      - name: Copy extra stuff
+        run: |
+          cmake --install build --prefix build/install
+          copy build/ReadMe.txt build/Release
+          copy build/install/bin/vcruntime140.dll build/Release
+
+      - name: Zip it up
+        run: |
+          move build/Release "build/${{env.FOLDER_NAME}}"
+          Compress-Archive -Path "build/${{env.FOLDER_NAME}}" -DestinationPath build/${{env.ARTIFACT_NAME}} -CompressionLevel Optimal
+
+      - name: Upload
+        uses: actions/upload-artifact@v3
+        with:
+          name: ${{env.ARTIFACT_NAME}}
+          path: build/${{env.ARTIFACT_NAME}}
--- a/.github/workflows/release.yml
+++ /dev/null
@@ -1,128 +1,0 @@
-name: Make Release Builds
-
-on: [workflow_dispatch]
-
-jobs:
-  build-linux-appimage:
-    runs-on: ubuntu-20.04  # Use oldest distro still supported by GitHub to cover the oldest possible glibc
-    timeout-minutes: 20
-
-    steps:
-      - name: Checkout
-        uses: actions/checkout@v3  # Checks out repository under $GITHUB_WORKSPACE so the job can access it
-        with:
-          submodules: 'recursive'
-
-      - name: Get CPU count
-        run: |
-          NPROC=$(python3 -c 'import multiprocessing; print(multiprocessing.cpu_count())')
-          echo "NPROC=$NPROC" >> $GITHUB_ENV
-          echo CPU count = $NPROC
-
-      - name: Get build dependencies for SDL from APT  # cf. https://github.com/libsdl-org/SDL/blob/main/docs/README-linux.md
-        run: |
-          sudo apt update
-          sudo apt install -y libasound2-dev libpulse-dev \
-            libaudio-dev libjack-dev libsndio-dev libsamplerate0-dev libx11-dev libxext-dev \
-            libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev libwayland-dev \
-            libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev \
-            libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev fcitx-libs-dev
-
-      - name: Configure
-        run: cmake -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
-
-      - name: Build
-        run: cmake --build build -- -j ${{ env.NPROC }}
-
-      - name: Prepare AppDir
-        run: bash packaging/prepare_appimage_appdir.sh build/CandyCrisis
-
-      - name: Make AppImage
-        run: |
-          wget https://github.com/AppImage/AppImageKit/releases/download/13/appimagetool-x86_64.AppImage
-          chmod +x appimagetool-x86_64.AppImage
-          ./appimagetool-x86_64.AppImage --no-appstream build/CandyCrisis.AppDir build/CandyCrisis-linux-x86_64.AppImage
-
-      - name: Upload
-        uses: actions/upload-artifact@v3
-        with:
-          name: CandyCrisis-linux-x86_64.AppImage
-          path: build/CandyCrisis-linux-x86_64.AppImage
-          
-  build-windows:
-    runs-on: windows-2022
-    timeout-minutes: 20
-
-    steps:
-      - name: Checkout
-        uses: actions/checkout@v3
-        with:
-          submodules: 'recursive'
-          
-      - name: Configure
-        run: cmake -S . -B build -G 'Visual Studio 17 2022'
-
-      - name: Build
-        run: cmake --build build --config Release -- -m
-
-      - name: Copy vcredist
-        run: |
-          cmake --install build --prefix build/install
-          copy build/ReadMe.txt build/Release
-          copy build/install/bin/vcruntime140.dll build/Release
-
-      - name: Upload
-        uses: actions/upload-artifact@v3
-        with:
-          name: CandyCrisis-windows-x64
-          path: build/Release
-
-  build-macos:
-    runs-on: macos-11
-    timeout-minutes: 20
-
-    steps:
-      - name: Import codesigning certs
-        uses: apple-actions/import-codesign-certs@v1
-        with:
-          p12-file-base64: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 }}
-          p12-password: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_PASSWORD }}
-
-      - name: Get CPU count
-        run: |
-          NPROC=$(python3 -c 'import multiprocessing; print(multiprocessing.cpu_count())')
-          echo "NPROC=$NPROC" >> $GITHUB_ENV
-          echo CPU count = $NPROC
-
-      - name: Checkout
-        uses: actions/checkout@v3
-        with:
-          submodules: 'recursive'
-
-      - name: Configure
-        run: cmake -S . -B build -G Xcode
-
-      - name: Build
-        run: cmake --build build --config RelWithDebInfo -- -j ${{ env.NPROC }}
-
-      - name: Codesign
-        run: codesign --force --sign ${{ secrets.APPLE_DEVELOPMENT_TEAM }} --options runtime "build/RelWithDebInfo/Candy Crisis.app"
-      
-      - name: Create dmg
-        run: |
-          cp build/ReadMe.txt build/RelWithDebInfo
-          hdiutil create -fs HFS+ -srcfolder build/RelWithDebInfo -volname "Candy Crisis" build/CandyCrisis-mac.dmg
-
-      - name: Notarize
-        run: |
-          xcrun notarytool store-credentials MyNotarizationProfileName --apple-id ${{ secrets.APPLE_NOTARIZATION_USERNAME }} --password ${{ secrets.APPLE_NOTARIZATION_PASSWORD }} --team-id ${{ secrets.APPLE_DEVELOPMENT_TEAM }}
-          xcrun notarytool submit build/CandyCrisis-mac.dmg --keychain-profile MyNotarizationProfileName --wait
-
-      - name: Staple
-        run: xcrun stapler staple build/CandyCrisis-mac.dmg
-
-      - name: Upload
-        uses: actions/upload-artifact@v3
-        with:
-          name: CandyCrisis-mac.dmg
-          path: build/CandyCrisis-mac.dmg
--- a/.gitignore
+++ b/.gitignore
@@ -4,4 +4,6 @@
 /dist
 /extern
 
+/SDL*
+
 .DS_Store
--- /dev/null
+++ b/BUILD.md
@@ -1,0 +1,60 @@
+# How to build Candy Crisis from source
+
+## macOS
+
+Prerequisites: Xcode, git, cmake (install via homebrew)
+
+Build recipe:
+
+```bash
+git clone https://github.com/jorio/CandyCrisis
+cd CandyCrisis
+
+curl -LO https://github.com/libsdl-org/SDL/releases/download/release-2.26.3/SDL2-2.26.3.dmg
+hdiutil attach SDL2-*.dmg
+cp -a /Volumes/SDL2/SDL2.framework SDL2.framework
+hdiutil detach /Volumes/SDL2
+
+cmake -S . -B build -G Xcode
+cmake --build build --config Release
+```
+
+## Windows
+
+Prerequisites: Visual Studio 2022, git, cmake
+
+Build recipe (to run in PowerShell):
+```bash
+git clone https://github.com/jorio/CandyCrisis
+cd CandyCrisis
+
+Invoke-WebRequest -OutFile SDL2-VC.zip -Uri https://github.com/libsdl-org/SDL/releases/download/release-2.26.3/SDL2-devel-2.26.3-VC.zip
+Expand-Archive SDL2-VC.zip
+move SDL2-VC/SDL2-* SDL2
+
+cmake -S . -B build -G 'Visual Studio 17 2022'
+cmake --build build --config Release
+```
+
+## Linux
+
+Prerequisites: a decent C compiler, git, cmake, and your platform's SDL2 development package
+
+```bash
+git clone https://github.com/jorio/CandyCrisis
+cd CandyCrisis
+cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
+cmake --build build
+```
+
+Or, if you want to build SDL from source and link it statically:
+
+```bash
+git clone https://github.com/jorio/CandyCrisis
+cd CandyCrisis
+
+git clone --depth 1 --branch release-2.26.3 https://github.com/libsdl-org/SDL
+
+cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_SDL_FROM_SOURCE=1 -DSTATIC_SDL=1
+cmake --build build
+```
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,8 +1,17 @@
-cmake_minimum_required(VERSION 3.16)  # Oldest supported Ubuntu is 20.04, which ships with cmake 3.16
+if(APPLE OR WIN32)
+	cmake_minimum_required(VERSION 3.21)
+else()
+	# Oldest supported Ubuntu is 20.04, which ships with cmake 3.16.
+	# When we can stop supporting Ubuntu 20.04, bump to CMake 3.21.
+	cmake_minimum_required(VERSION 3.16)
+endif()
 
 set(GAME_TARGET "CandyCrisis")
-set(GAME_MAC_BUNDLE_ID "io.jor.candycrisis")
+set(GAME_FRIENDLY_NAME "Candy Crisis")
+set(GAME_BUNDLE_ID "io.jor.candycrisis")
+set(GAME_MAC_COPYRIGHT "https://github.com/jorio/CandyCrisis")
 
+# Apply macOS deployment target and architectures to all subprojects
 set(CMAKE_OSX_DEPLOYMENT_TARGET "10.11" CACHE STRING "Minimum macOS deployment version")
 set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "Target macOS architectures")
 
@@ -13,16 +22,23 @@
 	set(CMAKE_C_STANDARD	17)
 endif()
 
-project(
-	${GAME_TARGET} LANGUAGES C CXX
-	VERSION 3.0.0
-	)
+project(${GAME_TARGET} LANGUAGES C
+	VERSION 3.0.0)
 
-
-
 # Create an option to switch between a system sdl library and a vendored sdl library
-option(SYSTEM_SDL "Use system SDL" OFF)
+option(BUILD_SDL_FROM_SOURCE "Build SDL from source" OFF)
+option(STATIC_SDL "Static link SDL" OFF)
+option(SANITIZE "Build with asan/ubsan" OFF)
+set(CODE_SIGN_IDENTITY "" CACHE STRING "macOS code signing identity. If omitted, the app won't be signed.")
 
+if(NOT WIN32 AND NOT APPLE)
+	if(SANITIZE)
+		message("Sanitizers enabled")
+	else()
+		message("Sanitizers disabled (pass -DSANITIZE=1 to enable)")
+	endif()
+endif()
+
 # Set Visual Studio startup project
 set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${GAME_TARGET})
 
@@ -32,14 +48,37 @@
 # FIND SDL
 #------------------------------------------------------------------------------
 
-if(SYSTEM_SDL)
+# If SDL2_DIR wasn't specified, discover if the user put some prebuilt SDL2 package in the project's root directory
+if(NOT DEFINED SDL2_DIR)
+	if(APPLE)
+		set(_sdl2_maybe "${CMAKE_SOURCE_DIR}/SDL2.framework/Resources/CMake")
+	elseif(WIN32)
+		set(_sdl2_maybe "${CMAKE_SOURCE_DIR}/SDL2/cmake")
+	endif()
+
+	if(DEFINED _sdl2_maybe AND EXISTS "${_sdl2_maybe}")
+		set(SDL2_DIR "${_sdl2_maybe}")
+	else()
+		message("Couldn't find prebuilt SDL2 package in: ${_sdl2_maybe}")
+	endif()
+	unset(_sdl2_maybe)
+endif()
+
+if(NOT BUILD_SDL_FROM_SOURCE)
 	# 1. Look for an SDL2 package, 2. look for the SDL2 component and 3. fail if none can be found
-	find_package(SDL2 REQUIRED CONFIG REQUIRED COMPONENTS SDL2)
-	
+	find_package(SDL2 CONFIG REQUIRED COMPONENTS SDL2)
+
 	# 1. Look for an SDL2 package, 2. Look for the SDL2maincomponent and 3. DO NOT fail when SDL2main is not available 
 	find_package(SDL2 REQUIRED CONFIG COMPONENTS SDL2main)
+
+	message("Found pre-built SDL: " ${SDL2_PREFIX})
 else()
-	add_subdirectory(SDL EXCLUDE_FROM_ALL)
+	if(NOT DEFINED SDL2_DIR)
+		set(SDL2_DIR "${CMAKE_SOURCE_DIR}/SDL")
+	endif()
+	
+	message("Building SDL from source: " ${SDL2_DIR})
+	add_subdirectory("${SDL2_DIR}" EXCLUDE_FROM_ALL)
 endif()
 
 #------------------------------------------------------------------------------
@@ -49,11 +88,15 @@
 # Write header file containing version info
 configure_file(${GAME_SOURCE_DIR}/version.h.in ${GAME_SOURCE_DIR}/version.h)
 
+# Readme file containing version info
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/packaging/ReadMe.txt.in ${CMAKE_CURRENT_BINARY_DIR}/ReadMe.txt)
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/packaging/version.txt.in ${CMAKE_CURRENT_BINARY_DIR}/version.txt)
+
 #------------------------------------------------------------------------------
 # EXECUTABLE TARGET
 #------------------------------------------------------------------------------
 
-
 file(GLOB_RECURSE GAME_SOURCES CONFIGURE_DEPENDS ${GAME_SOURCE_DIR}/*.cpp ${GAME_SOURCE_DIR}/*.c ${GAME_SOURCE_DIR}/*.h)
 
 if(WIN32)
@@ -61,19 +104,16 @@
 elseif(APPLE)
 	list(APPEND GAME_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/packaging/app.icns)
 	set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/packaging/app.icns PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
-else()
-	# Math lib, explicitly required on some Linux systems
-	#list(APPEND GAME_LIBRARIES m)
 endif()
 
+# Executable
 add_executable(${GAME_TARGET} ${GAME_SOURCES})
 
 target_include_directories(${GAME_TARGET} PRIVATE ${GAME_SOURCE_DIR})
 
-
-if (APPLE)
-	set_target_properties(${GAME_TARGET} PROPERTIES
-		OUTPUT_NAME		"Candy Crisis")
+# Create macOS app bundle with friendly name
+if(APPLE)
+	set_target_properties(${GAME_TARGET} PROPERTIES OUTPUT_NAME "${GAME_FRIENDLY_NAME}")
 endif()
 
 set_target_properties(${GAME_TARGET} PROPERTIES
@@ -89,36 +129,103 @@
 	# APPLE
 	#--------------------------------------------------------------------------
 
-	# Set framework search path to (App bundle)/Contents/Frameworks so the game can use its embedded SDL2.framework
-	XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/../Frameworks"
-
-	# Explicitly turn off code signing, otherwise downloaded app will be quarantined forever
-	XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY ""
-
 	# Build it as an .app bundle
 	MACOSX_BUNDLE						TRUE
 
 	# Set up Info.plist values
 	MACOSX_BUNDLE_ICON_FILE				"app.icns"	# CFBundleIconFile
-	MACOSX_BUNDLE_EXECUTABLE_NAME		${GAME_TARGET}			# CFBundleExecutable - executable name inside the bundle
-	MACOSX_BUNDLE_SHORT_VERSION_STRING	${PROJECT_VERSION}		# CFBundleShortVersionString
-#	MACOSX_BUNDLE_COPYRIGHT				${GAME_MAC_COPYRIGHT}	# NSHumanReadableCopyright (supersedes CFBundleGetInfoString (MACOSX_BUNDLE_INFO_STRING))
-	MACOSX_BUNDLE_BUNDLE_NAME			"Candy Crisis"			# CFBundleName - user-visible short name for the bundle
-	MACOSX_BUNDLE_GUI_IDENTIFIER		${GAME_MAC_BUNDLE_ID}	# CFBundleIdentifier - unique bundle ID in reverse-DNS format
+	MACOSX_BUNDLE_EXECUTABLE_NAME		"${GAME_TARGET}"		# CFBundleExecutable - executable name inside the bundle
+	MACOSX_BUNDLE_SHORT_VERSION_STRING	"${PROJECT_VERSION}"	# CFBundleShortVersionString
+	MACOSX_BUNDLE_COPYRIGHT				"${GAME_MAC_COPYRIGHT}"	# NSHumanReadableCopyright (supersedes CFBundleGetInfoString (MACOSX_BUNDLE_INFO_STRING))
+	MACOSX_BUNDLE_BUNDLE_NAME			"${GAME_FRIENDLY_NAME}"	# CFBundleName - user-visible short name for the bundle
+	MACOSX_BUNDLE_GUI_IDENTIFIER		"${GAME_BUNDLE_ID}"		# CFBundleIdentifier - unique bundle ID in reverse-DNS format
 
+	# Set framework search path to (App bundle)/Contents/Frameworks so the game can use its embedded SDL2.framework
+	XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/../Frameworks"
+
+	# If CODE_SIGN_IDENTITY is NOT empty: tell Xcode to codesign the app properly
+	# Otherwise, if it's empty: explicitly turn off code signing, otherwise downloaded app will be quarantined forever
+	XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${CODE_SIGN_IDENTITY}"
+	XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY[variant=Debug] ""		# don't bother signing debug build
+
 	# Bundle ID required for code signing - must match CFBundleIdentifier otherwise xcode will complain
-	XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER ${GAME_MAC_BUNDLE_ID}
+	XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER ${GAME_BUNDLE_ID}
 
 	# Don't bother with universal builds when we're working on the debug version
 	XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH[variant=Debug] "YES"
 
-	XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME			"YES"		# required for notarization to pass
+	XCODE_EMBED_FRAMEWORKS							"${SDL2_FRAMEWORK_PATH}"
+	XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY		"YES"		# frameworks must be signed by the same developer as the binary
+	XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY	"YES"		# not strictly necessary, but that's cleaner
+	XCODE_ATTRIBUTE_COPY_PHASE_STRIP[variant=Debug]	"NO"		# avoid "skipping copy phase strip" warning while working on Debug config
+
+	# The following is to pass notarization requirements
+	XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME			"YES"
+	XCODE_ATTRIBUTE_CODE_SIGN_INJECT_BASE_ENTITLEMENTS "NO"
+	XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS			"--options=runtime --timestamp"
 )
 
 #------------------------------------------------------------------------------
+# COMPILER/LINKER OPTIONS
+#------------------------------------------------------------------------------
+
+add_compile_definitions(
+	"$<$<CONFIG:DEBUG>:_DEBUG>"
+)
+
+if(NOT MSVC)
+	target_compile_options(${GAME_TARGET} PRIVATE
+		-Wall
+		-Wextra
+		-Wshadow
+		-Werror=return-type
+		-Wstrict-aliasing=2
+	)
+
+	# Sanitizers in debug mode (Linux only)
+	# When using a debugger, you should export LSAN_OPTIONS=detect_leaks=0
+	if(SANITIZE)
+		list(INSERT GAME_LIBRARIES 0 asan ubsan)
+		target_compile_options(${GAME_TARGET} PRIVATE
+			-fsanitize=alignment
+			-fsanitize=address
+			-fsanitize=leak
+			-fsanitize=undefined
+			-fno-omit-frame-pointer
+		)
+	endif()
+else()
+	# On Win32, we need NOGDI and NOUSER to be able to define some Mac functions
+	# whose names are otherwise taken by Windows APIs.
+	target_compile_definitions(${GAME_TARGET} PRIVATE
+		WIN32_LEAN_AND_MEAN
+		_CRT_SECURE_NO_WARNINGS		# quit whining about snprintf_s
+	)
+
+	target_compile_options(${GAME_TARGET} PRIVATE
+		/W4
+		/wd5105 # see https://developercommunity.visualstudio.com/t/1249671
+		/MP		# multiprocessor build
+		/Zi		# output info to PDB
+	)
+
+	# Let executable be debugged with PDB, even in Release builds
+	target_link_options(${GAME_TARGET} PRIVATE /DEBUG)
+
+	# Enable console for debug builds
+	set_target_properties(${GAME_TARGET} PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE")
+	set_target_properties(${GAME_TARGET} PROPERTIES COMPILE_DEFINITIONS_DEBUG "_CONSOLE")
+endif()
+
+#------------------------------------------------------------------------------
 # LINK LIBRARIES
 #------------------------------------------------------------------------------
 
+# Explicitly link math lib on Linux
+if(NOT APPLE AND NOT WIN32)
+	target_link_libraries(${GAME_TARGET} PRIVATE m)
+endif()
+
 # SDL2::SDL2main may or may not be available. It is e.g. required by Windows GUI applications  
 if(TARGET SDL2::SDL2main)
 	# It has an implicit dependency on SDL2 functions, so it MUST be added before SDL2::SDL2 (or SDL2::SDL2-static)
@@ -125,7 +232,7 @@
 	target_link_libraries(${GAME_TARGET} PRIVATE SDL2::SDL2main)
 endif()
 
-if(SYSTEM_SDL)
+if(NOT STATIC_SDL)
 	target_link_libraries(${GAME_TARGET} PRIVATE SDL2::SDL2)
 else()
 	target_link_libraries(${GAME_TARGET} PRIVATE SDL2::SDL2-static)
@@ -136,23 +243,25 @@
 #------------------------------------------------------------------------------
 
 if(APPLE)
-	set(GAME_DATA_TARGET_LOCATION "$<TARGET_FILE_DIR:${PROJECT_NAME}>/../Resources")
+	set(GAME_DATA_TARGET_LOCATION "$<TARGET_FILE_DIR:${GAME_TARGET}>/../Resources")
 else()
-	set(GAME_DATA_TARGET_LOCATION "$<TARGET_FILE_DIR:${PROJECT_NAME}>/CandyCrisisResources")
+	set(GAME_DATA_TARGET_LOCATION "$<TARGET_FILE_DIR:${GAME_TARGET}>/CandyCrisisResources")
 endif()
 
 add_custom_command(TARGET ${GAME_TARGET} POST_BUILD
 	COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/CandyCrisisResources" "${GAME_DATA_TARGET_LOCATION}")
 
+# Copy SDL2 DLL for convenience (WARNING: TARGET_RUNTIME_DLLS requires CMake 3.21, so this copy command was separated from the command above.)
+if(WIN32)
+	add_custom_command(TARGET ${GAME_TARGET} POST_BUILD
+		COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_RUNTIME_DLLS:${GAME_TARGET}> $<TARGET_FILE_DIR:${GAME_TARGET}>)
+endif()
+
 #------------------------------------------------------------------------------
 # INSTALL
 #------------------------------------------------------------------------------
 
-# Install Windows-specific libraries
+# Install Windows-specific libraries (cmake --install): copy Visual Studio redistributable DLLs to install location
 if(WIN32)
-	# When installing (cmake --install), copy Visual Studio redistributable DLLs to install location
 	include(InstallRequiredSystemLibraries)
 endif()
-
-# Copy documentation to output folder
-configure_file(${CMAKE_CURRENT_SOURCE_DIR}/packaging/ReadMe.txt.in ${CMAKE_CURRENT_BINARY_DIR}/ReadMe.txt)
--- a/README.md
+++ b/README.md
@@ -8,19 +8,7 @@
 
 ## How to build from source
 
-Prerequisites:
-- macOS: git, cmake, Xcode
-- Windows: git, cmake, Visual Studio 2022
-- Others: git, cmake, and a decent C++20 toolchain
-
-Build recipe:
-
-```bash
-git clone --recurse-submodules https://github.com/jorio/CandyCrisis
-cd CandyCrisis
-cmake -S . -B build
-cmake --build build
-```
+See [BUILD.md](BUILD.md)
 
 ## Credits/license
 
--- /dev/null
+++ b/packaging/version.txt.in
@@ -1,0 +1,1 @@
+@PROJECT_VERSION@
\ No newline at end of file