diff --git a/.github/actions/setup-ninja/action.yml b/.github/actions/setup-ninja/action.yml
new file mode 100644
index 00000000..b5d5fad0
--- /dev/null
+++ b/.github/actions/setup-ninja/action.yml
@@ -0,0 +1,62 @@
+name: 'Setup ninja'
+description: 'Download ninja and add it to the PATH environment variable'
+inputs:
+ version:
+ description: 'Ninja version'
+ default: '1.12.1'
+runs:
+ using: 'composite'
+ steps:
+ - name: 'Calculate variables'
+ id: calc
+ shell: sh
+ run: |
+ case "${{ runner.os }}-${{ runner.arch }}" in
+ "Linux-X86" | "Linux-X64")
+ archive="ninja-linux.zip"
+ ;;
+ "Linux-ARM64")
+ archive="ninja-linux-aarch64.zip"
+ ;;
+ "macOS-X86" | "macOS-X64" | "macOS-ARM64")
+ archive="ninja-mac.zip"
+ ;;
+ "Windows-X86" | "Windows-X64")
+ archive="ninja-win.zip"
+ ;;
+ "Windows-ARM64")
+ archive="ninja-winarm64.zip"
+ ;;
+ *)
+ echo "Unsupported ${{ runner.os }}-${{ runner.arch }}"
+ exit 1;
+ ;;
+ esac
+ echo "archive=${archive}" >> ${GITHUB_OUTPUT}
+ echo "cache-key=${archive}-${{ inputs.version }}-${{ runner.os }}-${{ runner.arch }}" >> ${GITHUB_OUTPUT}
+ - name: 'Restore cached ${{ steps.calc.outputs.archive }}'
+ id: cache-restore
+ uses: actions/cache/restore@v4
+ with:
+ path: '${{ runner.temp }}/${{ steps.calc.outputs.archive }}'
+ key: ${{ steps.calc.outputs.cache-key }}
+ - name: 'Download ninja ${{ inputs.version }} for ${{ runner.os }} (${{ runner.arch }})'
+ if: ${{ (!steps.cache-restore.outputs.cache-hit || steps.cache-restore.outputs.cache-hit == 'false') }}
+ shell: pwsh
+ run: |
+ Invoke-WebRequest "https://github.com/ninja-build/ninja/releases/download/v${{ inputs.version }}/${{ steps.calc.outputs.archive }}" -OutFile "${{ runner.temp }}/${{ steps.calc.outputs.archive }}"
+ - name: 'Cache ${{ steps.calc.outputs.archive }}'
+ if: ${{ (!steps.cache-restore.outputs.cache-hit || steps.cache-restore.outputs.cache-hit == 'false') }}
+ uses: actions/cache/save@v4
+ with:
+ path: '${{ runner.temp }}/${{ steps.calc.outputs.archive }}'
+ key: ${{ steps.calc.outputs.cache-key }}
+ - name: 'Extract ninja'
+ shell: pwsh
+ run: |
+ 7z "-o${{ runner.temp }}/ninja-${{ inputs.version }}-${{ runner.arch }}" x "${{ runner.temp }}/${{ steps.calc.outputs.archive }}"
+ - name: 'Set output variables'
+ id: final
+ shell: pwsh
+ run: |
+ echo "${{ runner.temp }}/ninja-${{ inputs.version }}-${{ runner.arch }}" >> $env:GITHUB_PATH
diff --git a/.github/fetch_sdl_vc.ps1 b/.github/fetch_sdl_vc.ps1
deleted file mode 100644
index 83d4db70..00000000
--- a/.github/fetch_sdl_vc.ps1
+++ /dev/null
@@ -1,40 +0,0 @@
-$ErrorActionPreference = "Stop"
-
-$project_root = "$psScriptRoot\.."
-Write-Output "project_root: $project_root"
-
-$sdl3_version = "3.0.0"
-$sdl3_zip = "SDL3-devel-$($sdl3_version)-VC.zip"
-
-$sdl3_url = "https://github.com/libsdl-org/SDL/releases/download/release-$($sdl3_version)/SDL3-devel-$($sdl3_version)-VC.zip"
-$sdl3_dlpath = "$($Env:TEMP)\$sdl3_zip"
-
-$sdl3_bindir = "$($project_root)"
-$sdl3_extractdir = "$($sdl3_bindir)\SDL3-$($sdl3_version)"
-$sdl3_root_name = "SDL3-devel-VC"
-
-echo "sdl3_bindir: $sdl3_bindir"
-echo "sdl3_extractdir: $sdl3_extractdir"
-echo "sdl3_root_name: $sdl3_root_name"
-
-echo "Cleaning previous artifacts"
-if (Test-Path $sdl3_extractdir) {
- Remove-Item $sdl3_extractdir -Recurse -Force
-}
-if (Test-Path "$($sdl3_bindir)/$sdl3_root_name") {
- Remove-Item "$($sdl3_bindir)/$sdl3_root_name" -Recurse -Force
-}
-if (Test-Path $sdl3_dlpath) {
- Remove-Item $sdl3_dlpath -Force
-}
-
-Write-Output "Downloading $sdl3_url"
-Invoke-WebRequest -Uri $sdl3_url -OutFile $sdl3_dlpath
-
-Write-Output "Extracting archive"
-Expand-Archive $sdl3_dlpath -DestinationPath $sdl3_bindir
-
-Write-Output "Setting up SDL3 folder"
-Rename-Item $sdl3_extractdir $sdl3_root_name
-
-Write-Output "Done"
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 00000000..b94a5523
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,735 @@
+name: 'release'
+run-name: 'Create SDL_image release artifacts for ${{ inputs.commit }}'
+
+on:
+ workflow_dispatch:
+ inputs:
+ commit:
+ description: 'Commit of SDL_image'
+ required: true
+
+jobs:
+
+ src:
+ runs-on: ubuntu-latest
+ outputs:
+ project: ${{ steps.releaser.outputs.project }}
+ version: ${{ steps.releaser.outputs.version }}
+ src-tar-gz: ${{ steps.releaser.outputs.src-tar-gz }}
+ src-tar-xz: ${{ steps.releaser.outputs.src-tar-xz }}
+ src-zip: ${{ steps.releaser.outputs.src-zip }}
+ steps:
+ - name: 'Set up Python'
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.11'
+ - name: 'Fetch build-release.py'
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ inputs.commit }}
+ sparse-checkout: 'build-scripts/build-release.py'
+ - name: 'Set up SDL sources'
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ inputs.commit }}
+ path: 'SDL'
+ fetch-depth: 0
+ - name: 'Build Source archive'
+ id: releaser
+ shell: bash
+ env:
+ GH_TOKEN: ${{ github.token }}
+ run: |
+ python build-scripts/build-release.py \
+ --actions source \
+ --commit ${{ inputs.commit }} \
+ --root "${{ github.workspace }}/SDL" \
+ --github \
+ --debug
+ - name: 'Store source archives'
+ uses: actions/upload-artifact@v4
+ with:
+ name: sources
+ path: '${{ github.workspace}}/dist'
+
+ linux-verify:
+ needs: [src]
+ runs-on: ubuntu-latest
+ steps:
+ - name: 'Set up Python'
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.11'
+ - name: 'Download source archives'
+ uses: actions/download-artifact@v4
+ with:
+ name: sources
+ path: '/tmp'
+ - name: 'Unzip ${{ needs.src.outputs.src-zip }}'
+ id: zip
+ run: |
+ set -e
+ mkdir /tmp/zipdir
+ cd /tmp/zipdir
+ unzip "/tmp/${{ needs.src.outputs.src-zip }}"
+ echo "path=/tmp/zipdir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT
+ - name: 'Untar ${{ needs.src.outputs.src-tar-gz }}'
+ id: tar
+ run: |
+ set -e
+ mkdir -p /tmp/tardir
+ tar -C /tmp/tardir -v -x -f "/tmp/${{ needs.src.outputs.src-tar-gz }}"
+ echo "path=/tmp/tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT
+ - name: 'Compare contents of ${{ needs.src.outputs.src-zip }} and ${{ needs.src.outputs.src-tar-gz }}'
+ run: |
+ set -e
+ diff "${{ steps.zip.outputs.path }}" "${{ steps.tar.outputs.path }}"
+ - name: 'Test versioning'
+ shell: bash
+ run: |
+ ${{ steps.tar.outputs.path }}/build-scripts/test-versioning.sh
+ - name: 'Fetch build-release.py'
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ inputs.commit }}
+ sparse-checkout: 'build-scripts/build-release.py'
+ - name: 'Download dependencies'
+ id: deps
+ env:
+ GH_TOKEN: ${{ github.token }}
+ run: |
+ python build-scripts/build-release.py \
+ --actions download \
+ --commit ${{ inputs.commit }} \
+ --root "${{ steps.tar.outputs.path }}" \
+ --github \
+ --debug
+ - name: 'Extract dependencies, build and install them'
+ id: deps-build
+ run: |
+ tar -C /tmp -v -x -f "${{ steps.deps.outputs.dep-path }}/SDL3-${{ steps.deps.outputs.dep-sdl-version }}.tar.xz"
+ cmake -S /tmp/SDL3-${{ steps.deps.outputs.dep-sdl-version }} -B /tmp/SDL-build -DCMAKE_INSTALL_PREFIX=/tmp/deps-prefix
+ cmake --build /tmp/SDL-build
+ cmake --install /tmp/SDL-build
+ echo "path=/tmp/deps-prefix" >>$GITHUB_OUTPUT
+ - name: 'CMake (configure + build)'
+ run: |
+ cmake \
+ -S ${{ steps.tar.outputs.path }} \
+ -B /tmp/build \
+ -DSDL3IMAGE_SAMPLES=ON \
+ -DSDL3IMAGE_TESTS=ON \
+ -DCMAKE_PREFIX_PATH="${{ steps.deps-build.outputs.path }}"
+ cmake --build /tmp/build --verbose
+ # ctest --test-dir /tmp/build --no-tests=error --output-on-failure
+
+ dmg:
+ needs: [src]
+ runs-on: macos-latest
+ outputs:
+ dmg: ${{ steps.releaser.outputs.dmg }}
+ steps:
+ - name: 'Set up Python'
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.11'
+ - name: 'Fetch build-release.py'
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ inputs.commit }}
+ sparse-checkout: 'build-scripts/build-release.py'
+ - name: 'Install nasm'
+ run: |
+ brew install nasm
+ - name: 'Download source archives'
+ uses: actions/download-artifact@v4
+ with:
+ name: sources
+ path: '${{ github.workspace }}'
+ - name: 'Untar ${{ needs.src.outputs.src-tar-gz }}'
+ id: tar
+ run: |
+ mkdir -p "${{ github.workspace }}/tardir"
+ tar -C "${{ github.workspace }}/tardir" -v -x -f "${{ github.workspace }}/${{ needs.src.outputs.src-tar-gz }}"
+ echo "path=${{ github.workspace }}/tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT
+ - name: 'Download external dependencies'
+ run: |
+ sh "${{ steps.tar.outputs.path }}/external/download.sh" --depth 1
+ - name: 'Build SDL3_image.dmg'
+ id: releaser
+ shell: bash
+ env:
+ GH_TOKEN: ${{ github.token }}
+ run: |
+ python build-scripts/build-release.py \
+ --actions dmg \
+ --commit ${{ inputs.commit }} \
+ --root "${{ steps.tar.outputs.path }}" \
+ --github \
+ --debug
+ - name: 'Store DMG image file'
+ uses: actions/upload-artifact@v4
+ with:
+ name: dmg
+ path: '${{ github.workspace }}/dist'
+
+ dmg-verify:
+ needs: [dmg, src]
+ runs-on: macos-latest
+ steps:
+ - name: 'Set up Python'
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.11'
+ - name: 'Fetch build-release.py'
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ inputs.commit }}
+ sparse-checkout: 'build-scripts/build-release.py'
+ - name: 'Download source archives'
+ uses: actions/download-artifact@v4
+ with:
+ name: sources
+ path: '${{ github.workspace }}'
+ - name: 'Untar ${{ needs.src.outputs.src-tar-gz }}'
+ id: src
+ run: |
+ mkdir -p /tmp/tardir
+ tar -C /tmp/tardir -v -x -f "${{ github.workspace }}/${{ needs.src.outputs.src-tar-gz }}"
+ echo "path=/tmp/tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT
+ - name: 'Download dependencies'
+ id: deps
+ env:
+ GH_TOKEN: ${{ github.token }}
+ run: |
+ python build-scripts/build-release.py \
+ --actions download \
+ --commit ${{ inputs.commit }} \
+ --root "${{ steps.src.outputs.path }}" \
+ --github \
+ --debug
+ - name: 'Mount dependencies'
+ id: deps-mount
+ run: |
+ hdiutil attach "${{ steps.deps.outputs.dep-path }}/SDL3-${{ steps.deps.outputs.dep-sdl-version }}.dmg"
+ sdl_mount_pount="/Volumes/SDL3"
+ if [ ! -d "$sdl_mount_pount/SDL3.xcframework" ]; then
+ echo "Cannot find SDL3.xcframework!"
+ exit 1
+ fi
+ echo "path=${sdl_mount_pount}" >>$GITHUB_OUTPUT
+ - name: 'Download ${{ needs.dmg.outputs.dmg }}'
+ uses: actions/download-artifact@v4
+ with:
+ name: dmg
+ path: '${{ github.workspace }}'
+ - name: 'Mount ${{ needs.dmg.outputs.dmg }}'
+ id: mount
+ run: |
+ hdiutil attach '${{ github.workspace }}/${{ needs.dmg.outputs.dmg }}'
+ mount_point="/Volumes/${{ needs.src.outputs.project }}"
+ if [ ! -d "$mount_point/${{ needs.src.outputs.project }}.xcframework" ]; then
+ echo "Cannot find ${{ needs.src.outputs.project }}.xcframework!"
+ exit 1
+ fi
+ echo "mount-point=${mount_point}">>$GITHUB_OUTPUT
+ - name: 'Verify presence of optional frameworks'
+ run: |
+ OPTIONAL_FRAMEWORKS="avif jxl webp"
+ rc=0
+ for opt in $OPTIONAL_FRAMEWORKS; do
+ fw_path="${{ steps.mount.outputs.mount-point }}/optional/${opt}.xcframework"
+ if [ -d "${fw_path}" ]; then
+ echo "$fw_path OK"
+ else
+ echo "$fw_path MISSING"
+ rc=1
+ fi
+ done
+ exit $rc
+ - name: 'CMake (configure + build) Darwin'
+ run: |
+ set -e
+ cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
+ -DTEST_SHARED=TRUE \
+ -DTEST_SHARED=TRUE \
+ -DTEST_STATIC=FALSE \
+ -DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }};${{ steps.deps-mount.outputs.path }}" \
+ -DCMAKE_SYSTEM_NAME=Darwin \
+ -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
+ -Werror=dev \
+ -B build_darwin
+ cmake --build build_darwin --config Release --verbose
+
+ - name: 'CMake (configure + build) iOS'
+ run: |
+ cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
+ -DTEST_SHARED=TRUE \
+ -DTEST_STATIC=FALSE \
+ -DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }};${{ steps.deps-mount.outputs.path }}" \
+ -DCMAKE_SYSTEM_NAME=iOS \
+ -DCMAKE_OSX_ARCHITECTURES="arm64" \
+ -Werror=dev \
+ -B build_ios
+ cmake --build build_ios --config Release --verbose
+ - name: 'CMake (configure + build) tvOS'
+ run: |
+ cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
+ -DTEST_SHARED=TRUE \
+ -DTEST_STATIC=FALSE \
+ -DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }};${{ steps.deps-mount.outputs.path }}" \
+ -DCMAKE_SYSTEM_NAME=tvOS \
+ -DCMAKE_OSX_ARCHITECTURES="arm64" \
+ -Werror=dev \
+ -B build_tvos
+ cmake --build build_tvos --config Release --verbose
+ - name: 'CMake (configure + build) iOS simulator'
+ run: |
+ sysroot=$(xcodebuild -version -sdk iphonesimulator Path)
+ echo "sysroot=$sysroot"
+ cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
+ -DTEST_SHARED=TRUE \
+ -DTEST_STATIC=FALSE \
+ -DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }};${{ steps.deps-mount.outputs.path }}" \
+ -DCMAKE_SYSTEM_NAME=iOS \
+ -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
+ -DCMAKE_OSX_SYSROOT="${sysroot}" \
+ -Werror=dev \
+ -B build_ios_simulator
+ cmake --build build_ios_simulator --config Release --verbose
+ - name: 'CMake (configure + build) tvOS simulator'
+ run: |
+ sysroot=$(xcodebuild -version -sdk appletvsimulator Path)
+ echo "sysroot=$sysroot"
+ cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
+ -DTEST_SHARED=TRUE \
+ -DTEST_STATIC=FALSE \
+ -DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount-point }};${{ steps.deps-mount.outputs.path }}" \
+ -DCMAKE_SYSTEM_NAME=tvOS \
+ -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
+ -DCMAKE_OSX_SYSROOT="${sysroot}" \
+ -Werror=dev \
+ -B build_tvos_simulator
+ cmake --build build_tvos_simulator --config Release --verbose
+ msvc:
+ needs: [src]
+ runs-on: windows-2019
+ outputs:
+ VC-x86: ${{ steps.releaser.outputs.VC-x86 }}
+ VC-x64: ${{ steps.releaser.outputs.VC-x64 }}
+ VC-devel: ${{ steps.releaser.outputs.VC-devel }}
+ steps:
+ - name: 'Set up Python'
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.11'
+ - name: 'Fetch build-release.py'
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ inputs.commit }}
+ sparse-checkout: 'build-scripts/build-release.py'
+ - name: 'Download source archives'
+ uses: actions/download-artifact@v4
+ with:
+ name: sources
+ path: '${{ github.workspace }}'
+ - name: 'Unzip ${{ needs.src.outputs.src-zip }}'
+ id: zip
+ run: |
+ New-Item C:\temp -ItemType Directory -ErrorAction SilentlyContinue
+ cd C:\temp
+ unzip "${{ github.workspace }}/${{ needs.src.outputs.src-zip }}"
+ echo "path=C:\temp\${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$Env:GITHUB_OUTPUT
+ - name: 'Download external dependencies'
+ run: |
+ ${{ steps.zip.outputs.path }}/external/Get-GitModules.ps1
+ - name: 'Build MSVC binary archives'
+ id: releaser
+ env:
+ GH_TOKEN: ${{ github.token }}
+ run: |
+ python build-scripts/build-release.py `
+ --actions download msvc `
+ --commit ${{ inputs.commit }} `
+ --root "${{ steps.zip.outputs.path }}" `
+ --github `
+ --debug
+ - name: 'Store MSVC archives'
+ uses: actions/upload-artifact@v4
+ with:
+ name: msvc
+ path: '${{ github.workspace }}/dist'
+
+ msvc-verify:
+ needs: [msvc, src]
+ runs-on: windows-latest
+ steps:
+ - name: 'Fetch .github/actions/setup-ninja/action.yml'
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ inputs.commit }}
+ sparse-checkout: |
+ .github/actions/setup-ninja/action.yml
+ build-scripts/build-release.py
+ - name: 'Set up Python'
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.11'
+ - name: Set up ninja
+ uses: ./.github/actions/setup-ninja
+ - name: 'Download source archives'
+ uses: actions/download-artifact@v4
+ with:
+ name: sources
+ path: '${{ github.workspace }}'
+ - name: 'Unzip ${{ needs.src.outputs.src-zip }}'
+ id: src
+ run: |
+ mkdir '${{ github.workspace }}/sources'
+ cd '${{ github.workspace }}/sources'
+ unzip "${{ github.workspace }}/${{ needs.src.outputs.src-zip }}"
+ echo "path=${{ github.workspace }}/sources/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$env:GITHUB_OUTPUT
+ - name: 'Download dependencies'
+ id: deps
+ env:
+ GH_TOKEN: ${{ github.token }}
+ run: |
+ python build-scripts/build-release.py `
+ --actions download `
+ --commit ${{ inputs.commit }} `
+ --root "${{ steps.src.outputs.path }}" `
+ --github `
+ --debug
+ - name: 'Extract dependencies'
+ id: deps-extract
+ run: |
+ mkdir '${{ github.workspace }}/deps-vc'
+ cd '${{ github.workspace }}/deps-vc'
+ unzip "${{ steps.deps.outputs.dep-path }}/SDL3-devel-${{ steps.deps.outputs.dep-sdl-version }}-VC.zip"
+ echo "path=${{ github.workspace }}/deps-vc" >>$env:GITHUB_OUTPUT
+ - name: 'Download MSVC binaries'
+ uses: actions/download-artifact@v4
+ with:
+ name: msvc
+ path: '${{ github.workspace }}'
+ - name: 'Unzip ${{ needs.msvc.outputs.VC-devel }}'
+ id: bin
+ run: |
+ mkdir '${{ github.workspace }}/vc'
+ cd '${{ github.workspace }}/vc'
+ unzip "${{ github.workspace }}/${{ needs.msvc.outputs.VC-devel }}"
+ echo "path=${{ github.workspace }}/vc/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$env:GITHUB_OUTPUT
+ - name: 'Configure vcvars x86'
+ uses: ilammy/msvc-dev-cmd@v1
+ with:
+ arch: x64_x86
+ - name: 'CMake (configure + build + tests) x86'
+ run: |
+ cmake -S "${{ steps.src.outputs.path }}/cmake/test" `
+ -B build_x86 `
+ -GNinja `
+ -DCMAKE_BUILD_TYPE=Debug `
+ -Werror=dev `
+ -DTEST_SHARED=TRUE `
+ -DTEST_STATIC=FALSE `
+ -DCMAKE_SUPPRESS_REGENERATION=TRUE `
+ -DCMAKE_PREFIX_PATH="${{ steps.bin.outputs.path }};${{ steps.deps-extract.outputs.path }}"
+ Start-Sleep -Seconds 2
+ cmake --build build_x86 --config Release --verbose
+ - name: 'Configure vcvars x64'
+ uses: ilammy/msvc-dev-cmd@v1
+ with:
+ arch: x64
+ - name: 'CMake (configure + build + tests) x64'
+ run: |
+ cmake -S "${{ steps.src.outputs.path }}/cmake/test" `
+ -B build_x64 `
+ -GNinja `
+ -DCMAKE_BUILD_TYPE=Debug `
+ -Werror=dev `
+ -DTEST_SHARED=TRUE `
+ -DTEST_STATIC=FALSE `
+ -DCMAKE_SUPPRESS_REGENERATION=TRUE `
+ -DCMAKE_PREFIX_PATH="${{ steps.bin.outputs.path }};${{ steps.deps-extract.outputs.path }}"
+ Start-Sleep -Seconds 2
+ cmake --build build_x64 --config Release --verbose
+ - name: 'Configure vcvars arm64'
+ uses: ilammy/msvc-dev-cmd@v1
+ with:
+ arch: x64_arm64
+ - name: 'CMake (configure + build + tests) arm64'
+ run: |
+ cmake -S "${{ steps.src.outputs.path }}/cmake/test" `
+ -B build_arm64 `
+ -GNinja `
+ -DCMAKE_BUILD_TYPE=Debug `
+ -Werror=dev `
+ -DTEST_SHARED=TRUE `
+ -DTEST_STATIC=FALSE `
+ -DCMAKE_SUPPRESS_REGENERATION=TRUE `
+ -DCMAKE_PREFIX_PATH="${{ steps.bin.outputs.path }};${{ steps.deps-extract.outputs.path }}"
+ Start-Sleep -Seconds 2
+ cmake --build build_arm64 --config Release --verbose
+
+ mingw:
+ needs: [src]
+ runs-on: ubuntu-24.04 # FIXME: current ubuntu-latest ships an outdated mingw, replace with ubuntu-latest once 24.04 becomes the new default
+ outputs:
+ mingw-devel-tar-gz: ${{ steps.releaser.outputs.mingw-devel-tar-gz }}
+ mingw-devel-tar-xz: ${{ steps.releaser.outputs.mingw-devel-tar-xz }}
+ steps:
+ - name: 'Set up Python'
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.11'
+ - name: 'Fetch build-release.py'
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ inputs.commit }}
+ sparse-checkout: 'build-scripts/build-release.py'
+ - name: 'Install Mingw toolchain'
+ run: |
+ sudo apt-get update -y
+ sudo apt-get install -y gcc-mingw-w64 g++-mingw-w64 ninja-build
+ - name: 'Download source archives'
+ uses: actions/download-artifact@v4
+ with:
+ name: sources
+ path: '${{ github.workspace }}'
+ - name: 'Untar ${{ needs.src.outputs.src-tar-gz }}'
+ id: tar
+ run: |
+ mkdir -p /tmp/tardir
+ tar -C /tmp/tardir -v -x -f "${{ github.workspace }}/${{ needs.src.outputs.src-tar-gz }}"
+ echo "path=/tmp/tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT
+ - name: 'Build MinGW binary archives'
+ id: releaser
+ env:
+ GH_TOKEN: ${{ github.token }}
+ run: |
+ python build-scripts/build-release.py \
+ --actions download mingw \
+ --commit ${{ inputs.commit }} \
+ --root "${{ steps.tar.outputs.path }}" \
+ --github \
+ --debug
+ - name: 'Store MinGW archives'
+ uses: actions/upload-artifact@v4
+ with:
+ name: mingw
+ path: '${{ github.workspace }}/dist'
+
+ mingw-verify:
+ needs: [mingw, src]
+ runs-on: ubuntu-latest
+ steps:
+ - name: 'Set up Python'
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.11'
+ - name: 'Fetch build-release.py'
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ inputs.commit }}
+ sparse-checkout: 'build-scripts/build-release.py'
+ - name: 'Install Mingw toolchain'
+ run: |
+ sudo apt-get update -y
+ sudo apt-get install -y gcc-mingw-w64 g++-mingw-w64 ninja-build
+ - name: 'Download source archives'
+ uses: actions/download-artifact@v4
+ with:
+ name: sources
+ path: '${{ github.workspace }}'
+ - name: 'Untar ${{ needs.src.outputs.src-tar-gz }}'
+ id: src
+ run: |
+ mkdir -p /tmp/tardir
+ tar -C /tmp/tardir -v -x -f "${{ github.workspace }}/${{ needs.src.outputs.src-tar-gz }}"
+ echo "path=/tmp/tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT
+ - name: 'Download dependencies'
+ id: deps
+ env:
+ GH_TOKEN: ${{ github.token }}
+ run: |
+ python build-scripts/build-release.py \
+ --actions download \
+ --commit ${{ inputs.commit }} \
+ --root "${{ steps.src.outputs.path }}" \
+ --github \
+ --debug
+ - name: 'Untar and install dependencies'
+ id: deps-extract
+ run: |
+ mkdir -p /tmp/deps-mingw/cmake
+ mkdir -p /tmp/deps-mingw/i686-w64-mingw32
+ mkdir -p /tmp/deps-mingw/x86_64-w64-mingw32
+
+ mkdir -p /tmp/deps-mingw-extract/sdl3
+ tar -C /tmp/deps-mingw-extract/sdl3 -v -x -f "${{ steps.deps.outputs.dep-path }}/SDL3-devel-${{ steps.deps.outputs.dep-sdl-version }}-mingw.tar.xz"
+ make -C /tmp/deps-mingw-extract/sdl3/SDL3-${{ steps.deps.outputs.dep-sdl-version }} install-all DESTDIR=/tmp/deps-mingw
+
+ # FIXME: this should be fixed in SDL3 releases after 3.1.3
+ mkdir -p /tmp/deps-mingw/cmake
+ cp -rv /tmp/deps-mingw-extract/sdl3/SDL3-${{ steps.deps.outputs.dep-sdl-version }}/cmake/* /tmp/deps-mingw/cmake
+ - name: 'Download MinGW binaries'
+ uses: actions/download-artifact@v4
+ with:
+ name: mingw
+ path: '${{ github.workspace }}'
+ - name: 'Untar and install ${{ needs.mingw.outputs.mingw-devel-tar-gz }}'
+ id: bin
+ run: |
+ mkdir -p /tmp/mingw-tardir
+ tar -C /tmp/mingw-tardir -v -x -f "${{ github.workspace }}/${{ needs.mingw.outputs.mingw-devel-tar-gz }}"
+ make -C /tmp/mingw-tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }} install-all DESTDIR=/tmp/deps-mingw
+ - name: 'CMake (configure + build) i686'
+ run: |
+ set -e
+ cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
+ -DCMAKE_BUILD_TYPE="Release" \
+ -DTEST_SHARED=TRUE \
+ -DTEST_STATIC=TRUE \
+ -DCMAKE_PREFIX_PATH="/tmp/deps-mingw" \
+ -DCMAKE_TOOLCHAIN_FILE="${{ steps.src.outputs.path }}/build-scripts/cmake-toolchain-mingw64-i686.cmake" \
+ -Werror=dev \
+ -B build_x86
+ cmake --build build_x86 --config Release --verbose
+ - name: 'CMake (configure + build) x86_64'
+ run: |
+ set -e
+ cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
+ -DCMAKE_BUILD_TYPE="Release" \
+ -DTEST_SHARED=TRUE \
+ -DTEST_STATIC=TRUE \
+ -DCMAKE_PREFIX_PATH="/tmp/deps-mingw" \
+ -DCMAKE_TOOLCHAIN_FILE="${{ steps.src.outputs.path }}/build-scripts/cmake-toolchain-mingw64-x86_64.cmake" \
+ -Werror=dev \
+ -B build_x64
+ cmake --build build_x64 --config Release --verbose
+
+ android:
+ needs: [src]
+ runs-on: ubuntu-latest
+ outputs:
+ android-aar: ${{ steps.releaser.outputs.android-aar }}
+ steps:
+ - name: 'Set up Python'
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.11'
+ - name: 'Fetch build-release.py'
+ uses: actions/checkout@v4
+ with:
+ sparse-checkout: 'build-scripts/build-release.py'
+ - name: 'Setup Android NDK'
+ uses: nttld/setup-ndk@v1
+ with:
+ local-cache: true
+ ndk-version: r21e
+ - name: 'Setup Java JDK'
+ uses: actions/setup-java@v4
+ with:
+ distribution: 'temurin'
+ java-version: '11'
+ - name: 'Install ninja'
+ run: |
+ sudo apt-get update -y
+ sudo apt-get install -y ninja-build
+ - name: 'Download source archives'
+ uses: actions/download-artifact@v4
+ with:
+ name: sources
+ path: '${{ github.workspace }}'
+ - name: 'Untar ${{ needs.src.outputs.src-tar-gz }}'
+ id: tar
+ run: |
+ mkdir -p /tmp/tardir
+ tar -C /tmp/tardir -v -x -f "${{ github.workspace }}/${{ needs.src.outputs.src-tar-gz }}"
+ echo "path=/tmp/tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT
+ - name: 'Build Android prefab binary archive(s)'
+ id: releaser
+ env:
+ GH_TOKEN: ${{ github.token }}
+ run: |
+ python build-scripts/build-release.py \
+ --actions download android \
+ --commit ${{ inputs.commit }} \
+ --root "${{ steps.tar.outputs.path }}" \
+ --github \
+ --debug
+ - name: 'Store Android archive(s)'
+ uses: actions/upload-artifact@v4
+ with:
+ name: android
+ path: '${{ github.workspace }}/dist'
+
+ android-verify:
+ needs: [android, src]
+ runs-on: ubuntu-latest
+ steps:
+ - name: 'Set up Python'
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.11'
+ - uses: actions/setup-java@v4
+ with:
+ distribution: 'temurin'
+ java-version: '17'
+ - name: 'Download source archives'
+ uses: actions/download-artifact@v4
+ with:
+ name: sources
+ path: '${{ github.workspace }}'
+ - name: 'Download Android .aar archive'
+ uses: actions/download-artifact@v4
+ with:
+ name: android
+ path: '${{ github.workspace }}'
+ - name: 'Untar ${{ needs.src.outputs.src-tar-gz }}'
+ id: src
+ run: |
+ mkdir -p /tmp/tardir
+ tar -C /tmp/tardir -v -x -f "${{ github.workspace }}/${{ needs.src.outputs.src-tar-gz }}"
+ echo "path=/tmp/tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT
+ - name: 'Extract Android SDK from AAR'
+ id: sdk
+ run: |
+ python "${{ github.workspace }}/${{ needs.android.outputs.android-aar }}" -o /tmp/deps-android
+ - name: 'Download dependencies'
+ id: deps
+ env:
+ GH_TOKEN: ${{ github.token }}
+ run: |
+ python "${{ steps.src.outputs.path }}/build-scripts/build-release.py" \
+ --actions download \
+ --commit ${{ inputs.commit }} \
+ --root "${{ steps.src.outputs.path }}" \
+ --github \
+ --debug
+ - name: 'Extract dependencies'
+ id: deps-extract
+ run: |
+ python "${{ steps.deps.outputs.dep-path }}/SDL3-${{ steps.deps.outputs.dep-sdl-version }}.aar" -o /tmp/deps-android
+ - name: 'Install ninja'
+ run: |
+ sudo apt-get update -y
+ sudo apt-get install -y ninja-build
+ - name: 'CMake (configure + build) x86, x64, arm32, arm64'
+ run: |
+ android_abis="x86 x86_64 armeabi-v7a arm64-v8a"
+ for android_abi in ${android_abis}; do
+ echo "Configuring ${android_abi}..."
+ cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
+ -GNinja \
+ -DTEST_FULL=TRUE \
+ -DTEST_STATIC=FALSE \
+ -DCMAKE_PREFIX_PATH="/tmp/deps-android" \
+ -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake \
+ -DANDROID_ABI=${android_abi} \
+ -Werror=dev \
+ -DCMAKE_BUILD_TYPE=Release \
+ -B "${android_abi}"
+ echo "Building ${android_abi}..."
+ cmake --build "${android_abi}" --config Release --verbose
+ done
diff --git a/.gitignore b/.gitignore
index 461b42f8..f4eb9a94 100644
--- a/.gitignore
+++ b/.gitignore
@@ -55,3 +55,4 @@ Release
*.ncb
*.suo
*.sdf
+Xcode/build.xcconfig
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5611f006..e43eb833 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,7 +6,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
set(MAJOR_VERSION 3)
set(MINOR_VERSION 0)
set(MICRO_VERSION 0)
-set(SDL_REQUIRED_VERSION 3.0.0)
+set(SDL_REQUIRED_VERSION 3.1.3)
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
message(FATAL_ERROR "Prevented in-tree built. Please create a build directory outside of the SDL_image source code and call cmake from there")
@@ -289,21 +289,6 @@ set_target_properties(${sdl3_image_target_name} PROPERTIES
C_VISIBILITY_PRESET "hidden"
)
-if (MSVC AND CMAKE_BUILD_TYPE MATCHES "Release")
- target_compile_options(${sdl3_image_target_name} PRIVATE /Zi)
-
- # Tell linker to include symbol data
- set_target_properties(${sdl3_image_target_name} PROPERTIES
- LINK_FLAGS "/INCREMENTAL:NO /DEBUG /OPT:REF /OPT:ICF"
- )
-
- # Set file name & location
- set_target_properties(${sdl3_image_target_name} PROPERTIES
- COMPILE_PDB_NAME ${sdl3_image_target_name}
- COMPILE_PDB_OUTPUT_DIR ${CMAKE_BINARY_DIR}
- )
-endif()
-
sdl_target_link_option_version_file(${sdl3_image_target_name} "${CMAKE_CURRENT_SOURCE_DIR}/src/SDL_image.sym")
if(NOT ANDROID)
@@ -1038,6 +1023,7 @@ if(SDLIMAGE_INSTALL)
endif()
configure_package_config_file(cmake/SDL3_imageConfig.cmake.in SDL3_imageConfig.cmake
+ NO_SET_AND_CHECK_MACRO
INSTALL_DESTINATION "${SDLIMAGE_INSTALL_CMAKEDIR}"
)
write_basic_package_version_file("${PROJECT_BINARY_DIR}/SDL3_imageConfigVersion.cmake"
diff --git a/VisualC/SDL_image.vcxproj b/VisualC/SDL_image.vcxproj
index 98b04cd5..041bc2ab 100644
--- a/VisualC/SDL_image.vcxproj
+++ b/VisualC/SDL_image.vcxproj
@@ -1,5 +1,8 @@
+
+ $(ProjectDir)
+
Debug
@@ -44,32 +47,16 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
<_ProjectFileVersion>10.0.40219.1
- $(SolutionDir)\$(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\
$(Platform)\$(Configuration)\
- $(SolutionDir)\$(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\
$(Platform)\$(Configuration)\
- $(SolutionDir)\$(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\
$(Platform)\$(Configuration)\
- $(SolutionDir)\$(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\
$(Platform)\$(Configuration)\
AllRules.ruleset
@@ -85,20 +72,20 @@
- $(ProjectDir)..\include;$(SolutionDir)..\external\SDL\include;$(IncludePath)
- $(SolutionDir)$(PlatformName)\$(Configuration);$(LibraryPath)
+ $(ProjectDir)..\include;$(ProjectDir)..\..\SDL\include;$(IncludePath)
+ $(SolutionDir)$(PlatformName)\$(Configuration);$(ProjectDir)..\..\SDL\VisualC\$(PlatformName)\$(Configuration);$(LibraryPath)
- $(ProjectDir)..\include;$(SolutionDir)..\external\SDL\include;$(IncludePath)
- $(SolutionDir)$(PlatformName)\$(Configuration);$(LibraryPath)
+ $(ProjectDir)..\include;$(ProjectDir)..\..\SDL\include;$(IncludePath)
+ $(SolutionDir)$(PlatformName)\$(Configuration);$(ProjectDir)..\..\SDL\VisualC\$(PlatformName)\$(Configuration);$(LibraryPath)
- $(ProjectDir)..\include;$(SolutionDir)..\external\SDL\include;$(IncludePath)
- $(SolutionDir)$(PlatformName)\$(Configuration);$(LibraryPath)
+ $(ProjectDir)..\include;$(ProjectDir)..\..\SDL\include;$(IncludePath)
+ $(SolutionDir)$(PlatformName)\$(Configuration);$(ProjectDir)..\..\SDL\VisualC\$(PlatformName)\$(Configuration);$(LibraryPath)
- $(ProjectDir)..\include;$(SolutionDir)..\external\SDL\include;$(IncludePath)
- $(SolutionDir)$(PlatformName)\$(Configuration);$(LibraryPath)
+ $(ProjectDir)..\include;$(ProjectDir)..\..\SDL\include;$(IncludePath)
+ $(SolutionDir)$(PlatformName)\$(Configuration);$(ProjectDir)..\..\SDL\VisualC\$(PlatformName)\$(Configuration);$(LibraryPath)
@@ -106,7 +93,7 @@
true
true
Win32
- .\Debug/SDL3_image.tlb
+ ./$(Configuration)/$(Platform)/SDL3_image.tlb
@@ -127,7 +114,6 @@
true
Windows
-
@@ -135,7 +121,7 @@
true
true
X64
- .\Debug/SDL3_image.tlb
+ ./$(Configuration)/$(Platform)/SDL3_image.tlb
@@ -156,7 +142,6 @@
true
Windows
-
@@ -164,7 +149,7 @@
true
true
Win32
- .\Release/SDL3_image.tlb
+ ./$(Configuration)/$(Platform)/SDL3_image.tlb
@@ -182,7 +167,6 @@
SDL3.lib;%(AdditionalDependencies)
Windows
-
@@ -190,7 +174,7 @@
true
true
X64
- .\Release/SDL3_image.tlb
+ ./$(Configuration)/$(Platform)/SDL3_image.tlb
@@ -208,7 +192,6 @@
Windows
SDL3.lib;%(AdditionalDependencies)
-
@@ -233,154 +216,149 @@
-
+
-
-
- {81ce8daf-ebb2-4761-8e45-b71abcca8c68}
-
-
Document
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
Document
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
Document
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
Document
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
+ Copying %(Filename)%(Extension)
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
+ Copying %(Filename)%(Extension)
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
+
+
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
+ Copying %(Filename)%(Extension)
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
+ Copying %(Filename)%(Extension)
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
+
+
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
+ Copying %(Filename)%(Extension)
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
+ Copying %(Filename)%(Extension)
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
+
+
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
+ Copying %(Filename)%(Extension)
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
+ Copying %(Filename)%(Extension)
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
+
+
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
+
+
Document
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
Document
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
Document
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
Document
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
-
-
-
-
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
- Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
- Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
-
-
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
- Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
- Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
-
-
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
- Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
- Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
-
-
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
- Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
- Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
- copy %(FullPath) $(SolutionDir)\$(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ copy %(FullPath) $(SolutionDir)$(Platform)\$(Configuration)\
Copying %(Filename)%(Extension)
- $(SolutionDir)\$(Platform)\$(Configuration)\%(Filename)%(Extension)
+ $(SolutionDir)$(Platform)\$(Configuration)\%(Filename)%(Extension)
diff --git a/VisualC/SDL_image.vcxproj.filters b/VisualC/SDL_image.vcxproj.filters
index 36156e59..be762419 100644
--- a/VisualC/SDL_image.vcxproj.filters
+++ b/VisualC/SDL_image.vcxproj.filters
@@ -86,29 +86,6 @@
Sources
-
-
- x64
-
-
- x64
-
-
- x64
-
-
- x64
-
-
- x64
-
-
- x64
-
-
- x64
-
-
x64
@@ -116,24 +93,45 @@
x86
+
+ x64
+
x86
+
+ x64
+
x86
+
+ x64
+
x86
+
+ x64
+
x86
+
+ x64
+
x86
+
+ x64
+
x86
+
+ x64
+
x86
diff --git a/VisualC/pkg-support/cmake/sdl3_image-config-version.cmake b/VisualC/pkg-support/cmake/sdl3_image-config-version.cmake
deleted file mode 100644
index 7c01743e..00000000
--- a/VisualC/pkg-support/cmake/sdl3_image-config-version.cmake
+++ /dev/null
@@ -1,54 +0,0 @@
-# based on the files generated by CMake's write_basic_package_version_file
-
-# SDL3_image CMake version configuration file:
-# This file is meant to be placed in a cmake subfolder of SDL3_image-devel-3.x.y-VC
-
-if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/../include/SDL3_image/SDL_image.h")
- message(AUTHOR_WARNING "Could not find SDL3_image/SDL_image.h. This script is meant to be placed in a CMake subfolder of SDL3_image-devel-3.x.y-VC")
- return()
-endif()
-
-file(READ "${CMAKE_CURRENT_LIST_DIR}/../include/SDL3_image/SDL_image.h" _sdl_image_h)
-string(REGEX MATCH "#define[ \t]+SDL_IMAGE_MAJOR_VERSION[ \t]+([0-9]+)" _sdl_major_re "${_sdl_image_h}")
-set(_sdl_major "${CMAKE_MATCH_1}")
-string(REGEX MATCH "#define[ \t]+SDL_IMAGE_MINOR_VERSION[ \t]+([0-9]+)" _sdl_minor_re "${_sdl_image_h}")
-set(_sdl_minor "${CMAKE_MATCH_1}")
-string(REGEX MATCH "#define[ \t]+SDL_IMAGE_MICRO_VERSION[ \t]+([0-9]+)" _sdl_micro_re "${_sdl_image_h}")
-set(_sdl_micro "${CMAKE_MATCH_1}")
-if(_sdl_major_re AND _sdl_minor_re AND _sdl_micro_re)
- set(PACKAGE_VERSION "${_sdl_major}.${_sdl_minor}.${_sdl_micro}")
-else()
- message(AUTHOR_WARNING "Could not extract version from SDL_image.h.")
- return()
-endif()
-
-if(PACKAGE_FIND_VERSION_RANGE)
- # Package version must be in the requested version range
- if ((PACKAGE_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MIN)
- OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_GREATER PACKAGE_FIND_VERSION_MAX)
- OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_GREATER_EQUAL PACKAGE_FIND_VERSION_MAX)))
- set(PACKAGE_VERSION_COMPATIBLE FALSE)
- else()
- set(PACKAGE_VERSION_COMPATIBLE TRUE)
- endif()
-else()
- if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
- set(PACKAGE_VERSION_COMPATIBLE FALSE)
- else()
- set(PACKAGE_VERSION_COMPATIBLE TRUE)
- if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
- set(PACKAGE_VERSION_EXACT TRUE)
- endif()
- endif()
-endif()
-
-# if the using project doesn't have CMAKE_SIZEOF_VOID_P set, fail.
-if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "")
- set(PACKAGE_VERSION_UNSUITABLE TRUE)
-endif()
-
-# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
-if(NOT (CMAKE_SIZEOF_VOID_P STREQUAL "8" OR CMAKE_SIZEOF_VOID_P STREQUAL "4"))
- set(PACKAGE_VERSION "${PACKAGE_VERSION} (32+64bit)")
- set(PACKAGE_VERSION_UNSUITABLE TRUE)
-endif()
diff --git a/VisualC/pkg-support/cmake/sdl3_image-config.cmake b/VisualC/pkg-support/cmake/sdl3_image-config.cmake
deleted file mode 100644
index e26a5f8c..00000000
--- a/VisualC/pkg-support/cmake/sdl3_image-config.cmake
+++ /dev/null
@@ -1,73 +0,0 @@
-# SDL3_image CMake configuration file:
-# This file is meant to be placed in a cmake subfolder of SDL3_image-devel-3.x.y-VC
-
-include(FeatureSummary)
-set_package_properties(SDL3_image PROPERTIES
- URL "https://www.libsdl.org/projects/SDL_image/"
- DESCRIPTION "SDL_image is an image file loading library"
-)
-
-cmake_minimum_required(VERSION 3.0)
-
-set(SDL3_image_FOUND TRUE)
-
-set(SDLIMAGE_AVIF FALSE)
-set(SDLIMAGE_BMP TRUE)
-set(SDLIMAGE_GIF TRUE)
-set(SDLIMAGE_JPG TRUE)
-set(SDLIMAGE_JXL FALSE)
-set(SDLIMAGE_LBM TRUE)
-set(SDLIMAGE_PCX TRUE)
-set(SDLIMAGE_PNG TRUE)
-set(SDLIMAGE_PNM TRUE)
-set(SDLIMAGE_QOI TRUE)
-set(SDLIMAGE_SVG TRUE)
-set(SDLIMAGE_TGA TRUE)
-set(SDLIMAGE_TIF FALSE)
-set(SDLIMAGE_XCF FALSE)
-set(SDLIMAGE_XPM TRUE)
-set(SDLIMAGE_XV TRUE)
-set(SDLIMAGE_WEBP FALSE)
-
-set(SDLIMAGE_JPG_SAVE FALSE)
-set(SDLIMAGE_PNG_SAVE FALSE)
-
-set(SDLIMAGE_VENDORED FALSE)
-
-set(SDLIMAGE_BACKEND_IMAGEIO FALSE)
-set(SDLIMAGE_BACKEND_STB TRUE)
-set(SDLIMAGE_BACKEND_WIC FALSE)
-
-if(CMAKE_SIZEOF_VOID_P STREQUAL "4")
- set(_sdl_arch_subdir "x86")
-elseif(CMAKE_SIZEOF_VOID_P STREQUAL "8")
- set(_sdl_arch_subdir "x64")
-else()
- unset(_sdl_arch_subdir)
- set(SDL3_image_FOUND FALSE)
- return()
-endif()
-
-set(_sdl3image_incdir "${CMAKE_CURRENT_LIST_DIR}/../include")
-set(_sdl3image_library "${CMAKE_CURRENT_LIST_DIR}/../lib/${_sdl_arch_subdir}/SDL3_image.lib")
-set(_sdl3image_dll "${CMAKE_CURRENT_LIST_DIR}/../lib/${_sdl_arch_subdir}/SDL3_image.dll")
-
-# All targets are created, even when some might not be requested though COMPONENTS.
-# This is done for compatibility with CMake generated SDL3_image-target.cmake files.
-
-if(NOT TARGET SDL3_image::SDL3_image)
- add_library(SDL3_image::SDL3_image SHARED IMPORTED)
- set_target_properties(SDL3_image::SDL3_image
- PROPERTIES
- INTERFACE_INCLUDE_DIRECTORIES "${_sdl3image_incdir}"
- IMPORTED_IMPLIB "${_sdl3image_library}"
- IMPORTED_LOCATION "${_sdl3image_dll}"
- COMPATIBLE_INTERFACE_BOOL "SDL3_SHARED"
- INTERFACE_SDL3_SHARED "ON"
- )
-endif()
-
-unset(_sdl_arch_subdir)
-unset(_sdl3image_incdir)
-unset(_sdl3image_library)
-unset(_sdl3image_dll)
diff --git a/Xcode/SDL_image.xcodeproj/project.pbxproj b/Xcode/SDL_image.xcodeproj/project.pbxproj
index 3fcef8a6..61388c1b 100644
--- a/Xcode/SDL_image.xcodeproj/project.pbxproj
+++ b/Xcode/SDL_image.xcodeproj/project.pbxproj
@@ -566,7 +566,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "PRODUCT_NAME=SDL3_image\nOPTIONAL_FRAMEWORKS=\"avif jxl webp\"\n\nmkdir -p build/dmg-tmp\ncp -a build/$PRODUCT_NAME.xcframework build/dmg-tmp/\ncp pkg-support/resources/ReadMe.txt build/dmg-tmp\nfor i in $OPTIONAL_FRAMEWORKS; do\n if [ -d build/$i.xcframework ]; then\n mkdir -p build/dmg-tmp/optional\n cp -a build/$i.xcframework build/dmg-tmp/optional/\n fi\ndone\n\n# remove the .DS_Store files if any (we may want to provide one in the future for fancy .dmgs)\nrm -rf build/dmg-tmp/.DS_Store\n\n# create the dmg\nhdiutil create -ov -fs HFS+ -volname $PRODUCT_NAME -srcfolder build/dmg-tmp build/$PRODUCT_NAME.dmg\n\n# clean up\nrm -rf build/dmg-tmp\n";
+ shellScript = "set -ex\n\nPRODUCT_NAME=SDL3_image\nOPTIONAL_FRAMEWORKS=\"avif jxl webp\"\n\nmkdir -p build/dmg-tmp/share/cmake/$PRODUCT_NAME\ncp -a build/$PRODUCT_NAME.xcframework build/dmg-tmp/\ncp pkg-support/resources/ReadMe.txt build/dmg-tmp\ncp pkg-support/resources/share/cmake/${PRODUCT_NAME}/${PRODUCT_NAME}Config.cmake build/dmg-tmp/share/cmake/${PRODUCT_NAME}\ncp pkg-support/resources/share/cmake/${PRODUCT_NAME}/${PRODUCT_NAME}ConfigVersion.cmake build/dmg-tmp/share/cmake/${PRODUCT_NAME}\nfor i in $OPTIONAL_FRAMEWORKS; do\n if [ -d build/$i.xcframework ]; then\n mkdir -p build/dmg-tmp/optional\n cp -a build/$i.xcframework build/dmg-tmp/optional/\n fi\ndone\n\n# remove the .DS_Store files if any (we may want to provide one in the future for fancy .dmgs)\nrm -rf build/dmg-tmp/.DS_Store\n\n# create the dmg\nhdiutil create -ov -fs HFS+ -volname $PRODUCT_NAME -srcfolder build/dmg-tmp build/$PRODUCT_NAME.dmg\n\n# clean up\nrm -rf build/dmg-tmp\n";
};
/* End PBXShellScriptBuildPhase section */
diff --git a/Xcode/pkg-support/build.xcconfig b/Xcode/pkg-support/build.xcconfig
new file mode 100644
index 00000000..28fc1578
--- /dev/null
+++ b/Xcode/pkg-support/build.xcconfig
@@ -0,0 +1,21 @@
+//
+// build.xcconfig
+//
+
+// Configuration settings file format documentation can be found at:
+// https://help.apple.com/xcode/#/dev745c5c974
+
+// Uncomment these lines to enable AVIF support
+// If you do this, you should run external/download.sh to download the decode libraries and add avif.framework to your application bundle.
+AVIF_PREPROCESSOR_DEFINITIONS = LOAD_AVIF
+AVIF_FRAMEWORK_LDFLAGS = -weak_framework avif
+
+// Uncomment these lines to enable JPEG-XL support
+// If you do this, you should run external/download.sh to download the decode libraries and add jxl.framework to your application bundle.
+JXL_PREPROCESSOR_DEFINITIONS = LOAD_JXL
+JXL_FRAMEWORK_LDFLAGS = -weak_framework jxl
+
+// Uncomment these lines to enable WebP support
+// If you do this, you should run external/download.sh to download the decode libraries and add webp.framework to your application bundle.
+WEBP_PREPROCESSOR_DEFINITIONS = LOAD_WEBP
+WEBP_FRAMEWORK_LDFLAGS = -weak_framework webp
diff --git a/Xcode/pkg-support/resources/CMake/SDL3_imageConfig.cmake b/Xcode/pkg-support/resources/CMake/SDL3_imageConfig.cmake
new file mode 100644
index 00000000..16601673
--- /dev/null
+++ b/Xcode/pkg-support/resources/CMake/SDL3_imageConfig.cmake
@@ -0,0 +1,95 @@
+# SDL3_image CMake configuration file:
+# This file is meant to be placed in Resources/CMake of a SDL3_image framework
+
+# INTERFACE_LINK_OPTIONS needs CMake 3.12
+cmake_minimum_required(VERSION 3.12)
+
+include(FeatureSummary)
+set_package_properties(SDL3_image PROPERTIES
+ URL "https://www.libsdl.org/projects/SDL_image/"
+ DESCRIPTION "SDL_image is an image file loading library"
+)
+
+set(SDL3_image_FOUND TRUE)
+
+set(SDLIMAGE_AVIF TRUE)
+set(SDLIMAGE_BMP TRUE)
+set(SDLIMAGE_GIF TRUE)
+set(SDLIMAGE_JPG TRUE)
+set(SDLIMAGE_JXL TRUE)
+set(SDLIMAGE_LBM TRUE)
+set(SDLIMAGE_PCX TRUE)
+set(SDLIMAGE_PNG TRUE)
+set(SDLIMAGE_PNM TRUE)
+set(SDLIMAGE_QOI TRUE)
+set(SDLIMAGE_SVG TRUE)
+set(SDLIMAGE_TGA TRUE)
+set(SDLIMAGE_TIF TRUE)
+set(SDLIMAGE_XCF TRUE)
+set(SDLIMAGE_XPM TRUE)
+set(SDLIMAGE_XV TRUE)
+set(SDLIMAGE_WEBP TRUE)
+
+set(SDLIMAGE_JPG_SAVE TRUE)
+set(SDLIMAGE_PNG_SAVE TRUE)
+
+set(SDLIMAGE_VENDORED FALSE)
+
+set(SDLIMAGE_BACKEND_IMAGEIO TRUE)
+set(SDLIMAGE_BACKEND_STB FALSE)
+set(SDLIMAGE_BACKEND_WIC FALSE)
+
+# Compute the installation prefix relative to this file.
+set(_sdl3_image_framework_path "${CMAKE_CURRENT_LIST_DIR}") # > /SDL3_image.framework/Resources/CMake/
+get_filename_component(_sdl3_image_framework_path "${_sdl3_image_framework_path}" REALPATH) # > /SDL3_image.framework/Versions/Current/Resources/CMake
+get_filename_component(_sdl3_image_framework_path "${_sdl3_image_framework_path}" REALPATH) # > /SDL3_image.framework/Versions/A/Resources/CMake/
+get_filename_component(_sdl3_image_framework_path "${_sdl3_image_framework_path}" PATH) # > /SDL3_image.framework/Versions/A/Resources/
+get_filename_component(_sdl3_image_framework_path "${_sdl3_image_framework_path}" PATH) # > /SDL3_image.framework/Versions/A/
+get_filename_component(_sdl3_image_framework_path "${_sdl3_image_framework_path}" PATH) # > /SDL3_image.framework/Versions/
+get_filename_component(_sdl3_image_framework_path "${_sdl3_image_framework_path}" PATH) # > /SDL3_image.framework/
+get_filename_component(_sdl3_image_framework_parent_path "${_sdl3_image_framework_path}" PATH) # > /
+
+# All targets are created, even when some might not be requested though COMPONENTS.
+# This is done for compatibility with CMake generated SDL3_image-target.cmake files.
+
+if(NOT TARGET SDL3_image::SDL3_image-shared)
+ add_library(SDL3_image::SDL3_image-shared SHARED IMPORTED)
+ set_target_properties(SDL3_image::SDL3_image-shared
+ PROPERTIES
+ FRAMEWORK "TRUE"
+ IMPORTED_LOCATION "${_sdl3_image_framework_path}/SDL3_image"
+ COMPATIBLE_INTERFACE_BOOL "SDL3_SHARED"
+ INTERFACE_SDL3_SHARED "ON"
+ COMPATIBLE_INTERFACE_STRING "SDL_VERSION"
+ INTERFACE_SDL_VERSION "SDL3"
+ )
+endif()
+set(SDL3_image_SDL3_image-shared_FOUND TRUE)
+
+set(SDL3_image_SDL3_image-static FALSE)
+
+unset(_sdl3_image_framework_path)
+unset(_sdl3_image_framework_parent_path)
+
+if(SDL3_image_SDL3_image-shared_FOUND)
+ set(SDL3_image_SDL3_image_FOUND TRUE)
+endif()
+
+function(_sdl_create_target_alias_compat NEW_TARGET TARGET)
+ if(CMAKE_VERSION VERSION_LESS "3.18")
+ # Aliasing local targets is not supported on CMake < 3.18, so make it global.
+ add_library(${NEW_TARGET} INTERFACE IMPORTED)
+ set_target_properties(${NEW_TARGET} PROPERTIES INTERFACE_LINK_LIBRARIES "${TARGET}")
+ else()
+ add_library(${NEW_TARGET} ALIAS ${TARGET})
+ endif()
+endfunction()
+
+# Make sure SDL3_image::SDL3_image always exists
+if(NOT TARGET SDL3_image::SDL3_image)
+ if(TARGET SDL3_image::SDL3_image-shared)
+ _sdl_create_target_alias_compat(SDL3_image::SDL3_image SDL3_image::SDL3_image-shared)
+ endif()
+endif()
+
+check_required_components(SDL3_image)
diff --git a/Xcode/pkg-support/resources/CMake/sdl3_image-config-version.cmake b/Xcode/pkg-support/resources/CMake/SDL3_imageConfigVersion.cmake
similarity index 100%
rename from Xcode/pkg-support/resources/CMake/sdl3_image-config-version.cmake
rename to Xcode/pkg-support/resources/CMake/SDL3_imageConfigVersion.cmake
diff --git a/Xcode/pkg-support/resources/CMake/sdl3_image-config.cmake b/Xcode/pkg-support/resources/CMake/sdl3_image-config.cmake
deleted file mode 100644
index 307fd695..00000000
--- a/Xcode/pkg-support/resources/CMake/sdl3_image-config.cmake
+++ /dev/null
@@ -1,61 +0,0 @@
-# SDL3_image CMake configuration file:
-# This file is meant to be placed in Resources/CMake of a SDL3_image framework
-
-# INTERFACE_LINK_OPTIONS needs CMake 3.12
-cmake_minimum_required(VERSION 3.12)
-
-include(FeatureSummary)
-set_package_properties(SDL3_image PROPERTIES
- URL "https://www.libsdl.org/projects/SDL_image/"
- DESCRIPTION "SDL_image is an image file loading library"
-)
-
-set(SDL3_image_FOUND TRUE)
-
-set(SDLIMAGE_AVIF FALSE)
-set(SDLIMAGE_BMP TRUE)
-set(SDLIMAGE_GIF TRUE)
-set(SDLIMAGE_JPG TRUE)
-set(SDLIMAGE_JXL FALSE)
-set(SDLIMAGE_LBM TRUE)
-set(SDLIMAGE_PCX TRUE)
-set(SDLIMAGE_PNG TRUE)
-set(SDLIMAGE_PNM TRUE)
-set(SDLIMAGE_QOI TRUE)
-set(SDLIMAGE_SVG TRUE)
-set(SDLIMAGE_TGA TRUE)
-set(SDLIMAGE_TIF TRUE)
-set(SDLIMAGE_XCF TRUE)
-set(SDLIMAGE_XPM TRUE)
-set(SDLIMAGE_XV TRUE)
-set(SDLIMAGE_WEBP FALSE)
-
-set(SDLIMAGE_JPG_SAVE FALSE)
-set(SDLIMAGE_PNG_SAVE FALSE)
-
-set(SDLIMAGE_VENDORED FALSE)
-
-set(SDLIMAGE_BACKEND_IMAGEIO FALSE)
-set(SDLIMAGE_BACKEND_STB TRUE)
-set(SDLIMAGE_BACKEND_WIC FALSE)
-
-string(REGEX REPLACE "SDL3_image\\.framework.*" "SDL3_image.framework" _sdl3image_framework_path "${CMAKE_CURRENT_LIST_DIR}")
-string(REGEX REPLACE "SDL3_image\\.framework.*" "" _sdl3image_framework_parent_path "${CMAKE_CURRENT_LIST_DIR}")
-
-# All targets are created, even when some might not be requested though COMPONENTS.
-# This is done for compatibility with CMake generated SDL3_image-target.cmake files.
-
-if(NOT TARGET SDL3_image::SDL3_image)
- add_library(SDL3_image::SDL3_image INTERFACE IMPORTED)
- set_target_properties(SDL3_image::SDL3_image
- PROPERTIES
- INTERFACE_COMPILE_OPTIONS "SHELL:-F ${_sdl3image_framework_parent_path}"
- INTERFACE_INCLUDE_DIRECTORIES "${_sdl3image_framework_path}/Headers"
- INTERFACE_LINK_OPTIONS "SHELL:-F ${_sdl3image_framework_parent_path};SHELL:-framework SDL3_image"
- COMPATIBLE_INTERFACE_BOOL "SDL3_SHARED"
- INTERFACE_SDL3_SHARED "ON"
- )
-endif()
-
-unset(_sdl3image_framework_path)
-unset(_sdl3image_framework_parent_path)
diff --git a/Xcode/pkg-support/resources/share/cmake/SDL3_image/SDL3_imageConfig.cmake b/Xcode/pkg-support/resources/share/cmake/SDL3_image/SDL3_imageConfig.cmake
new file mode 100644
index 00000000..612f1ee5
--- /dev/null
+++ b/Xcode/pkg-support/resources/share/cmake/SDL3_image/SDL3_imageConfig.cmake
@@ -0,0 +1,174 @@
+# SDL3 CMake configuration file:
+# This file is meant to be placed in share/cmake/SDL3_image, next to SDL3_image.xcframework
+
+# INTERFACE_LINK_OPTIONS needs CMake 3.12
+cmake_minimum_required(VERSION 3.12)
+
+include(FeatureSummary)
+set_package_properties(SDL3_image PROPERTIES
+ URL "https://www.libsdl.org/projects/SDL_image/"
+ DESCRIPTION "SDL_image is an image file loading library"
+)
+
+# Copied from `configure_package_config_file`
+macro(set_and_check _var _file)
+ set(${_var} "${_file}")
+ if(NOT EXISTS "${_file}")
+ message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
+ endif()
+endmacro()
+
+# Copied from `configure_package_config_file`
+macro(check_required_components _NAME)
+ foreach(comp ${${_NAME}_FIND_COMPONENTS})
+ if(NOT ${_NAME}_${comp}_FOUND)
+ if(${_NAME}_FIND_REQUIRED_${comp})
+ set(${_NAME}_FOUND FALSE)
+ endif()
+ endif()
+ endforeach()
+endmacro()
+
+macro(_check_target_is_simulator)
+ set(src [===[
+ #include
+ #if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR
+ int target_is_simulator;
+ #endif
+ int main(int argc, char *argv[]) { return target_is_simulator; }
+ ]===])
+ if(CMAKE_C_COMPILER)
+ include(CheckCSourceCompiles)
+ check_c_source_compiles("${src}" SDL_TARGET_IS_SIMULATOR)
+ elseif(CMAKE_CXX_COMPILER)
+ include(CheckCXXSourceCompiles)
+ check_cxx_source_compiles("${src}" SDL_TARGET_IS_SIMULATOR)
+ else()
+ enable_language(C)
+ include(CheckCSourceCompiles)
+ check_c_source_compiles("${src}" SDL_TARGET_IS_SIMULATOR)
+ endif()
+endmacro()
+
+if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
+ _check_target_is_simulator()
+ if(SDL_TARGET_IS_SIMULATOR)
+ set(_xcfw_target_subdir "ios-arm64_x86_64-simulator")
+ else()
+ set(_xcfw_target_subdir "ios-arm64")
+ endif()
+elseif(CMAKE_SYSTEM_NAME STREQUAL "tvOS")
+ _check_target_is_simulator()
+ if(SDL_TARGET_IS_SIMULATOR)
+ set(_xcfw_target_subdir "tvos-arm64_x86_64-simulator")
+ else()
+ set(_xcfw_target_subdir "tvos-arm64")
+ endif()
+elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ set(_xcfw_target_subdir "macos-arm64_x86_64")
+else()
+ message(WARNING "Unsupported Apple platform (${CMAKE_SYSTEM_NAME}) and broken SDL3_imageConfigVersion.cmake")
+ set(SDL3_image_FOUND FALSE)
+ return()
+endif()
+
+# Compute the installation prefix relative to this file.
+get_filename_component(_sdl3_image_xcframework_parent_path "${CMAKE_CURRENT_LIST_DIR}" REALPATH) # /share/cmake/SDL3/
+get_filename_component(_sdl3_image_xcframework_parent_path "${_sdl3_image_xcframework_parent_path}" REALPATH) # /share/cmake/SDL3/
+get_filename_component(_sdl3_image_xcframework_parent_path "${_sdl3_image_xcframework_parent_path}" PATH) # /share/cmake
+get_filename_component(_sdl3_image_xcframework_parent_path "${_sdl3_image_xcframework_parent_path}" PATH) # /share
+get_filename_component(_sdl3_image_xcframework_parent_path "${_sdl3_image_xcframework_parent_path}" PATH) # /
+set_and_check(_sdl3_image_xcframework_path "${_sdl3_image_xcframework_parent_path}/SDL3_image.xcframework") # /SDL3_image.xcframework
+set_and_check(_sdl3_image_framework_parent_path "${_sdl3_image_xcframework_path}/${_xcfw_target_subdir}") # /SDL3_image.xcframework/macos-arm64_x86_64
+set_and_check(_sdl3_image_framework_path "${_sdl3_image_framework_parent_path}/SDL3_image.framework") # /SDL3_image.xcframework/macos-arm64_x86_64/SDL3_image.framework
+
+set(SDL3_image_FOUND TRUE)
+
+set(SDLIMAGE_AVIF TRUE)
+set(SDLIMAGE_BMP TRUE)
+set(SDLIMAGE_GIF TRUE)
+set(SDLIMAGE_JPG TRUE)
+set(SDLIMAGE_JXL TRUE)
+set(SDLIMAGE_LBM TRUE)
+set(SDLIMAGE_PCX TRUE)
+set(SDLIMAGE_PNG TRUE)
+set(SDLIMAGE_PNM TRUE)
+set(SDLIMAGE_QOI TRUE)
+set(SDLIMAGE_SVG TRUE)
+set(SDLIMAGE_TGA TRUE)
+set(SDLIMAGE_TIF TRUE)
+set(SDLIMAGE_XCF TRUE)
+set(SDLIMAGE_XPM TRUE)
+set(SDLIMAGE_XV TRUE)
+set(SDLIMAGE_WEBP TRUE)
+
+set(SDLIMAGE_JPG_SAVE TRUE)
+set(SDLIMAGE_PNG_SAVE TRUE)
+
+set(SDLIMAGE_VENDORED FALSE)
+
+set(SDLIMAGE_BACKEND_IMAGEIO TRUE)
+set(SDLIMAGE_BACKEND_STB FALSE)
+set(SDLIMAGE_BACKEND_WIC FALSE)
+
+
+# All targets are created, even when some might not be requested though COMPONENTS.
+# This is done for compatibility with CMake generated SDL3_image-target.cmake files.
+
+if(NOT TARGET SDL3_image::SDL3_image-shared)
+ add_library(SDL3_image::SDL3_image-shared SHARED IMPORTED)
+ # CMake does not automatically add RPATHS when using xcframeworks
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/25998
+ if(0) # if(CMAKE_VERSION GREATER_EQUAL "3.28")
+ set_target_properties(SDL3_image::SDL3_image-shared
+ PROPERTIES
+ FRAMEWORK "TRUE"
+ IMPORTED_LOCATION "${_sdl3_image_xcframework_path}"
+ )
+ else()
+ set_target_properties(SDL3_image::SDL3_image-shared
+ PROPERTIES
+ FRAMEWORK "TRUE"
+ IMPORTED_LOCATION "${_sdl3_image_framework_path}/SDL3_image"
+ )
+ endif()
+ set_target_properties(SDL3_image::SDL3_image-shared
+ PROPERTIES
+ COMPATIBLE_INTERFACE_BOOL "SDL3_SHARED"
+ INTERFACE_SDL3_SHARED "ON"
+ COMPATIBLE_INTERFACE_STRING "SDL_VERSION"
+ INTERFACE_SDL_VERSION "SDL3"
+ )
+endif()
+set(SDL3_image_SDL3_image-shared_FOUND TRUE)
+
+set(SDL3_image_SDL3_image-static FALSE)
+
+unset(_sdl3_image_xcframework_parent_path)
+unset(_sdl3_image_xcframework_path)
+unset(_sdl3_image_framework_parent_path)
+unset(_sdl3_image_framework_path)
+unset(_sdl3_image_include_dirs)
+
+if(SDL3_image_SDL3_image-shared_FOUND)
+ set(SDL3_image_SDL3_image TRUE)
+endif()
+
+function(_sdl_create_target_alias_compat NEW_TARGET TARGET)
+ if(CMAKE_VERSION VERSION_LESS "3.18")
+ # Aliasing local targets is not supported on CMake < 3.18, so make it global.
+ add_library(${NEW_TARGET} INTERFACE IMPORTED)
+ set_target_properties(${NEW_TARGET} PROPERTIES INTERFACE_LINK_LIBRARIES "${TARGET}")
+ else()
+ add_library(${NEW_TARGET} ALIAS ${TARGET})
+ endif()
+endfunction()
+
+# Make sure SDL3_image::SDL3_image always exists
+if(NOT TARGET SDL3_image::SDL3_image)
+ if(TARGET SDL3_image::SDL3_image-shared)
+ _sdl_create_target_alias_compat(SDL3_image::SDL3_image SDL3_image::SDL3_image-shared)
+ endif()
+endif()
+
+check_required_components(SDL3_image)
diff --git a/Xcode/pkg-support/resources/share/cmake/SDL3_image/SDL3_imageConfigVersion.cmake b/Xcode/pkg-support/resources/share/cmake/SDL3_image/SDL3_imageConfigVersion.cmake
new file mode 100644
index 00000000..4633a1bd
--- /dev/null
+++ b/Xcode/pkg-support/resources/share/cmake/SDL3_image/SDL3_imageConfigVersion.cmake
@@ -0,0 +1,76 @@
+# based on the files generated by CMake's write_basic_package_version_file
+
+# SDL CMake version configuration file:
+# This file is meant to be placed in share/cmake/SDL3_image, next to SDL3_image.xcframework
+
+cmake_minimum_required(VERSION 3.12)
+
+get_filename_component(_sdl3_image_xcframework_parent_path "${CMAKE_CURRENT_LIST_DIR}" REALPATH) # /share/cmake/SDL3_image/
+get_filename_component(_sdl3_image_xcframework_parent_path "${_sdl3_image_xcframework_parent_path}" REALPATH) # /share/cmake/SDL3_image/
+get_filename_component(_sdl3_image_xcframework_parent_path "${_sdl3_image_xcframework_parent_path}" PATH) # /share/cmake
+get_filename_component(_sdl3_image_xcframework_parent_path "${_sdl3_image_xcframework_parent_path}" PATH) # /share
+get_filename_component(_sdl3_image_xcframework_parent_path "${_sdl3_image_xcframework_parent_path}" PATH) # /
+set(_sdl3_image_xcframework "${_sdl3_image_xcframework_parent_path}/SDL3_image.xcframework") # /SDL3_image.xcframework
+set(_sdl3_image_framework "${_sdl3_image_xcframework}/macos-arm64_x86_64/SDL3_image.framework") # /SDL3_image.xcframework/macos-arm64_x86_64/SDL3_image.framework
+set(_sdl3_image_version_h "${_sdl3_image_framework}/Headers/SDL_image.h") # /SDL3_image.xcframework/macos-arm64_x86_64/SDL3_image.framework/Headers/SDL_image.h
+
+if(NOT EXISTS "${_sdl3_image_version_h}")
+ message(AUTHOR_WARNING "Cannot not find ${_sdl3_image_framework}. This script is meant to be placed in share/cmake/SDL3, next to SDL3.xcframework")
+ return()
+endif()
+
+file(READ "${_sdl3_image_version_h}" _sdl_version_h)
+
+unset(_sdl3_image_xcframework_parent_path)
+unset(_sdl3_image_framework)
+unset(_sdl3_image_xcframework)
+unset(_sdl3_image_version_h)
+
+string(REGEX MATCH "#define[ \t]+SDL_IMAGE_MAJOR_VERSION[ \t]+([0-9]+)" _sdl_major_re "${_sdl_version_h}")
+set(_sdl_major "${CMAKE_MATCH_1}")
+string(REGEX MATCH "#define[ \t]+SDL_IMAGE_MINOR_VERSION[ \t]+([0-9]+)" _sdl_minor_re "${_sdl_version_h}")
+set(_sdl_minor "${CMAKE_MATCH_1}")
+string(REGEX MATCH "#define[ \t]+SDL_IMAGE_MICRO_VERSION[ \t]+([0-9]+)" _sdl_micro_re "${_sdl_version_h}")
+set(_sdl_micro "${CMAKE_MATCH_1}")
+if(_sdl_major_re AND _sdl_minor_re AND _sdl_micro_re)
+ set(PACKAGE_VERSION "${_sdl_major}.${_sdl_minor}.${_sdl_micro}")
+else()
+ message(AUTHOR_WARNING "Could not extract version from SDL_image.h.")
+ return()
+endif()
+
+unset(_sdl_major_re)
+unset(_sdl_major)
+unset(_sdl_minor_re)
+unset(_sdl_minor)
+unset(_sdl_micro_re)
+unset(_sdl_micro)
+
+if(PACKAGE_FIND_VERSION_RANGE)
+ # Package version must be in the requested version range
+ if ((PACKAGE_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MIN)
+ OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_GREATER PACKAGE_FIND_VERSION_MAX)
+ OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_GREATER_EQUAL PACKAGE_FIND_VERSION_MAX)))
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+ else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ endif()
+else()
+ if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+ else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+ endif()
+endif()
+
+# The SDL3_image.xcframework only contains 64-bit archives
+if(NOT "${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
+ set(PACKAGE_VERSION_UNSUITABLE TRUE)
+endif()
+
+if(NOT CMAKE_SYSTEM_NAME MATCHES "^(Darwin|iOS|tvOS)$")
+ set(PACKAGE_VERSION_UNSUITABLE TRUE)
+endif()
diff --git a/build-scripts/android-prefab.sh b/build-scripts/android-prefab.sh
deleted file mode 100755
index a66bbd3f..00000000
--- a/build-scripts/android-prefab.sh
+++ /dev/null
@@ -1,353 +0,0 @@
-#!/bin/bash
-
-set -e
-
-if ! [ "x$ANDROID_NDK_HOME" != "x" -a -d "$ANDROID_NDK_HOME" ]; then
- echo "ANDROID_NDK_HOME environment variable is not set"
- exit 1
-fi
-
-if ! [ "x$ANDROID_HOME" != "x" -a -d "$ANDROID_HOME" ]; then
- echo "ANDROID_HOME environment variable is not set"
- exit 1
-fi
-
-if [ "x$ANDROID_API" = "x" ]; then
- ANDROID_API="$(ls "$ANDROID_HOME/platforms" | grep -E "^android-[0-9]+$" | sed 's/android-//' | sort -n -r | head -1)"
- if [ "x$ANDROID_API" = "x" ]; then
- echo "No Android platform found in $ANDROID_HOME/platforms"
- exit 1
- fi
-else
- if ! [ -d "$ANDROID_HOME/platforms/android-$ANDROID_API" ]; then
- echo "Android api version $ANDROID_API is not available ($ANDROID_HOME/platforms/android-$ANDROID_API does not exist)" >2
- exit 1
- fi
-fi
-
-android_platformdir="$ANDROID_HOME/platforms/android-$ANDROID_API"
-
-echo "Building for android api version $ANDROID_API"
-echo "android_platformdir=$android_platformdir"
-
-scriptdir=$(cd -P -- "$(dirname -- "$0")" && printf '%s\n' "$(pwd -P)")
-sdlimage_root=$(cd -P -- "$(dirname -- "$0")/.." && printf '%s\n' "$(pwd -P)")
-
-build_root="${sdlimage_root}/build-android-prefab"
-
-android_abis="armeabi-v7a arm64-v8a x86 x86_64"
-android_api=19
-android_ndk=21
-android_stl="c++_shared"
-
-sdlimage_major=$(sed -ne 's/^#define SDL_IMAGE_MAJOR_VERSION *//p' "${sdlimage_root}/include/SDL3_image/SDL_image.h")
-sdlimage_minor=$(sed -ne 's/^#define SDL_IMAGE_MINOR_VERSION *//p' "${sdlimage_root}/include/SDL3_image/SDL_image.h")
-sdlimage_micro=$(sed -ne 's/^#define SDL_IMAGE_MICRO_VERSION *//p' "${sdlimage_root}/include/SDL3_image/SDL_image.h")
-sdlimage_version="${sdlimage_major}.${sdlimage_minor}.${sdlimage_micro}"
-echo "Building Android prefab package for SDL_image version $sdlimage_version"
-
-if test ! -d "${sdl_build_root}"; then
- echo "sdl_build_root is not defined or is not a directory."
- echo "Set this environment folder to the root of an android SDL${sdlimage_major} prefab build"
- echo "This usually is SDL/build-android-prefab"
- exit 1
-fi
-
-prefabhome="${build_root}/prefab-${sdlimage_version}"
-rm -rf "$prefabhome"
-mkdir -p "${prefabhome}"
-
-build_cmake_projects() {
- for android_abi in $android_abis; do
-
- rm -rf "${build_root}/build_${android_abi}/prefix"
-
- for build_shared_libs in ON OFF; do
- echo "Configuring CMake project for $android_abi (shared=${build_shared_libs})"
- cmake -S "${sdlimage_root}" -B "${build_root}/build_${android_abi}/shared_${build_shared_libs}" \
- -DSDLIMAGE_DEPS_SHARED=ON \
- -DSDLIMAGE_VENDORED=ON \
- -DSDLIMAGE_BACKEND_STB=OFF \
- -DSDLIMAGE_AVIF=OFF \
- -DSDLIMAGE_BMP=ON \
- -DSDLIMAGE_GIF=ON \
- -DSDLIMAGE_JPG=ON \
- -DSDLIMAGE_JXL=OFF \
- -DSJPEG_ANDROID_NDK_PATH="${ANDROID_NDK_HOME}" \
- -DSDLIMAGE_LBM=ON \
- -DSDLIMAGE_PCX=ON \
- -DSDLIMAGE_PNG=ON \
- -DSDLIMAGE_PNM=ON \
- -DSDLIMAGE_QOI=ON \
- -DSDLIMAGE_SVG=ON \
- -DSDLIMAGE_TGA=ON \
- -DSDLIMAGE_TIF=ON \
- -DSDLIMAGE_WEBP=ON \
- -DSDLIMAGE_XCF=ON \
- -DSDLIMAGE_XPM=ON \
- -DSDLIMAGE_XV=ON \
- -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake" \
- -DSDL${sdlimage_major}_DIR="${sdl_build_root}/build_${android_abi}/prefix/lib/cmake/SDL${sdlimage_major}" \
- -DANDROID_PLATFORM=${android_platform} \
- -DANDROID_ABI=${android_abi} \
- -DBUILD_SHARED_LIBS=${build_shared_libs} \
- -DCMAKE_INSTALL_PREFIX="${build_root}/build_${android_abi}/prefix" \
- -DCMAKE_INSTALL_INCLUDEDIR=include \
- -DCMAKE_INSTALL_LIBDIR=lib \
- -DCMAKE_BUILD_TYPE=Release \
- -DSDL${sdlimage_major}IMAGE_SAMPLES=OFF \
- -DSDL${sdlimage_major}IMAGE_TESTS=OFF \
- -GNinja
-
- echo "Building CMake project for $android_abi (shared=${build_shared_libs})"
- cmake --build "${build_root}/build_${android_abi}/shared_${build_shared_libs}"
-
- echo "Installing CMake project for $android_abi (shared=${build_shared_libs})"
- cmake --install "${build_root}/build_${android_abi}/shared_${build_shared_libs}"
- done
- done
-}
-
-pom_filename="SDL${sdlimage_major}_image-${sdlimage_version}.pom"
-pom_filepath="${prefabhome}/${pom_filename}"
-create_pom_xml() {
- echo "Creating ${pom_filename}"
- cat >"${pom_filepath}" <
- 4.0.0
- org.libsdl.android
- SDL${sdlimage_major}_image
- ${sdlimage_version}
- aar
- SDL${sdlimage_major}_image
- The AAR for SDL${sdlimage_major}_image
- https://libsdl.org/
-
-
- zlib License
- https://github.com/libsdl-org/SDL_image/blob/main/LICENSE.txt
- repo
-
-
-
-
- Sam Lantinga
- slouken@libsdl.org
- SDL
- https://www.libsdl.org
-
-
-
- scm:git:https://github.com/libsdl-org/SDL_image
- scm:git:ssh://github.com:libsdl-org/SDL_image.git
- https://github.com/libsdl-org/SDL_image
-
-
-
- ossrh
- https://s01.oss.sonatype.org/content/repositories/snapshots
-
-
- ossrh
- https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/
-
-
-
-EOF
-}
-
-create_aar_androidmanifest() {
- echo "Creating AndroidManifest.xml"
- cat >"${aar_root}/AndroidManifest.xml" <
-
-
-EOF
-}
-
-echo "Creating AAR root directory"
-aar_root="${prefabhome}/SDL${sdlimage_major}_image-${sdlimage_version}"
-mkdir -p "${aar_root}"
-
-aar_metainfdir_path=${aar_root}/META-INF
-mkdir -p "${aar_metainfdir_path}"
-cp "${sdlimage_root}/LICENSE.txt" "${aar_metainfdir_path}"
-
-prefabworkdir="${aar_root}/prefab"
-mkdir -p "${prefabworkdir}"
-
-cat >"${prefabworkdir}/prefab.json" <"${sdl_moduleworkdir}/module.json" <"${abi_sdllibdir}/abi.json" <"${sdl_moduleworkdir}/module.json" <"${abi_sdllibdir}/abi.json" <"${sdl_moduleworkdir}/module.json" <"${abi_sdllibdir}/abi.json" <"${aar_metainfdir_path}/LICENSE.zlib.txt"
-
-create_shared_module external_libpng libpng16 ":external_zlib"
-cp "${sdlimage_root}/external/libpng/LICENSE" "${aar_metainfdir_path}/LICENSE.libpng.txt"
-
-create_shared_module external_libjpeg libjpeg ""
-cp "${sdlimage_root}/external/jpeg/README" "${aar_metainfdir_path}/LICENSE.libjpeg.txt"
-
-create_shared_module external_libtiff libtiff ""
-cp "${sdlimage_root}/external/libtiff/COPYRIGHT" "${aar_metainfdir_path}/LICENSE.libtiff.txt"
-
-create_shared_module external_libwebp libwebp ""
-cp "${sdlimage_root}/external/libwebp/COPYING" "${aar_metainfdir_path}/LICENSE.libwebp.txt"
-
-#create_shared_module libbrotlicommon libbrotlicommon ""
-#create_shared_module libbrotlidec libbrotlidec ":libbrotlicommon"
-#create_shared_module libbrotlienc libbrotlienc ":libbrotlicommon"
-#cp "${sdlimage_root}/external/libjxl/third_party/brotli/LICENSE" "${aar_metainfdir_path}/LICENSE.brotli.txt"
-
-#create_shared_module external_libjxl libjxl ":brotlienc :brotlidec"
-#cp "${sdlimage_root}/external/libjxl/LICENSE" "${aar_metainfdir_path}/LICENSE.libjxl.txt"
-
-pushd "${aar_root}"
- aar_filename="SDL${sdlimage_major}_image-${sdlimage_version}.aar"
- zip -r "${aar_filename}" AndroidManifest.xml prefab META-INF
- zip -Tv "${aar_filename}" 2>/dev/null ;
- mv "${aar_filename}" "${prefabhome}"
-popd
-
-maven_filename="SDL${sdlimage_major}_image-${sdlimage_version}.zip"
-
-pushd "${prefabhome}"
- zip_filename="SDL${sdlimage_major}_image-${sdlimage_version}.zip"
- zip "${maven_filename}" "${aar_filename}" "${pom_filename}" 2>/dev/null;
- zip -Tv "${zip_filename}" 2>/dev/null;
-popd
-
-echo "Prefab zip is ready at ${prefabhome}/${aar_filename}"
-echo "Maven archive is ready at ${prefabhome}/${zip_filename}"
diff --git a/build-scripts/build-release.py b/build-scripts/build-release.py
new file mode 100755
index 00000000..5ef2a348
--- /dev/null
+++ b/build-scripts/build-release.py
@@ -0,0 +1,1429 @@
+#!/usr/bin/env python
+
+"""
+This script is shared between SDL2, SDL3, and all satellite libraries.
+Don't specialize this script for doing project-specific modifications.
+Rather, modify release-info.json.
+"""
+
+import argparse
+import collections
+import dataclasses
+from collections.abc import Callable
+import contextlib
+import datetime
+import fnmatch
+import glob
+import io
+import json
+import logging
+import multiprocessing
+import os
+from pathlib import Path
+import platform
+import re
+import shlex
+import shutil
+import subprocess
+import sys
+import tarfile
+import tempfile
+import textwrap
+import typing
+import zipfile
+
+
+logger = logging.getLogger(__name__)
+GIT_HASH_FILENAME = ".git-hash"
+REVISION_TXT = "REVISION.txt"
+
+
+def safe_isotime_to_datetime(str_isotime: str) -> datetime.datetime:
+ try:
+ return datetime.datetime.fromisoformat(str_isotime)
+ except ValueError:
+ pass
+ logger.warning("Invalid iso time: %s", str_isotime)
+ if str_isotime[-6:-5] in ("+", "-"):
+ # Commits can have isotime with invalid timezone offset (e.g. "2021-07-04T20:01:40+32:00")
+ modified_str_isotime = str_isotime[:-6] + "+00:00"
+ try:
+ return datetime.datetime.fromisoformat(modified_str_isotime)
+ except ValueError:
+ pass
+ raise ValueError(f"Invalid isotime: {str_isotime}")
+
+
+def arc_join(*parts: list[str]) -> str:
+ assert all(p[:1] != "/" and p[-1:] != "/" for p in parts), f"None of {parts} may start or end with '/'"
+ return "/".join(p for p in parts if p)
+
+
+@dataclasses.dataclass(frozen=True)
+class VsArchPlatformConfig:
+ arch: str
+ configuration: str
+ platform: str
+
+ def extra_context(self):
+ return {
+ "ARCH": self.arch,
+ "CONFIGURATION": self.configuration,
+ "PLATFORM": self.platform,
+ }
+
+
+@contextlib.contextmanager
+def chdir(path):
+ original_cwd = os.getcwd()
+ try:
+ os.chdir(path)
+ yield
+ finally:
+ os.chdir(original_cwd)
+
+
+class Executer:
+ def __init__(self, root: Path, dry: bool=False):
+ self.root = root
+ self.dry = dry
+
+ def run(self, cmd, cwd=None, env=None):
+ logger.info("Executing args=%r", cmd)
+ sys.stdout.flush()
+ if not self.dry:
+ subprocess.check_call(cmd, cwd=cwd or self.root, env=env, text=True)
+
+ def check_output(self, cmd, cwd=None, dry_out=None, env=None, text=True):
+ logger.info("Executing args=%r", cmd)
+ sys.stdout.flush()
+ if self.dry:
+ return dry_out
+ return subprocess.check_output(cmd, cwd=cwd or self.root, env=env, text=text)
+
+
+class SectionPrinter:
+ @contextlib.contextmanager
+ def group(self, title: str):
+ print(f"{title}:")
+ yield
+
+
+class GitHubSectionPrinter(SectionPrinter):
+ def __init__(self):
+ super().__init__()
+ self.in_group = False
+
+ @contextlib.contextmanager
+ def group(self, title: str):
+ print(f"::group::{title}")
+ assert not self.in_group, "Can enter a group only once"
+ self.in_group = True
+ yield
+ self.in_group = False
+ print("::endgroup::")
+
+
+class VisualStudio:
+ def __init__(self, executer: Executer, year: typing.Optional[str]=None):
+ self.executer = executer
+ self.vsdevcmd = self.find_vsdevcmd(year)
+ self.msbuild = self.find_msbuild()
+
+ @property
+ def dry(self) -> bool:
+ return self.executer.dry
+
+ VS_YEAR_TO_VERSION = {
+ "2022": 17,
+ "2019": 16,
+ "2017": 15,
+ "2015": 14,
+ "2013": 12,
+ }
+
+ def find_vsdevcmd(self, year: typing.Optional[str]=None) -> typing.Optional[Path]:
+ vswhere_spec = ["-latest"]
+ if year is not None:
+ try:
+ version = self.VS_YEAR_TO_VERSION[year]
+ except KeyError:
+ logger.error("Invalid Visual Studio year")
+ return None
+ vswhere_spec.extend(["-version", f"[{version},{version+1})"])
+ vswhere_cmd = ["vswhere"] + vswhere_spec + ["-property", "installationPath"]
+ vs_install_path = Path(self.executer.check_output(vswhere_cmd, dry_out="/tmp").strip())
+ logger.info("VS install_path = %s", vs_install_path)
+ assert vs_install_path.is_dir(), "VS installation path does not exist"
+ vsdevcmd_path = vs_install_path / "Common7/Tools/vsdevcmd.bat"
+ logger.info("vsdevcmd path = %s", vsdevcmd_path)
+ if self.dry:
+ vsdevcmd_path.parent.mkdir(parents=True, exist_ok=True)
+ vsdevcmd_path.touch(exist_ok=True)
+ assert vsdevcmd_path.is_file(), "vsdevcmd.bat batch file does not exist"
+ return vsdevcmd_path
+
+ def find_msbuild(self) -> typing.Optional[Path]:
+ vswhere_cmd = ["vswhere", "-latest", "-requires", "Microsoft.Component.MSBuild", "-find", r"MSBuild\**\Bin\MSBuild.exe"]
+ msbuild_path = Path(self.executer.check_output(vswhere_cmd, dry_out="/tmp/MSBuild.exe").strip())
+ logger.info("MSBuild path = %s", msbuild_path)
+ if self.dry:
+ msbuild_path.parent.mkdir(parents=True, exist_ok=True)
+ msbuild_path.touch(exist_ok=True)
+ assert msbuild_path.is_file(), "MSBuild.exe does not exist"
+ return msbuild_path
+
+ def build(self, arch_platform: VsArchPlatformConfig, projects: list[Path]):
+ assert projects, "Need at least one project to build"
+
+ vsdev_cmd_str = f"\"{self.vsdevcmd}\" -arch={arch_platform.arch}"
+ msbuild_cmd_str = " && ".join([f"\"{self.msbuild}\" \"{project}\" /m /p:BuildInParallel=true /p:Platform={arch_platform.platform} /p:Configuration={arch_platform.configuration}" for project in projects])
+ bat_contents = f"{vsdev_cmd_str} && {msbuild_cmd_str}\n"
+ bat_path = Path(tempfile.gettempdir()) / "cmd.bat"
+ with bat_path.open("w") as f:
+ f.write(bat_contents)
+
+ logger.info("Running cmd.exe script (%s): %s", bat_path, bat_contents)
+ cmd = ["cmd.exe", "/D", "/E:ON", "/V:OFF", "/S", "/C", f"CALL {str(bat_path)}"]
+ self.executer.run(cmd)
+
+
+class Archiver:
+ def __init__(self, zip_path: typing.Optional[Path]=None, tgz_path: typing.Optional[Path]=None, txz_path: typing.Optional[Path]=None):
+ self._zip_files = []
+ self._tar_files = []
+ self._added_files = set()
+ if zip_path:
+ self._zip_files.append(zipfile.ZipFile(zip_path, "w", compression=zipfile.ZIP_DEFLATED))
+ if tgz_path:
+ self._tar_files.append(tarfile.open(tgz_path, "w:gz"))
+ if txz_path:
+ self._tar_files.append(tarfile.open(txz_path, "w:xz"))
+
+ @property
+ def added_files(self) -> set[str]:
+ return self._added_files
+
+ def add_file_data(self, arcpath: str, data: bytes, mode: int, time: datetime.datetime):
+ for zf in self._zip_files:
+ file_data_time = (time.year, time.month, time.day, time.hour, time.minute, time.second)
+ zip_info = zipfile.ZipInfo(filename=arcpath, date_time=file_data_time)
+ zip_info.external_attr = mode << 16
+ zip_info.compress_type = zipfile.ZIP_DEFLATED
+ zf.writestr(zip_info, data=data)
+ for tf in self._tar_files:
+ tar_info = tarfile.TarInfo(arcpath)
+ tar_info.type = tarfile.REGTYPE
+ tar_info.mode = mode
+ tar_info.size = len(data)
+ tar_info.mtime = int(time.timestamp())
+ tf.addfile(tar_info, fileobj=io.BytesIO(data))
+
+ self._added_files.add(arcpath)
+
+ def add_symlink(self, arcpath: str, target: str, time: datetime.datetime, files_for_zip):
+ logger.debug("Adding symlink (target=%r) -> %s", target, arcpath)
+ for zf in self._zip_files:
+ file_data_time = (time.year, time.month, time.day, time.hour, time.minute, time.second)
+ for f in files_for_zip:
+ zip_info = zipfile.ZipInfo(filename=f["arcpath"], date_time=file_data_time)
+ zip_info.external_attr = f["mode"] << 16
+ zip_info.compress_type = zipfile.ZIP_DEFLATED
+ zf.writestr(zip_info, data=f["data"])
+ for tf in self._tar_files:
+ tar_info = tarfile.TarInfo(arcpath)
+ tar_info.type = tarfile.SYMTYPE
+ tar_info.mode = 0o777
+ tar_info.mtime = int(time.timestamp())
+ tar_info.linkname = target
+ tf.addfile(tar_info)
+
+ self._added_files.update(f["arcpath"] for f in files_for_zip)
+
+ def add_git_hash(self, arcdir: str, commit: str, time: datetime.datetime):
+ arcpath = arc_join(arcdir, GIT_HASH_FILENAME)
+ data = f"{commit}\n".encode()
+ self.add_file_data(arcpath=arcpath, data=data, mode=0o100644, time=time)
+
+ def add_file_path(self, arcpath: str, path: Path):
+ assert path.is_file(), f"{path} should be a file"
+ logger.debug("Adding %s -> %s", path, arcpath)
+ for zf in self._zip_files:
+ zf.write(path, arcname=arcpath)
+ for tf in self._tar_files:
+ tf.add(path, arcname=arcpath)
+
+ def add_file_directory(self, arcdirpath: str, dirpath: Path):
+ assert dirpath.is_dir()
+ if arcdirpath and arcdirpath[-1:] != "/":
+ arcdirpath += "/"
+ for f in dirpath.iterdir():
+ if f.is_file():
+ arcpath = f"{arcdirpath}{f.name}"
+ logger.debug("Adding %s to %s", f, arcpath)
+ self.add_file_path(arcpath=arcpath, path=f)
+
+ def close(self):
+ # Archiver is intentionally made invalid after this function
+ del self._zip_files
+ self._zip_files = None
+ del self._tar_files
+ self._tar_files = None
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, type, value, traceback):
+ self.close()
+
+
+class NodeInArchive:
+ def __init__(self, arcpath: str, path: typing.Optional[Path]=None, data: typing.Optional[bytes]=None, mode: typing.Optional[int]=None, symtarget: typing.Optional[str]=None, time: typing.Optional[datetime.datetime]=None, directory: bool=False):
+ self.arcpath = arcpath
+ self.path = path
+ self.data = data
+ self.mode = mode
+ self.symtarget = symtarget
+ self.time = time
+ self.directory = directory
+
+ @classmethod
+ def from_fs(cls, arcpath: str, path: Path, mode: int=0o100644, time: typing.Optional[datetime.datetime]=None) -> "NodeInArchive":
+ if time is None:
+ time = datetime.datetime.fromtimestamp(os.stat(path).st_mtime)
+ return cls(arcpath=arcpath, path=path, mode=mode)
+
+ @classmethod
+ def from_data(cls, arcpath: str, data: bytes, time: datetime.datetime) -> "NodeInArchive":
+ return cls(arcpath=arcpath, data=data, time=time, mode=0o100644)
+
+ @classmethod
+ def from_text(cls, arcpath: str, text: str, time: datetime.datetime) -> "NodeInArchive":
+ return cls.from_data(arcpath=arcpath, data=text.encode(), time=time)
+
+ @classmethod
+ def from_symlink(cls, arcpath: str, symtarget: str) -> "NodeInArchive":
+ return cls(arcpath=arcpath, symtarget=symtarget)
+
+ @classmethod
+ def from_directory(cls, arcpath: str) -> "NodeInArchive":
+ return cls(arcpath=arcpath, directory=True)
+
+ def __repr__(self) -> str:
+ return f"<{type(self).__name__}:arcpath={self.arcpath},path='{str(self.path)}',len(data)={len(self.data) if self.data else 'n/a'},directory={self.directory},symtarget={self.symtarget}>"
+
+
+def configure_file(path: Path, context: dict[str, str]) -> bytes:
+ text = path.read_text()
+ return configure_text(text, context=context).encode()
+
+
+def configure_text(text: str, context: dict[str, str]) -> str:
+ original_text = text
+ for txt, repl in context.items():
+ text = text.replace(f"@<@{txt}@>@", repl)
+ success = all(thing not in text for thing in ("@<@", "@>@"))
+ if not success:
+ raise ValueError(f"Failed to configure {repr(original_text)}")
+ return text
+
+
+class ArchiveFileTree:
+ def __init__(self):
+ self._tree: dict[str, NodeInArchive] = {}
+
+ def add_file(self, file: NodeInArchive):
+ self._tree[file.arcpath] = file
+
+ def get_latest_mod_time(self) -> datetime.datetime:
+ return max(item.time for item in self._tree.values() if item.time)
+
+ def add_to_archiver(self, archive_base: str, archiver: Archiver):
+ remaining_symlinks = set()
+ added_files = dict()
+
+ def calculate_symlink_target(s: NodeInArchive) -> str:
+ dest_dir = os.path.dirname(s.path)
+ if dest_dir:
+ dest_dir += "/"
+ target = dest_dir + s.symtarget
+ while True:
+ new_target, n = re.subn(r"([^/]+/+[.]{2}/)", "", target)
+ print(f"{target=} {new_target=}")
+ target = new_target
+ if not n:
+ break
+ return target
+
+ # Add files in first pass
+ for arcpath, node in self._tree.items():
+ if node.data is not None:
+ archiver.add_file_data(arcpath=arc_join(archive_base, arcpath), data=node.data, time=node.time, mode=node.mode)
+ added_files[node.path] = node
+ elif node.path is not None:
+ archiver.add_file_path(arcpath=arc_join(archive_base, arcpath), path=node.path)
+ added_files[node.path] = node
+ elif node.symtarget is not None:
+ remaining_symlinks.add(node)
+ elif node.directory:
+ pass
+ else:
+ raise ValueError(f"Invalid Archive Node: {repr(node)}")
+
+ # Resolve symlinks in second pass: zipfile does not support symlinks, so add files to zip archive
+ while True:
+ if not remaining_symlinks:
+ break
+ symlinks_this_time = set()
+ extra_added_files = {}
+ for symlink in remaining_symlinks:
+ symlink_files_for_zip = {}
+ symlink_target_path = calculate_symlink_target(symlink)
+ if symlink_target_path in added_files:
+ symlink_files_for_zip[symlink.path] = added_files[symlink_target_path]
+ else:
+ symlink_target_path_slash = symlink_target_path + "/"
+ for added_file in added_files:
+ if added_file.startswith(symlink_target_path_slash):
+ path_in_symlink = symlink.path + "/" + added_file.removeprefix(symlink_target_path_slash)
+ symlink_files_for_zip[path_in_symlink] = added_files[added_file]
+ if symlink_files_for_zip:
+ symlinks_this_time.add(symlink)
+ extra_added_files.update(symlink_files_for_zip)
+ files_for_zip = [{"arcpath": f"{archive_base}/{sym_path}", "data": sym_info.data, "mode": sym_info.mode} for sym_path, sym_info in symlink_files_for_zip.items()]
+ archiver.add_symlink(arcpath=f"{archive_base}/{symlink.path}", target=symlink.symtarget, time=symlink.time, files_for_zip=files_for_zip)
+ # if not symlinks_this_time:
+ # logger.info("files added: %r", set(path for path in added_files.keys()))
+ assert symlinks_this_time, f"No targets found for symlinks: {remaining_symlinks}"
+ remaining_symlinks.difference_update(symlinks_this_time)
+ added_files.update(extra_added_files)
+
+ def add_directory_tree(self, arc_dir: str, path: Path, time: datetime.datetime):
+ assert path.is_dir()
+ for files_dir, _, filenames in os.walk(path):
+ files_dir_path = Path(files_dir)
+ rel_files_path = files_dir_path.relative_to(path)
+ for filename in filenames:
+ self.add_file(NodeInArchive.from_fs(arcpath=arc_join(arc_dir, str(rel_files_path), filename), path=files_dir_path / filename, time=time))
+
+ def _add_files_recursively(self, arc_dir: str, paths: list[Path], time: datetime.datetime):
+ logger.debug(f"_add_files_recursively({arc_dir=} {paths=})")
+ for path in paths:
+ arcpath = arc_join(arc_dir, path.name)
+ if path.is_file():
+ logger.debug("Adding %s as %s", path, arcpath)
+ self.add_file(NodeInArchive.from_fs(arcpath=arcpath, path=path, time=time))
+ elif path.is_dir():
+ self._add_files_recursively(arc_dir=arc_join(arc_dir, path.name), paths=list(path.iterdir()), time=time)
+ else:
+ raise ValueError(f"Unsupported file type to add recursively: {path}")
+
+ def add_file_mapping(self, arc_dir: str, file_mapping: dict[str, list[str]], file_mapping_root: Path, context: dict[str, str], time: datetime.datetime):
+ for meta_rel_destdir, meta_file_globs in file_mapping.items():
+ rel_destdir = configure_text(meta_rel_destdir, context=context)
+ assert "@" not in rel_destdir, f"archive destination should not contain an @ after configuration ({repr(meta_rel_destdir)}->{repr(rel_destdir)})"
+ for meta_file_glob in meta_file_globs:
+ file_glob = configure_text(meta_file_glob, context=context)
+ assert "@" not in rel_destdir, f"archive glob should not contain an @ after configuration ({repr(meta_file_glob)}->{repr(file_glob)})"
+ if ":" in file_glob:
+ original_path, new_filename = file_glob.rsplit(":", 1)
+ assert ":" not in original_path, f"Too many ':' in {repr(file_glob)}"
+ assert "/" not in new_filename, f"New filename cannot contain a '/' in {repr(file_glob)}"
+ path = file_mapping_root / original_path
+ arcpath = arc_join(arc_dir, rel_destdir, new_filename)
+ if path.suffix == ".in":
+ data = configure_file(path, context=context)
+ logger.debug("Adding processed %s -> %s", path, arcpath)
+ self.add_file(NodeInArchive.from_data(arcpath=arcpath, data=data, time=time))
+ else:
+ logger.debug("Adding %s -> %s", path, arcpath)
+ self.add_file(NodeInArchive.from_fs(arcpath=arcpath, path=path, time=time))
+ else:
+ relative_file_paths = glob.glob(file_glob, root_dir=file_mapping_root)
+ assert relative_file_paths, f"Glob '{file_glob}' does not match any file"
+ self._add_files_recursively(arc_dir=arc_join(arc_dir, rel_destdir), paths=[file_mapping_root / p for p in relative_file_paths], time=time)
+
+
+class SourceCollector:
+ # TreeItem = collections.namedtuple("TreeItem", ("path", "mode", "data", "symtarget", "directory", "time"))
+ def __init__(self, root: Path, commit: str, filter: typing.Optional[Callable[[str], bool]], executer: Executer):
+ self.root = root
+ self.commit = commit
+ self.filter = filter
+ self.executer = executer
+
+ def get_archive_file_tree(self) -> ArchiveFileTree:
+ git_archive_args = ["git", "archive", "--format=tar.gz", self.commit, "-o", "/dev/stdout"]
+ logger.info("Executing args=%r", git_archive_args)
+ contents_tgz = subprocess.check_output(git_archive_args, cwd=self.root, text=False)
+ tar_archive = tarfile.open(fileobj=io.BytesIO(contents_tgz), mode="r:gz")
+ filenames = tuple(m.name for m in tar_archive if (m.isfile() or m.issym()))
+
+ file_times = self._get_file_times(paths=filenames)
+ git_contents = ArchiveFileTree()
+ for ti in tar_archive:
+ if self.filter and not self.filter(ti.name):
+ continue
+ data = None
+ symtarget = None
+ directory = False
+ file_time = None
+ if ti.isfile():
+ contents_file = tar_archive.extractfile(ti.name)
+ data = contents_file.read()
+ file_time = file_times[ti.name]
+ elif ti.issym():
+ symtarget = ti.linkname
+ file_time = file_times[ti.name]
+ elif ti.isdir():
+ directory = True
+ else:
+ raise ValueError(f"{ti.name}: unknown type")
+ node = NodeInArchive(arcpath=ti.name, data=data, mode=ti.mode, symtarget=symtarget, time=file_time, directory=directory)
+ git_contents.add_file(node)
+ return git_contents
+
+ def _get_file_times(self, paths: tuple[str, ...]) -> dict[str, datetime.datetime]:
+ dry_out = textwrap.dedent("""\
+ time=2024-03-14T15:40:25-07:00
+
+ M\tCMakeLists.txt
+ """)
+ git_log_out = self.executer.check_output(["git", "log", "--name-status", '--pretty=time=%cI', self.commit], dry_out=dry_out, cwd=self.root).splitlines(keepends=False)
+ current_time = None
+ set_paths = set(paths)
+ path_times: dict[str, datetime.datetime] = {}
+ for line in git_log_out:
+ if not line:
+ continue
+ if line.startswith("time="):
+ current_time = safe_isotime_to_datetime(line.removeprefix("time="))
+ continue
+ mod_type, file_paths = line.split(maxsplit=1)
+ assert current_time is not None
+ for file_path in file_paths.split("\t"):
+ if file_path in set_paths and file_path not in path_times:
+ path_times[file_path] = current_time
+
+ # FIXME: find out why some files are not shown in "git log"
+ # assert set(path_times.keys()) == set_paths
+ if set(path_times.keys()) != set_paths:
+ found_times = set(path_times.keys())
+ paths_without_times = set_paths.difference(found_times)
+ logger.warning("No times found for these paths: %s", paths_without_times)
+ max_time = max(time for time in path_times.values())
+ for path in paths_without_times:
+ path_times[path] = max_time
+
+ return path_times
+
+
+class Releaser:
+ def __init__(self, release_info: dict, commit: str, revision: str, root: Path, dist_path: Path, section_printer: SectionPrinter, executer: Executer, cmake_generator: str, deps_path: Path, overwrite: bool, github: bool, fast: bool):
+ self.release_info = release_info
+ self.project = release_info["name"]
+ self.version = self.extract_sdl_version(root=root, release_info=release_info)
+ self.root = root
+ self.commit = commit
+ self.revision = revision
+ self.dist_path = dist_path
+ self.section_printer = section_printer
+ self.executer = executer
+ self.cmake_generator = cmake_generator
+ self.cpu_count = multiprocessing.cpu_count()
+ self.deps_path = deps_path
+ self.overwrite = overwrite
+ self.github = github
+ self.fast = fast
+ self.arc_time = datetime.datetime.now()
+
+ self.artifacts: dict[str, Path] = {}
+
+ def get_context(self, extra_context: typing.Optional[dict[str, str]]=None) -> dict[str, str]:
+ ctx = {
+ "PROJECT_NAME": self.project,
+ "PROJECT_VERSION": self.version,
+ "PROJECT_COMMIT": self.commit,
+ "PROJECT_REVISION": self.revision,
+ }
+ if extra_context:
+ ctx.update(extra_context)
+ return ctx
+
+ @property
+ def dry(self) -> bool:
+ return self.executer.dry
+
+ def prepare(self):
+ logger.debug("Creating dist folder")
+ self.dist_path.mkdir(parents=True, exist_ok=True)
+
+ @classmethod
+ def _path_filter(cls, path: str) -> bool:
+ if ".gitmodules" in path:
+ return True
+ if path.startswith(".git"):
+ return False
+ return True
+
+ @classmethod
+ def _external_repo_path_filter(cls, path: str) -> bool:
+ if not cls._path_filter(path):
+ return False
+ if path.startswith("test/") or path.startswith("tests/"):
+ return False
+ return True
+
+ def create_source_archives(self) -> None:
+ source_collector = SourceCollector(root=self.root, commit=self.commit, executer=self.executer, filter=self._path_filter)
+ print(f"Collecting sources of {self.project}...")
+ archive_tree = source_collector.get_archive_file_tree()
+ latest_mod_time = archive_tree.get_latest_mod_time()
+ archive_tree.add_file(NodeInArchive.from_text(arcpath=REVISION_TXT, text=f"{self.revision}\n", time=latest_mod_time))
+ archive_tree.add_file(NodeInArchive.from_text(arcpath=f"{GIT_HASH_FILENAME}", text=f"{self.commit}\n", time=latest_mod_time))
+ archive_tree.add_file_mapping(arc_dir="", file_mapping=self.release_info["source"].get("files", {}), file_mapping_root=self.root, context=self.get_context(), time=latest_mod_time)
+
+ archive_base = f"{self.project}-{self.version}"
+ zip_path = self.dist_path / f"{archive_base}.zip"
+ tgz_path = self.dist_path / f"{archive_base}.tar.gz"
+ txz_path = self.dist_path / f"{archive_base}.tar.xz"
+
+ logger.info("Creating zip/tgz/txz source archives ...")
+ if self.dry:
+ zip_path.touch()
+ tgz_path.touch()
+ txz_path.touch()
+ else:
+ with Archiver(zip_path=zip_path, tgz_path=tgz_path, txz_path=txz_path) as archiver:
+ print(f"Adding source files of {self.project}...")
+ archive_tree.add_to_archiver(archive_base=archive_base, archiver=archiver)
+
+ for extra_repo in self.release_info["source"].get("extra-repos", []):
+ extra_repo_root = self.root / extra_repo
+ assert (extra_repo_root / ".git").exists(), f"{extra_repo_root} must be a git repo"
+ extra_repo_commit = self.executer.check_output(["git", "rev-parse", "HEAD"], dry_out=f"gitsha-extra-repo-{extra_repo}", cwd=extra_repo_root).strip()
+ extra_repo_source_collector = SourceCollector(root=extra_repo_root, commit=extra_repo_commit, executer=self.executer, filter=self._external_repo_path_filter)
+ print(f"Collecting sources of {extra_repo} ...")
+ extra_repo_archive_tree = extra_repo_source_collector.get_archive_file_tree()
+ print(f"Adding source files of {extra_repo} ...")
+ extra_repo_archive_tree.add_to_archiver(archive_base=f"{archive_base}/{extra_repo}", archiver=archiver)
+
+ for file in self.release_info["source"]["checks"]:
+ assert f"{archive_base}/{file}" in archiver.added_files, f"'{archive_base}/{file}' must exist"
+
+ logger.info("... done")
+
+ self.artifacts["src-zip"] = zip_path
+ self.artifacts["src-tar-gz"] = tgz_path
+ self.artifacts["src-tar-xz"] = txz_path
+
+ if not self.dry:
+ with tgz_path.open("r+b") as f:
+ # Zero the embedded timestamp in the gzip'ed tarball
+ f.seek(4, 0)
+ f.write(b"\x00\x00\x00\x00")
+
+ def create_dmg(self, configuration: str="Release") -> None:
+ dmg_in = self.root / self.release_info["dmg"]["path"]
+ xcode_project = self.root / self.release_info["dmg"]["project"]
+ assert xcode_project.is_dir(), f"{xcode_project} must be a directory"
+ assert (xcode_project / "project.pbxproj").is_file, f"{xcode_project} must contain project.pbxproj"
+ if not self.fast:
+ dmg_in.unlink(missing_ok=True)
+ build_xcconfig = self.release_info["dmg"].get("build-xcconfig")
+ if build_xcconfig:
+ shutil.copy(self.root / build_xcconfig, xcode_project.parent / "build.xcconfig")
+
+ xcode_scheme = self.release_info["dmg"].get("scheme")
+ xcode_target = self.release_info["dmg"].get("target")
+ assert xcode_scheme or xcode_target, "dmg needs scheme or target"
+ assert not (xcode_scheme and xcode_target), "dmg cannot have both scheme and target set"
+ if xcode_scheme:
+ scheme_or_target = "-scheme"
+ target_like = xcode_scheme
+ else:
+ scheme_or_target = "-target"
+ target_like = xcode_target
+ self.executer.run(["xcodebuild", "ONLY_ACTIVE_ARCH=NO", "-project", xcode_project, scheme_or_target, target_like, "-configuration", configuration])
+ if self.dry:
+ dmg_in.parent.mkdir(parents=True, exist_ok=True)
+ dmg_in.touch()
+
+ assert dmg_in.is_file(), f"{self.project}.dmg was not created by xcodebuild"
+
+ dmg_out = self.dist_path / f"{self.project}-{self.version}.dmg"
+ shutil.copy(dmg_in, dmg_out)
+ self.artifacts["dmg"] = dmg_out
+
+ @property
+ def git_hash_data(self) -> bytes:
+ return f"{self.commit}\n".encode()
+
+ def create_mingw_archives(self) -> None:
+ build_type = "Release"
+ build_parent_dir = self.root / "build-mingw"
+ ARCH_TO_GNU_ARCH = {
+ # "arm64": "aarch64",
+ "x86": "i686",
+ "x64": "x86_64",
+ }
+ ARCH_TO_TRIPLET = {
+ # "arm64": "aarch64-w64-mingw32",
+ "x86": "i686-w64-mingw32",
+ "x64": "x86_64-w64-mingw32",
+ }
+
+ new_env = dict(os.environ)
+
+ cmake_prefix_paths = []
+ mingw_deps_path = self.deps_path / "mingw-deps"
+
+ if "dependencies" in self.release_info["mingw"]:
+ shutil.rmtree(mingw_deps_path, ignore_errors=True)
+ mingw_deps_path.mkdir()
+
+ for triplet in ARCH_TO_TRIPLET.values():
+ (mingw_deps_path / triplet).mkdir()
+
+ def extract_filter(member: tarfile.TarInfo, path: str, /):
+ if member.name.startswith("SDL"):
+ member.name = "/".join(Path(member.name).parts[1:])
+ return member
+ for dep in self.release_info.get("dependencies", {}):
+ extract_path = mingw_deps_path / f"extract-{dep}"
+ extract_path.mkdir()
+ with chdir(extract_path):
+ tar_path = self.deps_path / glob.glob(self.release_info["mingw"]["dependencies"][dep]["artifact"], root_dir=self.deps_path)[0]
+ logger.info("Extracting %s to %s", tar_path, mingw_deps_path)
+ assert tar_path.suffix in (".gz", ".xz")
+ with tarfile.open(tar_path, mode=f"r:{tar_path.suffix.strip('.')}") as tarf:
+ tarf.extractall(filter=extract_filter)
+ for arch, triplet in ARCH_TO_TRIPLET.items():
+ install_cmd = self.release_info["mingw"]["dependencies"][dep]["install-command"]
+ extra_configure_data = {
+ "ARCH": ARCH_TO_GNU_ARCH[arch],
+ "TRIPLET": triplet,
+ "PREFIX": str(mingw_deps_path / triplet),
+ }
+ install_cmd = configure_text(install_cmd, context=self.get_context(extra_configure_data))
+ self.executer.run(shlex.split(install_cmd), cwd=str(extract_path))
+
+ dep_binpath = mingw_deps_path / triplet / "bin"
+ assert dep_binpath.is_dir(), f"{dep_binpath} for PATH should exist"
+ dep_pkgconfig = mingw_deps_path / triplet / "lib/pkgconfig"
+ assert dep_pkgconfig.is_dir(), f"{dep_pkgconfig} for PKG_CONFIG_PATH should exist"
+
+ new_env["PATH"] = os.pathsep.join([str(dep_binpath), new_env["PATH"]])
+ new_env["PKG_CONFIG_PATH"] = str(dep_pkgconfig)
+ cmake_prefix_paths.append(mingw_deps_path)
+
+ new_env["CFLAGS"] = f"-O2 -ffile-prefix-map={self.root}=/src/{self.project}"
+ new_env["CXXFLAGS"] = f"-O2 -ffile-prefix-map={self.root}=/src/{self.project}"
+
+ assert any(system in self.release_info["mingw"] for system in ("autotools", "cmake"))
+ assert not all(system in self.release_info["mingw"] for system in ("autotools", "cmake"))
+
+ mingw_archs = set()
+ arc_root = f"{self.project}-{self.version}"
+ archive_file_tree = ArchiveFileTree()
+
+ if "autotools" in self.release_info["mingw"]:
+ for arch in self.release_info["mingw"]["autotools"]["archs"]:
+ triplet = ARCH_TO_TRIPLET[arch]
+ new_env["CC"] = f"{triplet}-gcc"
+ new_env["CXX"] = f"{triplet}-g++"
+ new_env["RC"] = f"{triplet}-windres"
+
+ assert arch not in mingw_archs
+ mingw_archs.add(arch)
+
+ build_path = build_parent_dir / f"build-{triplet}"
+ install_path = build_parent_dir / f"install-{triplet}"
+ shutil.rmtree(install_path, ignore_errors=True)
+ build_path.mkdir(parents=True, exist_ok=True)
+ with self.section_printer.group(f"Configuring MinGW {triplet} (autotools)"):
+ extra_args = [arg.replace("@DEP_PREFIX@", str(mingw_deps_path / triplet)) for arg in self.release_info["mingw"]["autotools"]["args"]]
+ assert "@" not in " ".join(extra_args), f"@ should not be present in extra arguments ({extra_args})"
+ self.executer.run([
+ self.root / "configure",
+ f"--prefix={install_path}",
+ f"--includedir={install_path}/include",
+ f"--libdir={install_path}/lib",
+ f"--bindir={install_path}/bin",
+ f"--host={triplet}",
+ f"--build=x86_64-none-linux-gnu",
+ ] + extra_args, cwd=build_path, env=new_env)
+ with self.section_printer.group(f"Build MinGW {triplet} (autotools)"):
+ self.executer.run(["make", f"-j{self.cpu_count}"], cwd=build_path, env=new_env)
+ with self.section_printer.group(f"Install MinGW {triplet} (autotools)"):
+ self.executer.run(["make", "install"], cwd=build_path, env=new_env)
+ archive_file_tree.add_directory_tree(arc_dir=arc_join(arc_root, triplet), path=install_path)
+
+ if "cmake" in self.release_info["mingw"]:
+ assert self.release_info["mingw"]["cmake"]["shared-static"] in ("args", "both")
+ for arch in self.release_info["mingw"]["cmake"]["archs"]:
+ triplet = ARCH_TO_TRIPLET[arch]
+ new_env["CC"] = f"{triplet}-gcc"
+ new_env["CXX"] = f"{triplet}-g++"
+ new_env["RC"] = f"{triplet}-windres"
+
+ assert arch not in mingw_archs
+ mingw_archs.add(arch)
+
+ build_path = build_parent_dir / f"build-{triplet}"
+ install_path = build_parent_dir / f"install-{triplet}"
+ shutil.rmtree(install_path, ignore_errors=True)
+ build_path.mkdir(parents=True, exist_ok=True)
+ if self.release_info["mingw"]["cmake"]["shared-static"] == "args":
+ args_for_shared_static = ([], )
+ elif self.release_info["mingw"]["cmake"]["shared-static"] == "both":
+ args_for_shared_static = (["-DBUILD_SHARED_LIBS=ON"], ["-DBUILD_SHARED_LIBS=OFF"])
+ for arg_for_shared_static in args_for_shared_static:
+ with self.section_printer.group(f"Configuring MinGW {triplet} (CMake)"):
+ extra_args = [arg.replace("@DEP_PREFIX@", str(mingw_deps_path / triplet)) for arg in self.release_info["mingw"]["cmake"]["args"]]
+ assert "@" not in " ".join(extra_args), f"@ should not be present in extra arguments ({extra_args})"
+ self.executer.run([
+ f"cmake",
+ f"-S", str(self.root), "-B", str(build_path),
+ f"-DCMAKE_BUILD_TYPE={build_type}",
+ f'''-DCMAKE_C_FLAGS="-ffile-prefix-map={self.root}=/src/{self.project}"''',
+ f'''-DCMAKE_CXX_FLAGS="-ffile-prefix-map={self.root}=/src/{self.project}"''',
+ f"-DCMAKE_PREFIX_PATH={mingw_deps_path / triplet}",
+ f"-DCMAKE_INSTALL_PREFIX={install_path}",
+ f"-DCMAKE_INSTALL_INCLUDEDIR=include",
+ f"-DCMAKE_INSTALL_LIBDIR=lib",
+ f"-DCMAKE_INSTALL_BINDIR=bin",
+ f"-DCMAKE_INSTALL_DATAROOTDIR=share",
+ f"-DCMAKE_TOOLCHAIN_FILE={self.root}/build-scripts/cmake-toolchain-mingw64-{ARCH_TO_GNU_ARCH[arch]}.cmake",
+ f"-G{self.cmake_generator}",
+ ] + extra_args + ([] if self.fast else ["--fresh"]) + arg_for_shared_static, cwd=build_path, env=new_env)
+ with self.section_printer.group(f"Build MinGW {triplet} (CMake)"):
+ self.executer.run(["cmake", "--build", str(build_path), "--verbose", "--config", build_type], cwd=build_path, env=new_env)
+ with self.section_printer.group(f"Install MinGW {triplet} (CMake)"):
+ self.executer.run(["cmake", "--install", str(build_path)], cwd=build_path, env=new_env)
+ archive_file_tree.add_directory_tree(arc_dir=arc_join(arc_root, triplet), path=install_path, time=self.arc_time)
+
+ print("Recording extra files for MinGW development archive ...")
+ archive_file_tree.add_file_mapping(arc_dir=arc_root, file_mapping=self.release_info["mingw"].get("files", {}), file_mapping_root=self.root, context=self.get_context(), time=self.arc_time)
+ print("... done")
+
+ print("Creating zip/tgz/txz development archives ...")
+ zip_path = self.dist_path / f"{self.project}-devel-{self.version}-mingw.zip"
+ tgz_path = self.dist_path / f"{self.project}-devel-{self.version}-mingw.tar.gz"
+ txz_path = self.dist_path / f"{self.project}-devel-{self.version}-mingw.tar.xz"
+
+ with Archiver(zip_path=zip_path, tgz_path=tgz_path, txz_path=txz_path) as archiver:
+ archive_file_tree.add_to_archiver(archive_base="", archiver=archiver)
+ archiver.add_git_hash(arcdir=arc_root, commit=self.commit, time=self.arc_time)
+ print("... done")
+
+ self.artifacts["mingw-devel-zip"] = zip_path
+ self.artifacts["mingw-devel-tar-gz"] = tgz_path
+ self.artifacts["mingw-devel-tar-xz"] = txz_path
+
+ def _detect_android_api(self, android_home: str) -> typing.Optional[int]:
+ platform_dirs = list(Path(p) for p in glob.glob(f"{android_home}/platforms/android-*"))
+ re_platform = re.compile("android-([0-9]+)")
+ platform_versions = []
+ for platform_dir in platform_dirs:
+ logger.debug("Found Android Platform SDK: %s", platform_dir)
+ if m:= re_platform.match(platform_dir.name):
+ platform_versions.append(int(m.group(1)))
+ platform_versions.sort()
+ logger.info("Available platform versions: %s", platform_versions)
+ platform_versions = list(filter(lambda v: v >= self._android_api_minimum, platform_versions))
+ logger.info("Valid platform versions (>=%d): %s", self._android_api_minimum, platform_versions)
+ if not platform_versions:
+ return None
+ android_api = platform_versions[0]
+ logger.info("Selected API version %d", android_api)
+ return android_api
+
+ def _get_prefab_json_text(self) -> str:
+ return textwrap.dedent(f"""\
+ {{
+ "schema_version": 2,
+ "name": "{self.project}",
+ "version": "{self.version}",
+ "dependencies": []
+ }}
+ """)
+
+ def _get_prefab_module_json_text(self, library_name: typing.Optional[str], export_libraries: list[str]) -> str:
+ for lib in export_libraries:
+ assert isinstance(lib, str), f"{lib} must be a string"
+ module_json_dict = {
+ "export_libraries": export_libraries,
+ }
+ if library_name:
+ module_json_dict["library_name"] = f"lib{library_name}"
+ return json.dumps(module_json_dict, indent=4)
+
+ @property
+ def _android_api_minimum(self):
+ return self.release_info["android"]["api-minimum"]
+
+ @property
+ def _android_api_target(self):
+ return self.release_info["android"]["api-target"]
+
+ @property
+ def _android_ndk_minimum(self):
+ return self.release_info["android"]["ndk-minimum"]
+
+ def _get_prefab_abi_json_text(self, abi: str, cpp: bool, shared: bool) -> str:
+ abi_json_dict = {
+ "abi": abi,
+ "api": self._android_api_minimum,
+ "ndk": self._android_ndk_minimum,
+ "stl": "c++_shared" if cpp else "none",
+ "static": not shared,
+ }
+ return json.dumps(abi_json_dict, indent=4)
+
+ def _get_android_manifest_text(self) -> str:
+ return textwrap.dedent(f"""\
+
+
+
+ """)
+
+ def create_android_archives(self, android_api: int, android_home: Path, android_ndk_home: Path) -> None:
+ cmake_toolchain_file = Path(android_ndk_home) / "build/cmake/android.toolchain.cmake"
+ if not cmake_toolchain_file.exists():
+ logger.error("CMake toolchain file does not exist (%s)", cmake_toolchain_file)
+ raise SystemExit(1)
+ aar_path = self.dist_path / f"{self.project}-{self.version}.aar"
+ android_abis = self.release_info["android"]["abis"]
+ java_jars_added = False
+ module_data_added = False
+ android_deps_path = self.deps_path / "android-deps"
+ shutil.rmtree(android_deps_path, ignore_errors=True)
+
+ for dep, depinfo in self.release_info["android"].get("dependencies", {}).items():
+ android_aar = self.deps_path / glob.glob(depinfo["artifact"], root_dir=self.deps_path)[0]
+ with self.section_printer.group(f"Extracting Android dependency {dep} ({android_aar.name})"):
+ self.executer.run([sys.executable, str(android_aar), "-o", str(android_deps_path)])
+
+ for module_name, module_info in self.release_info["android"]["modules"].items():
+ assert "type" in module_info and module_info["type"] in ("interface", "library"), f"module {module_name} must have a valid type"
+
+ archive_file_tree = ArchiveFileTree()
+
+ for android_abi in android_abis:
+ with self.section_printer.group(f"Building for Android {android_api} {android_abi}"):
+ build_dir = self.root / "build-android" / f"{android_abi}-build"
+ install_dir = self.root / "install-android" / f"{android_abi}-install"
+ shutil.rmtree(install_dir, ignore_errors=True)
+ assert not install_dir.is_dir(), f"{install_dir} should not exist prior to build"
+ build_type = "Release"
+ cmake_args = [
+ "cmake",
+ "-S", str(self.root),
+ "-B", str(build_dir),
+ f'''-DCMAKE_C_FLAGS="-ffile-prefix-map={self.root}=/src/{self.project}"''',
+ f'''-DCMAKE_CXX_FLAGS="-ffile-prefix-map={self.root}=/src/{self.project}"''',
+ f"-DCMAKE_TOOLCHAIN_FILE={cmake_toolchain_file}",
+ f"-DCMAKE_PREFIX_PATH={str(android_deps_path)}",
+ f"-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH",
+ f"-DANDROID_HOME={android_home}",
+ f"-DANDROID_PLATFORM={android_api}",
+ f"-DANDROID_ABI={android_abi}",
+ "-DCMAKE_POSITION_INDEPENDENT_CODE=ON",
+ f"-DCMAKE_INSTALL_PREFIX={install_dir}",
+ "-DCMAKE_INSTALL_INCLUDEDIR=include ",
+ "-DCMAKE_INSTALL_LIBDIR=lib",
+ "-DCMAKE_INSTALL_DATAROOTDIR=share",
+ f"-DCMAKE_BUILD_TYPE={build_type}",
+ f"-G{self.cmake_generator}",
+ ] + self.release_info["android"]["cmake"]["args"] + ([] if self.fast else ["--fresh"])
+ build_args = [
+ "cmake",
+ "--build", str(build_dir),
+ "--verbose",
+ "--config", build_type,
+ ]
+ install_args = [
+ "cmake",
+ "--install", str(build_dir),
+ "--config", build_type,
+ ]
+ self.executer.run(cmake_args)
+ self.executer.run(build_args)
+ self.executer.run(install_args)
+
+ for module_name, module_info in self.release_info["android"]["modules"].items():
+ arcdir_prefab_module = f"prefab/modules/{module_name}"
+ if module_info["type"] == "library":
+ library = install_dir / module_info["library"]
+ assert library.suffix in (".so", ".a")
+ assert library.is_file(), f"CMake should have built library '{library}' for module {module_name}"
+ arcdir_prefab_libs = f"{arcdir_prefab_module}/libs/android.{android_abi}"
+ archive_file_tree.add_file(NodeInArchive.from_fs(arcpath=f"{arcdir_prefab_libs}/{library.name}", path=library, time=self.arc_time))
+ archive_file_tree.add_file(NodeInArchive.from_text(arcpath=f"{arcdir_prefab_libs}/abi.json", text=self._get_prefab_abi_json_text(abi=android_abi, cpp=False, shared=library.suffix == ".so"), time=self.arc_time))
+
+ if not module_data_added:
+ library_name = None
+ if module_info["type"] == "library":
+ library_name = Path(module_info["library"]).stem.removeprefix("lib")
+ export_libraries = module_info.get("export-libraries", [])
+ archive_file_tree.add_file(NodeInArchive.from_text(arcpath=arc_join(arcdir_prefab_module, "module.json"), text=self._get_prefab_module_json_text(library_name=library_name, export_libraries=export_libraries), time=self.arc_time))
+ arcdir_prefab_include = f"prefab/modules/{module_name}/include"
+ if "includes" in module_info:
+ archive_file_tree.add_file_mapping(arc_dir=arcdir_prefab_include, file_mapping=module_info["includes"], file_mapping_root=install_dir, context=self.get_context(), time=self.arc_time)
+ else:
+ archive_file_tree.add_file(NodeInArchive.from_text(arcpath=arc_join(arcdir_prefab_include, ".keep"), text="\n", time=self.arc_time))
+ module_data_added = True
+
+ if not java_jars_added:
+ java_jars_added = True
+ if "jars" in self.release_info["android"]:
+ classes_jar_path = install_dir / configure_text(text=self.release_info["android"]["jars"]["classes"], context=self.get_context())
+ sources_jar_path = install_dir / configure_text(text=self.release_info["android"]["jars"]["sources"], context=self.get_context())
+ doc_jar_path = install_dir / configure_text(text=self.release_info["android"]["jars"]["doc"], context=self.get_context())
+ assert classes_jar_path.is_file(), f"CMake should have compiled the java sources and archived them into a JAR ({classes_jar_path})"
+ assert sources_jar_path.is_file(), f"CMake should have archived the java sources into a JAR ({sources_jar_path})"
+ assert doc_jar_path.is_file(), f"CMake should have archived javadoc into a JAR ({doc_jar_path})"
+
+ archive_file_tree.add_file(NodeInArchive.from_fs(arcpath="classes.jar", path=classes_jar_path, time=self.arc_time))
+ archive_file_tree.add_file(NodeInArchive.from_fs(arcpath="classes-sources.jar", path=sources_jar_path, time=self.arc_time))
+ archive_file_tree.add_file(NodeInArchive.from_fs(arcpath="classes-doc.jar", path=doc_jar_path, time=self.arc_time))
+
+ assert ("jars" in self.release_info["android"] and java_jars_added) or "jars" not in self.release_info["android"], "Must have archived java JAR archives"
+
+ archive_file_tree.add_file_mapping(arc_dir="", file_mapping=self.release_info["android"].get("files", {}), file_mapping_root=self.root, context=self.get_context(), time=self.arc_time)
+
+ archive_file_tree.add_file(NodeInArchive.from_text(arcpath="prefab/prefab.json", text=self._get_prefab_json_text(), time=self.arc_time))
+ archive_file_tree.add_file(NodeInArchive.from_text(arcpath="AndroidManifest.xml", text=self._get_android_manifest_text(), time=self.arc_time))
+
+ with Archiver(zip_path=aar_path) as archiver:
+ archive_file_tree.add_to_archiver(archive_base="", archiver=archiver)
+ archiver.add_git_hash(arcdir="", commit=self.commit, time=self.arc_time)
+ self.artifacts[f"android-aar"] = aar_path
+
+ def download_dependencies(self):
+ shutil.rmtree(self.deps_path, ignore_errors=True)
+ self.deps_path.mkdir(parents=True)
+
+ if self.github:
+ with open(os.environ["GITHUB_OUTPUT"], "a") as f:
+ f.write(f"dep-path={self.deps_path.absolute()}\n")
+
+ for dep, depinfo in self.release_info.get("dependencies", {}).items():
+ startswith = depinfo["startswith"]
+ dep_repo = depinfo["repo"]
+ # FIXME: dropped "--exclude-pre-releases"
+ dep_string_data = self.executer.check_output(["gh", "-R", dep_repo, "release", "list", "--exclude-drafts", "--json", "name,createdAt,tagName", "--jq", f'[.[]|select(.name|startswith("{startswith}"))]|max_by(.createdAt)']).strip()
+ dep_data = json.loads(dep_string_data)
+ dep_tag = dep_data["tagName"]
+ dep_version = dep_data["name"]
+ logger.info("Download dependency %s version %s (tag=%s) ", dep, dep_version, dep_tag)
+ self.executer.run(["gh", "-R", dep_repo, "release", "download", dep_tag], cwd=self.deps_path)
+ if self.github:
+ with open(os.environ["GITHUB_OUTPUT"], "a") as f:
+ f.write(f"dep-{dep.lower()}-version={dep_version}\n")
+
+ def verify_dependencies(self):
+ for dep, depinfo in self.release_info.get("dependencies", {}).items():
+ if "mingw" in self.release_info:
+ mingw_matches = glob.glob(self.release_info["mingw"]["dependencies"][dep]["artifact"], root_dir=self.deps_path)
+ assert len(mingw_matches) == 1, f"Exactly one archive matches mingw {dep} dependency: {mingw_matches}"
+ if "dmg" in self.release_info:
+ dmg_matches = glob.glob(self.release_info["dmg"]["dependencies"][dep]["artifact"], root_dir=self.deps_path)
+ assert len(dmg_matches) == 1, f"Exactly one archive matches dmg {dep} dependency: {dmg_matches}"
+ if "msvc" in self.release_info:
+ msvc_matches = glob.glob(self.release_info["msvc"]["dependencies"][dep]["artifact"], root_dir=self.deps_path)
+ assert len(msvc_matches) == 1, f"Exactly one archive matches msvc {dep} dependency: {msvc_matches}"
+ if "android" in self.release_info:
+ android_matches = glob.glob(self.release_info["android"]["dependencies"][dep]["artifact"], root_dir=self.deps_path)
+ assert len(android_matches) == 1, f"Exactly one archive matches msvc {dep} dependency: {msvc_matches}"
+
+ @staticmethod
+ def _arch_to_vs_platform(arch: str, configuration: str="Release") -> VsArchPlatformConfig:
+ ARCH_TO_VS_PLATFORM = {
+ "x86": VsArchPlatformConfig(arch="x86", platform="Win32", configuration=configuration),
+ "x64": VsArchPlatformConfig(arch="x64", platform="x64", configuration=configuration),
+ "arm64": VsArchPlatformConfig(arch="arm64", platform="ARM64", configuration=configuration),
+ }
+ return ARCH_TO_VS_PLATFORM[arch]
+
+ def build_msvc(self):
+ with self.section_printer.group("Find Visual Studio"):
+ vs = VisualStudio(executer=self.executer)
+ for arch in self.release_info["msvc"].get("msbuild", {}).get("archs", []):
+ self._build_msvc_msbuild(arch_platform=self._arch_to_vs_platform(arch=arch), vs=vs)
+ if "cmake" in self.release_info["msvc"]:
+ deps_path = self.root / "msvc-deps"
+ shutil.rmtree(deps_path, ignore_errors=True)
+ dep_roots = []
+ for dep, depinfo in self.release_info["msvc"].get("dependencies", {}).items():
+ dep_extract_path = deps_path / f"extract-{dep}"
+ msvc_zip = self.deps_path / glob.glob(depinfo["artifact"], root_dir=self.deps_path)[0]
+ with zipfile.ZipFile(msvc_zip, "r") as zf:
+ zf.extractall(dep_extract_path)
+ contents_msvc_zip = glob.glob(str(dep_extract_path / "*"))
+ assert len(contents_msvc_zip) == 1, f"There must be exactly one root item in the root directory of {dep}"
+ dep_roots.append(contents_msvc_zip[0])
+
+ for arch in self.release_info["msvc"].get("cmake", {}).get("archs", []):
+ self._build_msvc_cmake(arch_platform=self._arch_to_vs_platform(arch=arch), dep_roots=dep_roots)
+ with self.section_printer.group("Create SDL VC development zip"):
+ self._build_msvc_devel()
+
+ def _build_msvc_msbuild(self, arch_platform: VsArchPlatformConfig, vs: VisualStudio):
+ platform_context = self.get_context(arch_platform.extra_context())
+ for dep, depinfo in self.release_info["msvc"].get("dependencies", {}).items():
+ msvc_zip = self.deps_path / glob.glob(depinfo["artifact"], root_dir=self.deps_path)[0]
+
+ src_globs = [configure_text(instr["src"], context=platform_context) for instr in depinfo["copy"]]
+ with zipfile.ZipFile(msvc_zip, "r") as zf:
+ for member in zf.namelist():
+ member_path = "/".join(Path(member).parts[1:])
+ for src_i, src_glob in enumerate(src_globs):
+ if fnmatch.fnmatch(member_path, src_glob):
+ dst = (self.root / configure_text(depinfo["copy"][src_i]["dst"], context=platform_context)).resolve() / Path(member_path).name
+ zip_data = zf.read(member)
+ if dst.exists():
+ identical = False
+ if dst.is_file():
+ orig_bytes = dst.read_bytes()
+ if orig_bytes == zip_data:
+ identical = True
+ if not identical:
+ logger.warning("Extracting dependency %s, will cause %s to be overwritten", dep, dst)
+ if not self.overwrite:
+ raise RuntimeError("Run with --overwrite to allow overwriting")
+ logger.debug("Extracting %s -> %s", member, dst)
+
+ dst.parent.mkdir(exist_ok=True, parents=True)
+ dst.write_bytes(zip_data)
+
+ prebuilt_paths = set(self.root / full_prebuilt_path for prebuilt_path in self.release_info["msvc"]["msbuild"].get("prebuilt", []) for full_prebuilt_path in glob.glob(configure_text(prebuilt_path, context=platform_context), root_dir=self.root))
+ msbuild_paths = set(self.root / configure_text(f, context=platform_context) for file_mapping in (self.release_info["msvc"]["msbuild"]["files-lib"], self.release_info["msvc"]["msbuild"]["files-devel"]) for files_list in file_mapping.values() for f in files_list)
+ assert prebuilt_paths.issubset(msbuild_paths), f"msvc.msbuild.prebuilt must be a subset of (msvc.msbuild.files-lib, msvc.msbuild.files-devel)"
+ built_paths = msbuild_paths.difference(prebuilt_paths)
+ logger.info("MSbuild builds these files, to be included in the package: %s", built_paths)
+ if not self.fast:
+ for b in built_paths:
+ b.unlink(missing_ok=True)
+
+ rel_projects: list[str] = self.release_info["msvc"]["msbuild"]["projects"]
+ projects = list(self.root / p for p in rel_projects)
+
+ directory_build_props_src_relpath = self.release_info["msvc"]["msbuild"].get("directory-build-props")
+ for project in projects:
+ dir_b_props = project.parent / "Directory.Build.props"
+ dir_b_props.unlink(missing_ok = True)
+ if directory_build_props_src_relpath:
+ src = self.root / directory_build_props_src_relpath
+ logger.debug("Copying %s -> %s", src, dir_b_props)
+ shutil.copy(src=src, dst=dir_b_props)
+
+ with self.section_printer.group(f"Build {arch_platform.arch} VS binary"):
+ vs.build(arch_platform=arch_platform, projects=projects)
+
+ if self.dry:
+ for b in built_paths:
+ b.parent.mkdir(parents=True, exist_ok=True)
+ b.touch()
+
+ for b in built_paths:
+ assert b.is_file(), f"{b} has not been created"
+ b.parent.mkdir(parents=True, exist_ok=True)
+ b.touch()
+
+ zip_path = self.dist_path / f"{self.project}-{self.version}-win32-{arch_platform.arch}.zip"
+ zip_path.unlink(missing_ok=True)
+
+ logger.info("Collecting files...")
+ archive_file_tree = ArchiveFileTree()
+ archive_file_tree.add_file_mapping(arc_dir="", file_mapping=self.release_info["msvc"]["msbuild"]["files-lib"], file_mapping_root=self.root, context=platform_context, time=self.arc_time)
+ archive_file_tree.add_file_mapping(arc_dir="", file_mapping=self.release_info["msvc"]["files-lib"], file_mapping_root=self.root, context=platform_context, time=self.arc_time)
+
+ logger.info("Writing to %s", zip_path)
+ with Archiver(zip_path=zip_path) as archiver:
+ arc_root = f""
+ archive_file_tree.add_to_archiver(archive_base=arc_root, archiver=archiver)
+ archiver.add_git_hash(arcdir=arc_root, commit=self.commit, time=self.arc_time)
+ self.artifacts[f"VC-{arch_platform.arch}"] = zip_path
+
+ for p in built_paths:
+ assert p.is_file(), f"{p} should exist"
+
+ def _arch_platform_to_build_path(self, arch_platform: VsArchPlatformConfig) -> Path:
+ return self.root / f"build-vs-{arch_platform.arch}"
+
+ def _arch_platform_to_install_path(self, arch_platform: VsArchPlatformConfig) -> Path:
+ return self._arch_platform_to_build_path(arch_platform) / "prefix"
+
+ def _build_msvc_cmake(self, arch_platform: VsArchPlatformConfig, dep_roots: list[Path]):
+ build_path = self._arch_platform_to_build_path(arch_platform)
+ install_path = self._arch_platform_to_install_path(arch_platform)
+ platform_context = self.get_context(extra_context=arch_platform.extra_context())
+
+ build_type = "Release"
+
+ built_paths = set(install_path / configure_text(f, context=platform_context) for file_mapping in (self.release_info["msvc"]["cmake"]["files-lib"], self.release_info["msvc"]["cmake"]["files-devel"]) for files_list in file_mapping.values() for f in files_list)
+ logger.info("CMake builds these files, to be included in the package: %s", built_paths)
+ if not self.fast:
+ for b in built_paths:
+ b.unlink(missing_ok=True)
+
+ shutil.rmtree(install_path, ignore_errors=True)
+ build_path.mkdir(parents=True, exist_ok=True)
+ with self.section_printer.group(f"Configure VC CMake project for {arch_platform.arch}"):
+ self.executer.run([
+ "cmake", "-S", str(self.root), "-B", str(build_path),
+ "-A", arch_platform.platform,
+ "-DCMAKE_INSTALL_BINDIR=bin",
+ "-DCMAKE_INSTALL_DATAROOTDIR=share",
+ "-DCMAKE_INSTALL_INCLUDEDIR=include",
+ "-DCMAKE_INSTALL_LIBDIR=lib",
+ f"-DCMAKE_BUILD_TYPE={build_type}",
+ f"-DCMAKE_INSTALL_PREFIX={install_path}",
+ # MSVC debug information format flags are selected by an abstraction
+ "-DCMAKE_POLICY_DEFAULT_CMP0141=NEW",
+ # MSVC debug information format
+ "-DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=ProgramDatabase",
+ # Linker flags for executables
+ "-DCMAKE_EXE_LINKER_FLAGS=-INCREMENTAL:NO -DEBUG -OPT:REF -OPT:ICF",
+ # Linker flag for shared libraries
+ "-DCMAKE_SHARED_LINKER_FLAGS=-INCREMENTAL:NO -DEBUG -OPT:REF -OPT:ICF",
+ # MSVC runtime library flags are selected by an abstraction
+ "-DCMAKE_POLICY_DEFAULT_CMP0091=NEW",
+ # Use statically linked runtime (-MT) (ideally, should be "MultiThreaded$<$:Debug>")
+ "-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded",
+ f"-DCMAKE_PREFIX_PATH={';'.join(str(s) for s in dep_roots)}",
+ ] + self.release_info["msvc"]["cmake"]["args"] + ([] if self.fast else ["--fresh"]))
+
+ with self.section_printer.group(f"Build VC CMake project for {arch_platform.arch}"):
+ self.executer.run(["cmake", "--build", str(build_path), "--verbose", "--config", build_type])
+ with self.section_printer.group(f"Install VC CMake project for {arch_platform.arch}"):
+ self.executer.run(["cmake", "--install", str(build_path), "--config", build_type])
+
+ if self.dry:
+ for b in built_paths:
+ b.parent.mkdir(parents=True, exist_ok=True)
+ b.touch()
+
+ zip_path = self.dist_path / f"{self.project}-{self.version}-win32-{arch_platform.arch}.zip"
+ zip_path.unlink(missing_ok=True)
+
+ logger.info("Collecting files...")
+ archive_file_tree = ArchiveFileTree()
+ archive_file_tree.add_file_mapping(arc_dir="", file_mapping=self.release_info["msvc"]["cmake"]["files-lib"], file_mapping_root=install_path, context=platform_context, time=self.arc_time)
+ archive_file_tree.add_file_mapping(arc_dir="", file_mapping=self.release_info["msvc"]["files-lib"], file_mapping_root=self.root, context=self.get_context(), time=self.arc_time)
+
+ logger.info("Creating %s", zip_path)
+ with Archiver(zip_path=zip_path) as archiver:
+ arc_root = f""
+ archive_file_tree.add_to_archiver(archive_base=arc_root, archiver=archiver)
+ archiver.add_git_hash(arcdir=arc_root, commit=self.commit, time=self.arc_time)
+
+ for p in built_paths:
+ assert p.is_file(), f"{p} should exist"
+
+ def _build_msvc_devel(self) -> None:
+ zip_path = self.dist_path / f"{self.project}-devel-{self.version}-VC.zip"
+ arc_root = f"{self.project}-{self.version}"
+
+ logger.info("Collecting files...")
+ archive_file_tree = ArchiveFileTree()
+ if "msbuild" in self.release_info["msvc"]:
+ for arch in self.release_info["msvc"]["msbuild"]["archs"]:
+ arch_platform = self._arch_to_vs_platform(arch=arch)
+ platform_context = self.get_context(arch_platform.extra_context())
+ archive_file_tree.add_file_mapping(arc_dir=arc_root, file_mapping=self.release_info["msvc"]["msbuild"]["files-devel"], file_mapping_root=self.root, context=platform_context, time=self.arc_time)
+ if "cmake" in self.release_info["msvc"]:
+ for arch in self.release_info["msvc"]["cmake"]["archs"]:
+ arch_platform = self._arch_to_vs_platform(arch=arch)
+ platform_context = self.get_context(arch_platform.extra_context())
+ archive_file_tree.add_file_mapping(arc_dir=arc_root, file_mapping=self.release_info["msvc"]["cmake"]["files-devel"], file_mapping_root=self._arch_platform_to_install_path(arch_platform), context=platform_context, time=self.arc_time)
+ archive_file_tree.add_file_mapping(arc_dir=arc_root, file_mapping=self.release_info["msvc"]["files-devel"], file_mapping_root=self.root, context=self.get_context(), time=self.arc_time)
+
+ with Archiver(zip_path=zip_path) as archiver:
+ archive_file_tree.add_to_archiver(archive_base="", archiver=archiver)
+ archiver.add_git_hash(arcdir=arc_root, commit=self.commit, time=self.arc_time)
+ self.artifacts["VC-devel"] = zip_path
+
+ @classmethod
+ def extract_sdl_version(cls, root: Path, release_info: dict) -> str:
+ with open(root / release_info["version"]["file"], "r") as f:
+ text = f.read()
+ major = next(re.finditer(release_info["version"]["re_major"], text, flags=re.M)).group(1)
+ minor = next(re.finditer(release_info["version"]["re_minor"], text, flags=re.M)).group(1)
+ micro = next(re.finditer(release_info["version"]["re_micro"], text, flags=re.M)).group(1)
+ return f"{major}.{minor}.{micro}"
+
+
+def main(argv=None) -> int:
+ if sys.version_info < (3, 11):
+ logger.error("This script needs at least python 3.11")
+ return 1
+
+ parser = argparse.ArgumentParser(allow_abbrev=False, description="Create SDL release artifacts")
+ parser.add_argument("--root", metavar="DIR", type=Path, default=Path(__file__).absolute().parents[1], help="Root of project")
+ parser.add_argument("--release-info", metavar="JSON", dest="path_release_info", type=Path, default=Path(__file__).absolute().parent / "release-info.json", help="Path of release-info.json")
+ parser.add_argument("--dependency-folder", metavar="FOLDER", dest="deps_path", type=Path, default="deps", help="Directory containing pre-built archives of dependencies (will be removed when downloading archives)")
+ parser.add_argument("--out", "-o", metavar="DIR", dest="dist_path", type=Path, default="dist", help="Output directory")
+ parser.add_argument("--github", action="store_true", help="Script is running on a GitHub runner")
+ parser.add_argument("--commit", default="HEAD", help="Git commit/tag of which a release should be created")
+ parser.add_argument("--actions", choices=["download", "source", "android", "mingw", "msvc", "dmg"], required=True, nargs="+", dest="actions", help="What to do?")
+ parser.set_defaults(loglevel=logging.INFO)
+ parser.add_argument('--vs-year', dest="vs_year", help="Visual Studio year")
+ parser.add_argument('--android-api', type=int, dest="android_api", help="Android API version")
+ parser.add_argument('--android-home', dest="android_home", default=os.environ.get("ANDROID_HOME"), help="Android Home folder")
+ parser.add_argument('--android-ndk-home', dest="android_ndk_home", default=os.environ.get("ANDROID_NDK_HOME"), help="Android NDK Home folder")
+ parser.add_argument('--cmake-generator', dest="cmake_generator", default="Ninja", help="CMake Generator")
+ parser.add_argument('--debug', action='store_const', const=logging.DEBUG, dest="loglevel", help="Print script debug information")
+ parser.add_argument('--dry-run', action='store_true', dest="dry", help="Don't execute anything")
+ parser.add_argument('--force', action='store_true', dest="force", help="Ignore a non-clean git tree")
+ parser.add_argument('--overwrite', action='store_true', dest="overwrite", help="Allow potentially overwriting other projects")
+ parser.add_argument('--fast', action='store_true', dest="fast", help="Don't do a rebuild")
+
+ args = parser.parse_args(argv)
+ logging.basicConfig(level=args.loglevel, format='[%(levelname)s] %(message)s')
+ args.deps_path = args.deps_path.absolute()
+ args.dist_path = args.dist_path.absolute()
+ args.root = args.root.absolute()
+ args.dist_path = args.dist_path.absolute()
+ if args.dry:
+ args.dist_path = args.dist_path / "dry"
+
+ if args.github:
+ section_printer: SectionPrinter = GitHubSectionPrinter()
+ else:
+ section_printer = SectionPrinter()
+
+ if args.github and "GITHUB_OUTPUT" not in os.environ:
+ os.environ["GITHUB_OUTPUT"] = "/tmp/github_output.txt"
+
+ executer = Executer(root=args.root, dry=args.dry)
+
+ root_git_hash_path = args.root / GIT_HASH_FILENAME
+ root_is_maybe_archive = root_git_hash_path.is_file()
+ if root_is_maybe_archive:
+ logger.warning("%s detected: Building from archive", GIT_HASH_FILENAME)
+ archive_commit = root_git_hash_path.read_text().strip()
+ if args.commit != archive_commit:
+ logger.warning("Commit argument is %s, but archive commit is %s. Using %s.", args.commit, archive_commit, archive_commit)
+ args.commit = archive_commit
+ revision = (args.root / REVISION_TXT).read_text().strip()
+ else:
+ args.commit = executer.check_output(["git", "rev-parse", args.commit], dry_out="e5812a9fd2cda317b503325a702ba3c1c37861d9").strip()
+ revision = executer.check_output(["git", "describe", "--always", "--tags", "--long", args.commit], dry_out="preview-3.1.3-96-g9512f2144").strip()
+ logger.info("Using commit %s", args.commit)
+
+ try:
+ with args.path_release_info.open() as f:
+ release_info = json.load(f)
+ except FileNotFoundError:
+ logger.error(f"Could not find {args.path_release_info}")
+
+ releaser = Releaser(
+ release_info=release_info,
+ commit=args.commit,
+ revision=revision,
+ root=args.root,
+ dist_path=args.dist_path,
+ executer=executer,
+ section_printer=section_printer,
+ cmake_generator=args.cmake_generator,
+ deps_path=args.deps_path,
+ overwrite=args.overwrite,
+ github=args.github,
+ fast=args.fast,
+ )
+
+ if root_is_maybe_archive:
+ logger.warning("Building from archive. Skipping clean git tree check.")
+ else:
+ porcelain_status = executer.check_output(["git", "status", "--ignored", "--porcelain"], dry_out="\n").strip()
+ if porcelain_status:
+ print(porcelain_status)
+ logger.warning("The tree is dirty! Do not publish any generated artifacts!")
+ if not args.force:
+ raise Exception("The git repo contains modified and/or non-committed files. Run with --force to ignore.")
+
+ if args.fast:
+ logger.warning("Doing fast build! Do not publish generated artifacts!")
+
+ with section_printer.group("Arguments"):
+ print(f"project = {releaser.project}")
+ print(f"version = {releaser.version}")
+ print(f"revision = {revision}")
+ print(f"commit = {args.commit}")
+ print(f"out = {args.dist_path}")
+ print(f"actions = {args.actions}")
+ print(f"dry = {args.dry}")
+ print(f"force = {args.force}")
+ print(f"overwrite = {args.overwrite}")
+ print(f"cmake_generator = {args.cmake_generator}")
+
+ releaser.prepare()
+
+ if "download" in args.actions:
+ releaser.download_dependencies()
+
+ if set(args.actions).intersection({"msvc", "mingw", "android"}):
+ print("Verifying presence of dependencies (run 'download' action to download) ...")
+ releaser.verify_dependencies()
+ print("... done")
+
+ if "source" in args.actions:
+ if root_is_maybe_archive:
+ raise Exception("Cannot build source archive from source archive")
+ with section_printer.group("Create source archives"):
+ releaser.create_source_archives()
+
+ if "dmg" in args.actions:
+ if platform.system() != "Darwin" and not args.dry:
+ parser.error("framework artifact(s) can only be built on Darwin")
+
+ releaser.create_dmg()
+
+ if "msvc" in args.actions:
+ if platform.system() != "Windows" and not args.dry:
+ parser.error("msvc artifact(s) can only be built on Windows")
+ releaser.build_msvc()
+
+ if "mingw" in args.actions:
+ releaser.create_mingw_archives()
+
+ if "android" in args.actions:
+ if args.android_home is None or not Path(args.android_home).is_dir():
+ parser.error("Invalid $ANDROID_HOME or --android-home: must be a directory containing the Android SDK")
+ if args.android_ndk_home is None or not Path(args.android_ndk_home).is_dir():
+ parser.error("Invalid $ANDROID_NDK_HOME or --android_ndk_home: must be a directory containing the Android NDK")
+ if args.android_api is None:
+ with section_printer.group("Detect Android APIS"):
+ args.android_api = releaser._detect_android_api(android_home=args.android_home)
+ if args.android_api is None or not (Path(args.android_home) / f"platforms/android-{args.android_api}").is_dir():
+ parser.error("Invalid --android-api, and/or could not be detected")
+ with section_printer.group("Android arguments"):
+ print(f"android_home = {args.android_home}")
+ print(f"android_ndk_home = {args.android_ndk_home}")
+ print(f"android_api = {args.android_api}")
+ releaser.create_android_archives(
+ android_api=args.android_api,
+ android_home=args.android_home,
+ android_ndk_home=args.android_ndk_home,
+ )
+ with section_printer.group("Summary"):
+ print(f"artifacts = {releaser.artifacts}")
+
+ if args.github:
+ with open(os.environ["GITHUB_OUTPUT"], "a") as f:
+ f.write(f"project={releaser.project}\n")
+ f.write(f"version={releaser.version}\n")
+ for k, v in releaser.artifacts.items():
+ f.write(f"{k}={v.name}\n")
+ return 0
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())
diff --git a/build-scripts/cmake-toolchain-mingw64-i686.cmake b/build-scripts/cmake-toolchain-mingw64-i686.cmake
new file mode 100644
index 00000000..8be7b3a8
--- /dev/null
+++ b/build-scripts/cmake-toolchain-mingw64-i686.cmake
@@ -0,0 +1,18 @@
+set(CMAKE_SYSTEM_NAME Windows)
+set(CMAKE_SYSTEM_PROCESSOR x86)
+
+find_program(CMAKE_C_COMPILER NAMES i686-w64-mingw32-gcc)
+find_program(CMAKE_CXX_COMPILER NAMES i686-w64-mingw32-g++)
+find_program(CMAKE_RC_COMPILER NAMES i686-w64-mingw32-windres windres)
+
+if(NOT CMAKE_C_COMPILER)
+ message(FATAL_ERROR "Failed to find CMAKE_C_COMPILER.")
+endif()
+
+if(NOT CMAKE_CXX_COMPILER)
+ message(FATAL_ERROR "Failed to find CMAKE_CXX_COMPILER.")
+endif()
+
+if(NOT CMAKE_RC_COMPILER)
+ message(FATAL_ERROR "Failed to find CMAKE_RC_COMPILER.")
+endif()
diff --git a/build-scripts/cmake-toolchain-mingw64-x86_64.cmake b/build-scripts/cmake-toolchain-mingw64-x86_64.cmake
new file mode 100644
index 00000000..8bf43669
--- /dev/null
+++ b/build-scripts/cmake-toolchain-mingw64-x86_64.cmake
@@ -0,0 +1,18 @@
+set(CMAKE_SYSTEM_NAME Windows)
+set(CMAKE_SYSTEM_PROCESSOR x86_64)
+
+find_program(CMAKE_C_COMPILER NAMES x86_64-w64-mingw32-gcc)
+find_program(CMAKE_CXX_COMPILER NAMES x86_64-w64-mingw32-g++)
+find_program(CMAKE_RC_COMPILER NAMES x86_64-w64-mingw32-windres windres)
+
+if(NOT CMAKE_C_COMPILER)
+ message(FATAL_ERROR "Failed to find CMAKE_C_COMPILER.")
+endif()
+
+if(NOT CMAKE_CXX_COMPILER)
+ message(FATAL_ERROR "Failed to find CMAKE_CXX_COMPILER.")
+endif()
+
+if(NOT CMAKE_RC_COMPILER)
+ message(FATAL_ERROR "Failed to find CMAKE_RC_COMPILER.")
+endif()
diff --git a/build-scripts/create-release.py b/build-scripts/create-release.py
new file mode 100755
index 00000000..2e1fd559
--- /dev/null
+++ b/build-scripts/create-release.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+
+import argparse
+from pathlib import Path
+import json
+import logging
+import re
+import subprocess
+
+ROOT = Path(__file__).resolve().parents[1]
+
+
+def determine_project() -> str:
+ text = (ROOT / "build-scripts/release-info.json").read_text()
+ release_info = json.loads(text)
+ project_with_version = release_info["name"]
+ project, _ = re.subn("([^a-zA-Z_])", "", project_with_version)
+ return project
+
+
+def main():
+ project = determine_project()
+ default_remote = f"libsdl-org/{project}"
+
+ current_commit = subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=ROOT, text=True).strip()
+
+ parser = argparse.ArgumentParser(allow_abbrev=False)
+ parser.add_argument("--ref", required=True, help=f"Name of branch or tag containing release.yml")
+ parser.add_argument("--remote", "-R", default=default_remote, help=f"Remote repo (default={default_remote})")
+ parser.add_argument("--commit", default=current_commit, help=f"Commit (default={current_commit})")
+ args = parser.parse_args()
+
+
+ print(f"Running release.yml workflow:")
+ print(f" commit = {args.commit}")
+ print(f" remote = {args.remote}")
+
+ subprocess.check_call(["gh", "-R", args.remote, "workflow", "run", "release.yml", "--ref", args.ref, "-f", f"commit={args.commit}"], cwd=ROOT)
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())
diff --git a/build-scripts/pkg-support/android/INSTALL.md.in b/build-scripts/pkg-support/android/INSTALL.md.in
new file mode 100644
index 00000000..136de4ed
--- /dev/null
+++ b/build-scripts/pkg-support/android/INSTALL.md.in
@@ -0,0 +1,61 @@
+This Android archive allows use of @<@PROJECT_NAME@>@ in your Android project, without needing to copy any SDL source.
+For integration with CMake/ndk-build, it uses [prefab](https://google.github.io/prefab/).
+
+Copy this archive (@<@PROJECT_NAME@>@-@<@PROJECT_VERSION@>@.aar) to a `app/libs` directory of your project.
+
+In `app/build.gradle` of your Android project, add:
+```
+android {
+ /* ... */
+ buildFeatures {
+ prefab true
+ }
+}
+dependencies {
+ implementation files('libs/@<@PROJECT_NAME@>@-@<@PROJECT_VERSION@>@.aar')
+ /* ... */
+}
+```
+
+If you're using CMake, add the following to your CMakeLists.txt:
+```
+find_package(@<@PROJECT_NAME@>@ REQUIRED CONFIG)
+target_link_libraries(yourgame PRIVATE @<@PROJECT_NAME@>@::@<@PROJECT_NAME@>@)
+```
+
+If you use ndk-build, add the following before `include $(BUILD_SHARED_LIBRARY)` to your `Android.mk`:
+```
+LOCAL_SHARED_LIBARARIES := @<@PROJECT_NAME@>@
+```
+And add the following at the bottom:
+```
+# https://google.github.io/prefab/build-systems.html
+
+# Add the prefab modules to the import path.
+$(call import-add-path,/out)
+
+# Import @<@PROJECT_NAME@>@ so we can depend on it.
+$(call import-module,prefab/@<@PROJECT_NAME@>@)
+```
+
+---
+
+For advanced users:
+
+If you want to build a 3rd party library outside Gradle,
+running the following command will extract the Android archive into a more common directory structure.
+```
+python @<@PROJECT_NAME@>@-@PROJECT_VERSION@.aar -o android_prefix
+```
+Add `--help` for a list of all available options.
+
+
+Look at the example programs in ./test (of the source archive), and check out online documentation:
+ https://wiki.libsdl.org/SDL3/FrontPage
+
+Join the SDL discourse server if you want to join the community:
+ https://discourse.libsdl.org/
+
+
+That's it!
+Sam Lantinga
diff --git a/build-scripts/pkg-support/android/__main__.py.in b/build-scripts/pkg-support/android/__main__.py.in
new file mode 100755
index 00000000..344cf719
--- /dev/null
+++ b/build-scripts/pkg-support/android/__main__.py.in
@@ -0,0 +1,104 @@
+#!/usr/bin/env python
+
+"""
+Create a @<@PROJECT_NAME@>@ SDK prefix from an Android archive
+This file is meant to be placed in a the root of an android .aar archive
+
+Example usage:
+```sh
+python @<@PROJECT_NAME@>@-@<@PROJECT_VERSION@>@.aar -o /usr/opt/android-sdks
+cmake -S my-project \
+ -DCMAKE_PREFIX_PATH=/usr/opt/android-sdks \
+ -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake \
+ -B build-arm64 -DANDROID_ABI=arm64-v8a \
+ -DCMAKE_BUILD_TYPE=Releaase
+cmake --build build-arm64
+```
+"""
+import argparse
+import io
+import json
+import os
+import pathlib
+import re
+import stat
+import zipfile
+
+
+AAR_PATH = pathlib.Path(__file__).resolve().parent
+ANDROID_ARCHS = { "armeabi-v7a", "arm64-v8a", "x86", "x86_64" }
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description="Convert a @<@PROJECT_NAME@>@ Android .aar archive into a SDK",
+ allow_abbrev=False,
+ )
+ parser.add_argument("--version", action="version", version="@<@PROJECT_NAME@>@ @<@PROJECT_VERSION@>@")
+ parser.add_argument("-o", dest="output", type=pathlib.Path, required=True, help="Folder where to store the SDK")
+ args = parser.parse_args()
+
+ print(f"Creating a @<@PROJECT_NAME@>@ SDK at {args.output}...")
+
+ prefix = args.output
+ incdir = prefix / "include"
+ libdir = prefix / "lib"
+
+ RE_LIB_MODULE_ARCH = re.compile(r"prefab/modules/(?P[A-Za-z0-9_-]+)/libs/android\.(?P[a-zA-Z0-9_-]+)/(?Plib[A-Za-z0-9_]+\.(?:so|a))")
+ RE_INC_MODULE_ARCH = re.compile(r"prefab/modules/(?P[A-Za-z0-9_-]+)/include/(?P[a-zA-Z0-9_./-]+)")
+ RE_LICENSE = re.compile(r"(?:.*/)?(?P(?:license|copying)(?:\.md|\.txt)?)", flags=re.I)
+ RE_PROGUARD = re.compile(r"(?:.*/)?(?Pproguard.*\.(?:pro|txt))", flags=re.I)
+ RE_CMAKE = re.compile(r"(?:.*/)?(?P.*\.cmake)", flags=re.I)
+
+ with zipfile.ZipFile(AAR_PATH) as zf:
+ project_description = json.loads(zf.read("description.json"))
+ project_name = project_description["name"]
+ project_version = project_description["version"]
+ licensedir = prefix / "share/licenses" / project_name
+ cmakedir = libdir / "cmake" / project_name
+ javadir = prefix / "share/java" / project_name
+ javadocdir = prefix / "share/javadoc" / project_name
+
+ def read_zipfile_and_write(path: pathlib.Path, zippath: str):
+ data = zf.read(zippath)
+ path.parent.mkdir(parents=True, exist_ok=True)
+ path.write_bytes(data)
+
+ for zip_info in zf.infolist():
+ zippath = zip_info.filename
+ if m := RE_LIB_MODULE_ARCH.match(zippath):
+ lib_path = libdir / m["arch"] / m["filename"]
+ read_zipfile_and_write(lib_path, zippath)
+ if m["filename"].endswith(".so"):
+ os.chmod(lib_path, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)
+
+ elif m := RE_INC_MODULE_ARCH.match(zippath):
+ header_path = incdir / m["header"]
+ read_zipfile_and_write(header_path, zippath)
+ elif m:= RE_LICENSE.match(zippath):
+ license_path = licensedir / m["filename"]
+ read_zipfile_and_write(license_path, zippath)
+ elif m:= RE_PROGUARD.match(zippath):
+ proguard_path = javadir / m["filename"]
+ read_zipfile_and_write(proguard_path, zippath)
+ elif m:= RE_CMAKE.match(zippath):
+ cmake_path = cmakedir / m["filename"]
+ read_zipfile_and_write(cmake_path, zippath)
+ elif zippath == "classes.jar":
+ versioned_jar_path = javadir / f"{project_name}-{project_version}.jar"
+ unversioned_jar_path = javadir / f"{project_name}.jar"
+ read_zipfile_and_write(versioned_jar_path, zippath)
+ os.symlink(src=versioned_jar_path.name, dst=unversioned_jar_path)
+ elif zippath == "classes-sources.jar":
+ jarpath = javadir / f"{project_name}-{project_version}-sources.jar"
+ read_zipfile_and_write(jarpath, zippath)
+ elif zippath == "classes-doc.jar":
+ jarpath = javadocdir / f"{project_name}-{project_version}-javadoc.jar"
+ read_zipfile_and_write(jarpath, zippath)
+
+ print("... done")
+ return 0
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())
diff --git a/build-scripts/pkg-support/android/cmake/SDL3_imageConfig.cmake b/build-scripts/pkg-support/android/cmake/SDL3_imageConfig.cmake
new file mode 100644
index 00000000..3ae22f42
--- /dev/null
+++ b/build-scripts/pkg-support/android/cmake/SDL3_imageConfig.cmake
@@ -0,0 +1,128 @@
+# SDL CMake configuration file:
+# This file is meant to be placed in lib/cmake/SDL3_image subfolder of a reconstructed Android SDL3_image SDK
+
+cmake_minimum_required(VERSION 3.0...3.5)
+
+include(FeatureSummary)
+set_package_properties(SDL3_image PROPERTIES
+ URL "https://www.libsdl.org/projects/SDL_image/"
+ DESCRIPTION "SDL_image is an image file loading library"
+)
+
+# Copied from `configure_package_config_file`
+macro(set_and_check _var _file)
+ set(${_var} "${_file}")
+ if(NOT EXISTS "${_file}")
+ message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
+ endif()
+endmacro()
+
+set(SDLIMAGE_AVIF FALSE)
+set(SDLIMAGE_BMP TRUE)
+set(SDLIMAGE_GIF TRUE)
+set(SDLIMAGE_JPG TRUE)
+set(SDLIMAGE_JXL FALSE)
+set(SDLIMAGE_LBM TRUE)
+set(SDLIMAGE_PCX TRUE)
+set(SDLIMAGE_PNG TRUE)
+set(SDLIMAGE_PNM TRUE)
+set(SDLIMAGE_QOI TRUE)
+set(SDLIMAGE_SVG TRUE)
+set(SDLIMAGE_TGA TRUE)
+set(SDLIMAGE_TIF FALSE)
+set(SDLIMAGE_XCF FALSE)
+set(SDLIMAGE_XPM TRUE)
+set(SDLIMAGE_XV TRUE)
+set(SDLIMAGE_WEBP FALSE)
+
+set(SDLIMAGE_JPG_SAVE FALSE)
+set(SDLIMAGE_PNG_SAVE FALSE)
+
+set(SDLIMAGE_VENDORED FALSE)
+
+set(SDLIMAGE_BACKEND_IMAGEIO FALSE)
+set(SDLIMAGE_BACKEND_STB TRUE)
+set(SDLIMAGE_BACKEND_WIC FALSE)
+
+# Copied from `configure_package_config_file`
+macro(check_required_components _NAME)
+ foreach(comp ${${_NAME}_FIND_COMPONENTS})
+ if(NOT ${_NAME}_${comp}_FOUND)
+ if(${_NAME}_FIND_REQUIRED_${comp})
+ set(${_NAME}_FOUND FALSE)
+ endif()
+ endif()
+ endforeach()
+endmacro()
+
+set(SDL3_image_FOUND TRUE)
+
+if(SDL_CPU_X86)
+ set(_sdl_arch_subdir "x86")
+elseif(SDL_CPU_X64)
+ set(_sdl_arch_subdir "x86_64")
+elseif(SDL_CPU_ARM32)
+ set(_sdl_arch_subdir "armeabi-v7a")
+elseif(SDL_CPU_ARM64)
+ set(_sdl_arch_subdir "arm64-v8a")
+else()
+ set(SDL3_image_FOUND FALSE)
+ return()
+endif()
+
+get_filename_component(_sdl3_prefix "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE)
+get_filename_component(_sdl3_prefix "${_sdl3_prefix}/.." ABSOLUTE)
+get_filename_component(_sdl3_prefix "${_sdl3_prefix}/.." ABSOLUTE)
+set_and_check(_sdl3_prefix "${_sdl3_prefix}")
+set_and_check(_sdl3_include_dirs "${_sdl3_prefix}/include")
+
+set_and_check(_sdl3_lib "${_sdl3_prefix}/lib/${_sdl_arch_subdir}/libSDL3_image.so")
+
+unset(_sdl_arch_subdir)
+unset(_sdl3_prefix)
+
+# All targets are created, even when some might not be requested though COMPONENTS.
+# This is done for compatibility with CMake generated SDL3_image-target.cmake files.
+
+if(EXISTS "${_sdl3_lib}")
+ if(NOT TARGET SDL3_image::SDL3_image-shared)
+ add_library(SDL3_image::SDL3_image-shared SHARED IMPORTED)
+ set_target_properties(SDL3_image::SDL3_image-shared
+ PROPERTIES
+ IMPORTED_LOCATION "${_sdl3_lib}"
+ COMPATIBLE_INTERFACE_BOOL "SDL3_SHARED"
+ INTERFACE_SDL3_SHARED "ON"
+ COMPATIBLE_INTERFACE_STRING "SDL_VERSION"
+ INTERFACE_SDL_VERSION "SDL3"
+ )
+ endif()
+ set(SDL3_image_SDL3_image-shared_FOUND TRUE)
+else()
+ set(SDL3_image_SDL3_image-shared_FOUND FALSE)
+endif()
+unset(_sdl3_lib)
+
+set(SDL3_image_SDL3_image-static_FOUND FALSE)
+
+if(SDL3_image_SDL3_image-shared_FOUND)
+ set(SDL3_image_SDL3_image_FOUND TRUE)
+endif()
+
+function(_sdl_create_target_alias_compat NEW_TARGET TARGET)
+ if(CMAKE_VERSION VERSION_LESS "3.18")
+ # Aliasing local targets is not supported on CMake < 3.18, so make it global.
+ add_library(${NEW_TARGET} INTERFACE IMPORTED)
+ set_target_properties(${NEW_TARGET} PROPERTIES INTERFACE_LINK_LIBRARIES "${TARGET}")
+ else()
+ add_library(${NEW_TARGET} ALIAS ${TARGET})
+ endif()
+endfunction()
+
+# Make sure SDL3_image::SDL3_image always exists
+if(NOT TARGET SDL3_image::SDL3_image)
+ if(TARGET SDL3_image::SDL3_image-shared)
+ _sdl_create_target_alias_compat(SDL3_image::SDL3_image SDL3_image::SDL3_image-shared)
+ endif()
+endif()
+
+check_required_components(SDL3_image)
diff --git a/build-scripts/pkg-support/android/cmake/SDL3_imageConfigVersion.cmake.in b/build-scripts/pkg-support/android/cmake/SDL3_imageConfigVersion.cmake.in
new file mode 100644
index 00000000..0dae8ed6
--- /dev/null
+++ b/build-scripts/pkg-support/android/cmake/SDL3_imageConfigVersion.cmake.in
@@ -0,0 +1,33 @@
+# SDL_image CMake version configuration file:
+# This file is meant to be placed in a lib/cmake/SDL3_image subfolder of a reconstructed Android SDL3_image SDK
+
+set(PACKAGE_VERSION "@<@PROJECT_VERSION@>@")
+
+if(PACKAGE_FIND_VERSION_RANGE)
+ # Package version must be in the requested version range
+ if ((PACKAGE_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MIN)
+ OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_GREATER PACKAGE_FIND_VERSION_MAX)
+ OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_GREATER_EQUAL PACKAGE_FIND_VERSION_MAX)))
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+ else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ endif()
+else()
+ if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+ else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+ endif()
+endif()
+
+include("${CMAKE_CURRENT_LIST_DIR}/sdlcpu.cmake")
+SDL_DetectTargetCPUArchitectures(_detected_archs)
+
+# check that the installed version has a compatible architecture as the one which is currently searching:
+if(NOT(SDL_CPU_X86 OR SDL_CPU_X64 OR SDL_CPU_ARM32 OR SDL_CPU_ARM64))
+ set(PACKAGE_VERSION "${PACKAGE_VERSION} (X86,X64,ARM32,ARM64)")
+ set(PACKAGE_VERSION_UNSUITABLE TRUE)
+endif()
diff --git a/build-scripts/pkg-support/android/description.json.in b/build-scripts/pkg-support/android/description.json.in
new file mode 100644
index 00000000..e75ef382
--- /dev/null
+++ b/build-scripts/pkg-support/android/description.json.in
@@ -0,0 +1,5 @@
+{
+ "name": "@<@PROJECT_NAME@>@",
+ "version": "@<@PROJECT_VERSION@>@",
+ "git-hash": "@<@PROJECT_COMMIT@>@"
+}
diff --git a/build-scripts/pkg-support/mingw/Makefile b/build-scripts/pkg-support/mingw/Makefile
new file mode 100644
index 00000000..5d1330c4
--- /dev/null
+++ b/build-scripts/pkg-support/mingw/Makefile
@@ -0,0 +1,39 @@
+#
+# Makefile for installing the mingw32 version of the SDL_image library
+
+DESTDIR = /usr/local
+ARCHITECTURES := i686-w64-mingw32 x86_64-w64-mingw32
+
+default:
+ @echo "Run \"make install-i686\" to install 32-bit"
+ @echo "Run \"make install-x86_64\" to install 64-bit"
+ @echo "Run \"make install-all\" to install both"
+ @echo "Add DESTDIR=/custom/path to change the destination folder"
+
+install:
+ @if test -d $(ARCH) && test -d $(DESTDIR); then \
+ (cd $(ARCH) && cp -rv bin include lib share $(DESTDIR)/); \
+ else \
+ echo "*** ERROR: $(ARCH) or $(DESTDIR) does not exist!"; \
+ exit 1; \
+ fi
+
+install-i686:
+ $(MAKE) install ARCH=i686-w64-mingw32
+
+install-x86_64:
+ $(MAKE) install ARCH=x86_64-w64-mingw32
+
+install-all:
+ @if test -d $(DESTDIR); then \
+ mkdir -p $(DESTDIR)/cmake; \
+ cp -rv cmake/* $(DESTDIR)/cmake; \
+ for arch in $(ARCHITECTURES); do \
+ $(MAKE) install ARCH=$$arch DESTDIR=$(DESTDIR)/$$arch; \
+ done \
+ else \
+ echo "*** ERROR: $(DESTDIR) does not exist!"; \
+ exit 1; \
+ fi
+
+.PHONY: default install install-i686 install-x86_64 install-all
diff --git a/mingw/pkg-support/cmake/sdl3_image-config.cmake b/build-scripts/pkg-support/mingw/cmake/SDL3_imageConfig.cmake
similarity index 100%
rename from mingw/pkg-support/cmake/sdl3_image-config.cmake
rename to build-scripts/pkg-support/mingw/cmake/SDL3_imageConfig.cmake
diff --git a/mingw/pkg-support/cmake/sdl3_image-config-version.cmake b/build-scripts/pkg-support/mingw/cmake/SDL3_imageConfigVersion.cmake
similarity index 83%
rename from mingw/pkg-support/cmake/sdl3_image-config-version.cmake
rename to build-scripts/pkg-support/mingw/cmake/SDL3_imageConfigVersion.cmake
index 51b02c28..584b45f5 100644
--- a/mingw/pkg-support/cmake/sdl3_image-config-version.cmake
+++ b/build-scripts/pkg-support/mingw/cmake/SDL3_imageConfigVersion.cmake
@@ -2,9 +2,9 @@
# This file is meant to be placed in a cmake subfolder of SDL3_image-devel-3.x.y-mingw
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
- set(sdl3_image_config_path "${CMAKE_CURRENT_LIST_DIR}/../i686-w64-mingw32/lib/cmake/SDL3_image/sdl3_image-config-version.cmake")
+ set(sdl3_image_config_path "${CMAKE_CURRENT_LIST_DIR}/../i686-w64-mingw32/lib/cmake/SDL3_image/SDL3_imageConfigVersion.cmake")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
- set(sdl3_image_config_path "${CMAKE_CURRENT_LIST_DIR}/../x86_64-w64-mingw32/lib/cmake/SDL3_image/sdl3_image-config-version.cmake")
+ set(sdl3_image_config_path "${CMAKE_CURRENT_LIST_DIR}/../x86_64-w64-mingw32/lib/cmake/SDL3_image/SDL3_imageConfigVersion.cmake")
else("${CMAKE_SIZEOF_VOID_P}" STREQUAL "")
set(PACKAGE_VERSION_UNSUITABLE TRUE)
return()
diff --git a/build-scripts/pkg-support/msvc/cmake/SDL3_imageConfig.cmake.in b/build-scripts/pkg-support/msvc/cmake/SDL3_imageConfig.cmake.in
new file mode 100644
index 00000000..70be4ac6
--- /dev/null
+++ b/build-scripts/pkg-support/msvc/cmake/SDL3_imageConfig.cmake.in
@@ -0,0 +1,115 @@
+# @<@PROJECT_NAME@>@ CMake configuration file:
+# This file is meant to be placed in a cmake subfolder of @<@PROJECT_NAME@>@-devel-@<@PROJECT_VERSION@>@-VC.zip
+
+include(FeatureSummary)
+set_package_properties(SDL3_image PROPERTIES
+ URL "https://www.libsdl.org/projects/SDL_image/"
+ DESCRIPTION "SDL_image is an image file loading library"
+)
+
+cmake_minimum_required(VERSION 3.0...3.5)
+
+# Copied from `configure_package_config_file`
+macro(check_required_components _NAME)
+ foreach(comp ${${_NAME}_FIND_COMPONENTS})
+ if(NOT ${_NAME}_${comp}_FOUND)
+ if(${_NAME}_FIND_REQUIRED_${comp})
+ set(${_NAME}_FOUND FALSE)
+ endif()
+ endif()
+ endforeach()
+endmacro()
+
+set(SDL3_image_FOUND TRUE)
+
+set(SDLIMAGE_AVIF TRUE)
+set(SDLIMAGE_BMP TRUE)
+set(SDLIMAGE_GIF TRUE)
+set(SDLIMAGE_JPG TRUE)
+set(SDLIMAGE_JXL FALSE)
+set(SDLIMAGE_LBM TRUE)
+set(SDLIMAGE_PCX TRUE)
+set(SDLIMAGE_PNG TRUE)
+set(SDLIMAGE_PNM TRUE)
+set(SDLIMAGE_QOI TRUE)
+set(SDLIMAGE_SVG TRUE)
+set(SDLIMAGE_TGA TRUE)
+set(SDLIMAGE_TIF TRUE)
+set(SDLIMAGE_XCF FALSE)
+set(SDLIMAGE_XPM TRUE)
+set(SDLIMAGE_XV TRUE)
+set(SDLIMAGE_WEBP TRUE)
+
+set(SDLIMAGE_JPG_SAVE FALSE)
+set(SDLIMAGE_PNG_SAVE FALSE)
+
+set(SDLIMAGE_VENDORED FALSE)
+
+set(SDLIMAGE_BACKEND_IMAGEIO FALSE)
+set(SDLIMAGE_BACKEND_STB TRUE)
+set(SDLIMAGE_BACKEND_WIC FALSE)
+
+if(SDL_CPU_X86)
+ set(_sdl_arch_subdir "x86")
+elseif(SDL_CPU_X64 OR SDL_CPU_ARM64EC)
+ set(_sdl_arch_subdir "x64")
+elseif(SDL_CPU_ARM64)
+ set(SDLIMAGE_AVIF FALSE)
+ set(SDLIMAGE_TIF FALSE)
+ set(SDLIMAGE_WEBP FALSE)
+ set(_sdl_arch_subdir "arm64")
+else()
+ set(SDL3_image_FOUND FALSE)
+ return()
+endif()
+
+set(_sdl3image_incdir "${CMAKE_CURRENT_LIST_DIR}/../include")
+set(_sdl3image_library "${CMAKE_CURRENT_LIST_DIR}/../lib/${_sdl_arch_subdir}/SDL3_image.lib")
+set(_sdl3image_dll "${CMAKE_CURRENT_LIST_DIR}/../lib/${_sdl_arch_subdir}/SDL3_image.dll")
+
+# All targets are created, even when some might not be requested though COMPONENTS.
+# This is done for compatibility with CMake generated SDL3_image-target.cmake files.
+
+set(SDL3_image_SDL3_image-shared_FOUND TRUE)
+if(NOT TARGET SDL3_image::SDL3_image-shared)
+ add_library(SDL3_image::SDL3_image-shared SHARED IMPORTED)
+ set_target_properties(SDL3_image::SDL3_image-shared
+ PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${_sdl3image_incdir}"
+ IMPORTED_IMPLIB "${_sdl3image_library}"
+ IMPORTED_LOCATION "${_sdl3image_dll}"
+ COMPATIBLE_INTERFACE_BOOL "SDL3_SHARED"
+ INTERFACE_SDL3_SHARED "ON"
+ )
+endif()
+
+unset(_sdl_arch_subdir)
+unset(_sdl3image_incdir)
+unset(_sdl3image_library)
+unset(_sdl3image_dll)
+
+set(SDL3_image_SDL3_image-static_FOUND TRUE)
+
+set(SDL3_image_SDL3_image_FOUND FALSE)
+if(SDL3_image_SDL3_image-hared_FOUND OR SDL3_image_SDL3_image-static_FOUND)
+ set(SDL3_image_SDL3_image_FOUND TRUE)
+endif()
+
+function(_sdl_create_target_alias_compat NEW_TARGET TARGET)
+ if(CMAKE_VERSION VERSION_LESS "3.18")
+ # Aliasing local targets is not supported on CMake < 3.18, so make it global.
+ add_library(${NEW_TARGET} INTERFACE IMPORTED)
+ set_target_properties(${NEW_TARGET} PROPERTIES INTERFACE_LINK_LIBRARIES "${TARGET}")
+ else()
+ add_library(${NEW_TARGET} ALIAS ${TARGET})
+ endif()
+endfunction()
+
+# Make sure SDL3_image::SDL3_image always exists
+if(NOT TARGET SDL3_image::SDL3_image)
+ if(TARGET SDL3_image::SDL3_image-shared)
+ _sdl_create_target_alias_compat(SDL3_image::SDL3_image SDL3_image::SDL3_image-shared)
+ endif()
+endif()
+
+check_required_components(SDL3_image)
diff --git a/build-scripts/pkg-support/msvc/cmake/SDL3_imageConfigVersion.cmake.in b/build-scripts/pkg-support/msvc/cmake/SDL3_imageConfigVersion.cmake.in
new file mode 100644
index 00000000..ebbcf99a
--- /dev/null
+++ b/build-scripts/pkg-support/msvc/cmake/SDL3_imageConfigVersion.cmake.in
@@ -0,0 +1,33 @@
+# @<@PROJECT_NAME@>@ CMake version configuration file:
+# This file is meant to be placed in a cmake subfolder of @<@PROJECT_NAME@>@-devel-@<@PROJECT_VERSION@>@-VC.zip
+
+set(PACKAGE_VERSION "@<@PROJECT_VERSION@>@")
+
+if(PACKAGE_FIND_VERSION_RANGE)
+ # Package version must be in the requested version range
+ if ((PACKAGE_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MIN)
+ OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_GREATER PACKAGE_FIND_VERSION_MAX)
+ OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_GREATER_EQUAL PACKAGE_FIND_VERSION_MAX)))
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+ else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ endif()
+else()
+ if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+ else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+ endif()
+endif()
+
+include("${CMAKE_CURRENT_LIST_DIR}/sdlcpu.cmake")
+SDL_DetectTargetCPUArchitectures(_detected_archs)
+
+# check that the installed version has a compatible architecture as the one which is currently searching:
+if(NOT(SDL_CPU_X86 OR SDL_CPU_X64 OR SDL_CPU_ARM64 OR SDL_CPU_ARM64EC))
+ set(PACKAGE_VERSION "${PACKAGE_VERSION} (X86,X64,ARM64)")
+ set(PACKAGE_VERSION_UNSUITABLE TRUE)
+endif()
diff --git a/build-scripts/release-info.json b/build-scripts/release-info.json
new file mode 100644
index 00000000..01efd59b
--- /dev/null
+++ b/build-scripts/release-info.json
@@ -0,0 +1,286 @@
+{
+ "name": "SDL3_image",
+ "remote": "libsdl-org/SDL_image",
+ "dependencies": {
+ "SDL": {
+ "startswith": "3.",
+ "repo": "libsdl-org/SDL"
+ }
+ },
+ "version": {
+ "file": "include/SDL3_image/SDL_image.h",
+ "re_major": "^#define SDL_IMAGE_MAJOR_VERSION\\s+([0-9]+)$",
+ "re_minor": "^#define SDL_IMAGE_MINOR_VERSION\\s+([0-9]+)$",
+ "re_micro": "^#define SDL_IMAGE_MICRO_VERSION\\s+([0-9]+)$"
+ },
+ "source": {
+ "checks": [
+ "src/IMG.c",
+ "include/SDL3_image/SDL_image.h",
+ "examples/showimage.c"
+ ]
+ },
+ "dmg": {
+ "project": "Xcode/SDL_image.xcodeproj",
+ "path": "Xcode/build/SDL3_image.dmg",
+ "scheme": "SDL3_image.dmg",
+ "build-xcconfig": "Xcode/pkg-support/build.xcconfig",
+ "dependencies": {
+ "SDL": {
+ "artifact": "SDL3-*.dmg"
+ }
+ }
+ },
+ "mingw": {
+ "cmake": {
+ "archs": ["x86", "x64"],
+ "args": [
+ "-DSDLIMAGE_AVIF=OFF",
+ "-DSDLIMAGE_BMP=ON",
+ "-DSDLIMAGE_GIF=ON",
+ "-DSDLIMAGE_JPG=ON",
+ "-DSDLIMAGE_JXL=OFF",
+ "-DSDLIMAGE_LBM=ON",
+ "-DSDLIMAGE_PCX=ON",
+ "-DSDLIMAGE_PNG=ON",
+ "-DSDLIMAGE_PNM=ON",
+ "-DSDLIMAGE_QOI=ON",
+ "-DSDLIMAGE_SVG=ON",
+ "-DSDLIMAGE_TGA=ON",
+ "-DSDLIMAGE_TIF=OFF",
+ "-DSDLIMAGE_WEBP=OFF",
+ "-DSDLIMAGE_XCF=ON",
+ "-DSDLIMAGE_XPM=ON",
+ "-DSDLIMAGE_XV=ON",
+ "-DSDLIMAGE_SAMPLES=OFF",
+ "-DSDLIMAGE_TESTS=OFF",
+ "-DSDLIMAGE_VENDORED=OFF"
+ ],
+ "shared-static": "both"
+ },
+ "files": {
+ "": [
+ "CHANGES.txt",
+ "LICENSE.txt",
+ "README.txt",
+ "build-scripts/pkg-support/mingw/Makefile"
+ ],
+ "cmake": [
+ "build-scripts/pkg-support/mingw/cmake/SDL3_imageConfig.cmake",
+ "build-scripts/pkg-support/mingw/cmake/SDL3_imageConfigVersion.cmake"
+ ]
+ },
+ "dependencies": {
+ "SDL": {
+ "artifact": "SDL3-devel-*-mingw.tar.xz",
+ "install-command": "make install-@<@ARCH@>@ DESTDIR=@<@PREFIX@>@"
+ }
+ }
+ },
+ "msvc": {
+ "msbuild": {
+ "archs": [
+ "x86",
+ "x64"
+ ],
+ "projects": [
+ "VisualC/SDL_image.vcxproj"
+ ],
+ "prebuilt": [
+ "VisualC/external/optional/@<@ARCH@>@/*"
+ ],
+ "files-lib": {
+ "": [
+ "VisualC/@<@PLATFORM@>@/@<@CONFIGURATION@>@/SDL3_image.dll"
+ ],
+ "optional": [
+ "VisualC/external/optional/@<@ARCH@>@/libavif-16.dll",
+ "VisualC/external/optional/@<@ARCH@>@/libtiff-6.dll",
+ "VisualC/external/optional/@<@ARCH@>@/libwebp-7.dll",
+ "VisualC/external/optional/@<@ARCH@>@/libwebpdemux-2.dll",
+ "VisualC/external/optional/@<@ARCH@>@/LICENSE.avif.txt",
+ "VisualC/external/optional/@<@ARCH@>@/LICENSE.dav1d.txt",
+ "VisualC/external/optional/@<@ARCH@>@/LICENSE.tiff.txt",
+ "VisualC/external/optional/@<@ARCH@>@/LICENSE.webp.txt"
+ ]
+ },
+ "files-devel": {
+ "lib/@<@ARCH@>@": [
+ "VisualC/@<@PLATFORM@>@/@<@CONFIGURATION@>@/SDL3_image.dll",
+ "VisualC/@<@PLATFORM@>@/@<@CONFIGURATION@>@/SDL3_image.lib",
+ "VisualC/@<@PLATFORM@>@/@<@CONFIGURATION@>@/SDL3_image.pdb"
+ ],
+ "lib/@<@ARCH@>@/optional": [
+ "VisualC/external/optional/@<@ARCH@>@/libavif-16.dll",
+ "VisualC/external/optional/@<@ARCH@>@/libtiff-6.dll",
+ "VisualC/external/optional/@<@ARCH@>@/libwebp-7.dll",
+ "VisualC/external/optional/@<@ARCH@>@/libwebpdemux-2.dll",
+ "VisualC/external/optional/@<@ARCH@>@/LICENSE.avif.txt",
+ "VisualC/external/optional/@<@ARCH@>@/LICENSE.dav1d.txt",
+ "VisualC/external/optional/@<@ARCH@>@/LICENSE.tiff.txt",
+ "VisualC/external/optional/@<@ARCH@>@/LICENSE.webp.txt"
+ ]
+ }
+ },
+ "cmake": {
+ "archs": [
+ "arm64"
+ ],
+ "args": [
+ "-DBUILD_SHARED_LIBS=ON",
+ "-DSDLIMAGE_AVIF=ON",
+ "-DSDLIMAGE_BMP=ON",
+ "-DSDLIMAGE_GIF=ON",
+ "-DSDLIMAGE_JPG=ON",
+ "-DSDLIMAGE_JXL=OFF",
+ "-DSDLIMAGE_LBM=ON",
+ "-DSDLIMAGE_PCX=ON",
+ "-DSDLIMAGE_PNG=ON",
+ "-DSDLIMAGE_PNM=ON",
+ "-DSDLIMAGE_QOI=ON",
+ "-DSDLIMAGE_SVG=ON",
+ "-DSDLIMAGE_TGA=ON",
+ "-DSDLIMAGE_TIF=ON",
+ "-DSDLIMAGE_WEBP=ON",
+ "-DSDLIMAGE_XCF=ON",
+ "-DSDLIMAGE_XPM=ON",
+ "-DSDLIMAGE_XV=ON",
+ "-DSDLIMAGE_SAMPLES=OFF",
+ "-DSDLIMAGE_TESTS=OFF",
+ "-DSDLIMAGE_VENDORED=ON"
+ ],
+ "files-lib": {
+ "": [
+ "bin/SDL3_image.dll"
+ ],
+ "optional": [
+ "bin/libavif-16.dll",
+ "bin/dav1d.dll",
+ "bin/aom.dll",
+ "bin/tiff.dll",
+ "bin/libwebp.dll",
+ "bin/libwebpdemux.dll"
+ ]
+ },
+ "files-devel": {
+ "lib/@<@ARCH@>@": [
+ "bin/SDL3_image.dll",
+ "bin/SDL3_image.pdb",
+ "lib/SDL3_image.lib"
+ ],
+ "lib/@<@ARCH@>@/optional": [
+ "bin/libavif-16.dll",
+ "bin/dav1d.dll",
+ "bin/aom.dll",
+ "bin/tiff.dll",
+ "bin/libwebp.dll",
+ "bin/libwebpdemux.dll"
+ ]
+ }
+ },
+ "files-lib": {
+ "": [
+ "README.txt"
+ ]
+ },
+ "files-devel": {
+ "": [
+ "CHANGES.txt",
+ "LICENSE.txt",
+ "README.txt"
+ ],
+ "cmake": [
+ "build-scripts/pkg-support/msvc/cmake/SDL3_imageConfig.cmake.in:SDL3_imageConfig.cmake",
+ "build-scripts/pkg-support/msvc/cmake/SDL3_imageConfigVersion.cmake.in:SDL3_imageConfigVersion.cmake",
+ "cmake/sdlcpu.cmake"
+ ],
+ "include/SDL3_image": [
+ "include/SDL3_image/SDL_image.h"
+ ]
+ },
+ "dependencies": {
+ "SDL": {
+ "artifact": "SDL3-devel-*-VC.zip",
+ "copy": [
+ {
+ "src": "lib/@<@ARCH@>@/SDL3.*",
+ "dst": "../SDL/VisualC/@<@PLATFORM@>@/@<@CONFIGURATION@>@"
+ },
+ {
+ "src": "include/SDL3/*",
+ "dst": "../SDL/include/SDL3"
+ }
+ ]
+ }
+ }
+ },
+ "android": {
+ "cmake": {
+ "args": [
+ "-DBUILD_SHARED_LIBS=ON",
+ "-DSDLIMAGE_AVIF=OFF",
+ "-DSDLIMAGE_BMP=ON",
+ "-DSDLIMAGE_GIF=ON",
+ "-DSDLIMAGE_JPG=ON",
+ "-DSDLIMAGE_JXL=OFF",
+ "-DSDLIMAGE_LBM=ON",
+ "-DSDLIMAGE_PCX=ON",
+ "-DSDLIMAGE_PNG=ON",
+ "-DSDLIMAGE_PNM=ON",
+ "-DSDLIMAGE_QOI=ON",
+ "-DSDLIMAGE_SVG=ON",
+ "-DSDLIMAGE_TGA=ON",
+ "-DSDLIMAGE_TIF=OFF",
+ "-DSDLIMAGE_WEBP=OFF",
+ "-DSDLIMAGE_XCF=ON",
+ "-DSDLIMAGE_XPM=ON",
+ "-DSDLIMAGE_XV=ON",
+ "-DSDLIMAGE_SAMPLES=OFF",
+ "-DSDLIMAGE_TESTS=OFF",
+ "-DSDLIMAGE_VENDORED=ON"
+ ]
+ },
+ "modules": {
+ "SDL3_image-shared": {
+ "type": "library",
+ "library": "lib/libSDL3_image.so",
+ "includes": {
+ "SDL3_image": ["include/SDL3_image/*.h"]
+ }
+ },
+ "SDL3_image": {
+ "type": "interface",
+ "export-libraries": [":SDL3_image-shared"]
+ }
+ },
+ "abis": [
+ "armeabi-v7a",
+ "arm64-v8a",
+ "x86",
+ "x86_64"
+ ],
+ "api-minimum": 19,
+ "api-target": 29,
+ "ndk-minimum": 21,
+ "files": {
+ "": [
+ "build-scripts/pkg-support/android/INSTALL.md.in:INSTALL.md",
+ "build-scripts/pkg-support/android/__main__.py.in:__main__.py",
+ "build-scripts/pkg-support/android/description.json.in:description.json"
+ ],
+ "META-INF": [
+ "LICENSE.txt"
+ ],
+ "cmake": [
+ "cmake/sdlcpu.cmake",
+ "build-scripts/pkg-support/android/cmake/SDL3_imageConfig.cmake",
+ "build-scripts/pkg-support/android/cmake/SDL3_imageConfigVersion.cmake.in:SDL3_imageConfigVersion.cmake"
+ ]
+ },
+ "dependencies": {
+ "SDL": {
+ "artifact": "SDL3-*.aar"
+ }
+ }
+ }
+}
diff --git a/build-scripts/test-versioning.sh b/build-scripts/test-versioning.sh
index bc0e1ba6..b9a4942d 100755
--- a/build-scripts/test-versioning.sh
+++ b/build-scripts/test-versioning.sh
@@ -138,13 +138,5 @@ else
not_ok "project.pbxproj DYLIB_CURRENT_VERSION is inconsistent, expected $ref, got $dylib_cur"
fi
-sdl_req=$(sed -ne 's/\$sdl3_version = "\([0-9.]*\)"$/\1/p' .github/fetch_sdl_vc.ps1)
-
-if [ "$ref_sdl_req" = "$sdl_req" ]; then
- ok ".github/fetch_sdl_vc.ps1 $sdl_req"
-else
- not_ok ".github/fetch_sdl_vc.ps1 sdl3_version=$sdl_req disagrees with CMakeLists.txt SDL_REQUIRED_VERSION=$ref_sdl_req"
-fi
-
echo "1..$tests"
exit "$failed"
diff --git a/cmake/SDL3_imageConfig.cmake.in b/cmake/SDL3_imageConfig.cmake.in
index a3862a4b..db72fd70 100644
--- a/cmake/SDL3_imageConfig.cmake.in
+++ b/cmake/SDL3_imageConfig.cmake.in
@@ -43,10 +43,13 @@ set(SDLIMAGE_BACKEND_WIC @SDLIMAGE_BACKEND_WIC@)
set(SDLIMAGE_SDL3_REQUIRED_VERSION @SDL_REQUIRED_VERSION@)
+set(SDL3_image_SDL3_image-shared_FOUND FALSE)
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/SDL3_image-shared-targets.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/SDL3_image-shared-targets.cmake")
+ set(SDL3_image_SDL3_image-shared_FOUND TRUE)
endif()
+set(SDL3_image_SDL3_image-static_FOUND FALSE)
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/SDL3_image-static-targets.cmake")
if(SDLIMAGE_VENDORED)
@@ -89,7 +92,7 @@ if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/SDL3_image-static-targets.cmake")
endif()
endif()
- if(SDLIMAGE_JPG AND NOT TARGET JPEG::JPEG AND NOT SDLIMAGE_JPG_SHARED)
+ if(SDLIMAGE_JPG AND NOT TARGET JPEG::JPEG AND NOT SDLIMAGE_JPG_SHARED AND NOT (SDLIMAGE_BACKEND_STB OR SDLIMAGE_BACKEND_WIC OR SDLIMAGE_BACKEND_IMAGEIO))
find_dependency(JPEG)
endif()
@@ -98,11 +101,11 @@ if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/SDL3_image-static-targets.cmake")
find_dependency(libjxl)
endif()
- if(SDLIMAGE_PNG AND NOT TARGET PNG::PNG AND NOT SDLIMAGE_PNG_SHARED)
+ if(SDLIMAGE_PNG AND NOT TARGET PNG::PNG AND NOT SDLIMAGE_PNG_SHARED AND NOT (SDLIMAGE_BACKEND_STB OR SDLIMAGE_BACKEND_WIC OR SDLIMAGE_BACKEND_IMAGEIO))
find_dependency(PNG)
endif()
- if(SDLIMAGE_TIF AND NOT TARGET TIFF::TIFF)
+ if(SDLIMAGE_TIF AND NOT TARGET TIFF::TIFF AND NOT (SDLIMAGE_BACKEND_IMAGEIO OR SDLIMAGE_BACKEND_WIC))
find_dependency(TIFF)
endif()
@@ -117,6 +120,7 @@ if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/SDL3_image-static-targets.cmake")
endif()
include("${CMAKE_CURRENT_LIST_DIR}/SDL3_image-static-targets.cmake")
+ set(SDL3_image_SDL3_image-static_FOUND TRUE)
endif()
function(_sdl_create_target_alias_compat NEW_TARGET TARGET)
@@ -133,7 +137,10 @@ endfunction()
if(NOT TARGET SDL3_image::SDL3_image)
if(TARGET SDL3_image::SDL3_image-shared)
_sdl_create_target_alias_compat(SDL3_image::SDL3_image SDL3_image::SDL3_image-shared)
- else()
+ elseif(TARGET SDL3_image::SDL3_image-static)
_sdl_create_target_alias_compat(SDL3_image::SDL3_image SDL3_image::SDL3_image-static)
endif()
endif()
+
+@PACKAGE_INIT@
+check_required_components(SDL3_image)
diff --git a/cmake/sdlcpu.cmake b/cmake/sdlcpu.cmake
new file mode 100644
index 00000000..d63a57f9
--- /dev/null
+++ b/cmake/sdlcpu.cmake
@@ -0,0 +1,156 @@
+function(SDL_DetectTargetCPUArchitectures DETECTED_ARCHS)
+
+ set(known_archs EMSCRIPTEN ARM32 ARM64 ARM64EC LOONGARCH64 POWERPC32 POWERPC64 X86 X64)
+
+ if(APPLE AND CMAKE_OSX_ARCHITECTURES)
+ foreach(known_arch IN LISTS known_archs)
+ set(SDL_CPU_${known_arch} "0")
+ endforeach()
+ set(detected_archs)
+ foreach(osx_arch IN LISTS CMAKE_OSX_ARCHITECTURES)
+ if(osx_arch STREQUAL "x86_64")
+ set(SDL_CPU_X64 "1")
+ list(APPEND detected_archs "X64")
+ elseif(osx_arch STREQUAL "arm64")
+ set(SDL_CPU_ARM64 "1")
+ list(APPEND detected_archs "ARM64")
+ endif()
+ endforeach()
+ set("${DETECTED_ARCHS}" "${detected_archs}" PARENT_SCOPE)
+ return()
+ endif()
+
+ set(detected_archs)
+ foreach(known_arch IN LISTS known_archs)
+ if(SDL_CPU_${known_arch})
+ list(APPEND detected_archs "${known_arch}")
+ endif()
+ endforeach()
+
+ if(detected_archs)
+ set("${DETECTED_ARCHS}" "${detected_archs}" PARENT_SCOPE)
+ return()
+ endif()
+
+ set(arch_check_ARM32 "defined(__arm__) || defined(_M_ARM)")
+ set(arch_check_ARM64 "defined(__aarch64__) || defined(_M_ARM64)")
+ set(arch_check_ARM64EC "defined(_M_ARM64EC)")
+ set(arch_check_EMSCRIPTEN "defined(__EMSCRIPTEN__)")
+ set(arch_check_LOONGARCH64 "defined(__loongarch64)")
+ set(arch_check_POWERPC32 "(defined(__PPC__) || defined(__powerpc__)) && !defined(__powerpc64__)")
+ set(arch_check_POWERPC64 "defined(__PPC64__) || defined(__powerpc64__)")
+ set(arch_check_X86 "defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) ||defined( __i386) || defined(_M_IX86)")
+ set(arch_check_X64 "(defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)) && !defined(_M_ARM64EC)")
+
+ set(src_vars "")
+ set(src_main "")
+ foreach(known_arch IN LISTS known_archs)
+ set(detected_${known_arch} "0")
+
+ string(APPEND src_vars "
+#if ${arch_check_${known_arch}}
+#define ARCH_${known_arch} \"1\"
+#else
+#define ARCH_${known_arch} \"0\"
+#endif
+const char *arch_${known_arch} = \"INFO<${known_arch}=\" ARCH_${known_arch} \">\";
+")
+ string(APPEND src_main "
+ result += arch_${known_arch}[argc];")
+ endforeach()
+
+ set(src_arch_detect "${src_vars}
+int main(int argc, char *argv[]) {
+ (void)argv;
+ int result = 0;
+${src_main}
+ return result;
+}")
+
+ if(CMAKE_C_COMPILER)
+ set(ext ".c")
+ elseif(CMAKE_CXX_COMPILER)
+ set(ext ".cpp")
+ else()
+ enable_language(C)
+ set(ext ".c")
+ endif()
+ set(path_src_arch_detect "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CMakeTmp/SDL_detect_arch${ext}")
+ file(WRITE "${path_src_arch_detect}" "${src_arch_detect}")
+ set(path_dir_arch_detect "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CMakeTmp/SDL_detect_arch")
+ set(path_bin_arch_detect "${path_dir_arch_detect}/bin")
+
+ set(detected_archs)
+
+ set(msg "Detecting Target CPU Architecture")
+ message(STATUS "${msg}")
+
+ include(CMakePushCheckState)
+
+ set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
+
+ cmake_push_check_state(RESET)
+ try_compile(SDL_CPU_CHECK_ALL
+ "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CMakeTmp/SDL_detect_arch"
+ SOURCES "${path_src_arch_detect}"
+ COPY_FILE "${path_bin_arch_detect}"
+ )
+ cmake_pop_check_state()
+ if(NOT SDL_CPU_CHECK_ALL)
+ message(STATUS "${msg} - ")
+ message(WARNING "Failed to compile source detecting the target CPU architecture")
+ else()
+ set(re "INFO<([A-Z0-9]+)=([01])>")
+ file(STRINGS "${path_bin_arch_detect}" infos REGEX "${re}")
+
+ foreach(info_arch_01 IN LISTS infos)
+ string(REGEX MATCH "${re}" A "${info_arch_01}")
+ if(NOT "${CMAKE_MATCH_1}" IN_LIST known_archs)
+ message(WARNING "Unknown architecture: \"${CMAKE_MATCH_1}\"")
+ continue()
+ endif()
+ set(arch "${CMAKE_MATCH_1}")
+ set(arch_01 "${CMAKE_MATCH_2}")
+ set(detected_${arch} "${arch_01}")
+ endforeach()
+
+ foreach(known_arch IN LISTS known_archs)
+ if(detected_${known_arch})
+ list(APPEND detected_archs ${known_arch})
+ endif()
+ endforeach()
+ endif()
+
+ if(detected_archs)
+ foreach(known_arch IN LISTS known_archs)
+ set("SDL_CPU_${known_arch}" "${detected_${known_arch}}" CACHE BOOL "Detected architecture ${known_arch}")
+ endforeach()
+ message(STATUS "${msg} - ${detected_archs}")
+ else()
+ include(CheckCSourceCompiles)
+ cmake_push_check_state(RESET)
+ foreach(known_arch IN LISTS known_archs)
+ if(NOT detected_archs)
+ set(cache_variable "SDL_CPU_${known_arch}")
+ set(test_src "
+ int main(int argc, char *argv[]) {
+ #if ${arch_check_${known_arch}}
+ return 0;
+ #else
+ choke
+ #endif
+ }
+ ")
+ check_c_source_compiles("${test_src}" "${cache_variable}")
+ if(${cache_variable})
+ set(SDL_CPU_${known_arch} "1" CACHE BOOL "Detected architecture ${known_arch}")
+ set(detected_archs ${known_arch})
+ else()
+ set(SDL_CPU_${known_arch} "0" CACHE BOOL "Detected architecture ${known_arch}")
+ endif()
+ endif()
+ endforeach()
+ cmake_pop_check_state()
+ endif()
+ set("${DETECTED_ARCHS}" "${detected_archs}" PARENT_SCOPE)
+endfunction()
diff --git a/cmake/test/CMakeLists.txt b/cmake/test/CMakeLists.txt
index a9dae6bf..61cad84c 100644
--- a/cmake/test/CMakeLists.txt
+++ b/cmake/test/CMakeLists.txt
@@ -16,6 +16,15 @@ add_feature_info("TEST_SHARED" TEST_SHARED "Test linking with shared library")
option(TEST_STATIC "Test linking to static SDL3_image library" ON)
add_feature_info("TEST_STATIC" TEST_STATIC "Test linking with static library")
+if(ANDROID)
+ macro(add_executable NAME)
+ set(args ${ARGN})
+ list(REMOVE_ITEM args WIN32)
+ add_library(${NAME} SHARED ${args})
+ unset(args)
+ endmacro()
+endif()
+
if(TEST_SHARED)
find_package(SDL3 REQUIRED CONFIG COMPONENTS SDL3)
find_package(SDL3_image REQUIRED CONFIG)
diff --git a/external/dav1d b/external/dav1d
index 58e3a991..aabfea0c 160000
--- a/external/dav1d
+++ b/external/dav1d
@@ -1 +1 @@
-Subproject commit 58e3a991928088a51020118149b2c8550fa0021d
+Subproject commit aabfea0c42f9df86268fe1c578e8c9b50d28fcc9
diff --git a/external/download.sh b/external/download.sh
index df63ee46..b78a4a50 100755
--- a/external/download.sh
+++ b/external/download.sh
@@ -2,6 +2,8 @@
set -e
+ARGUMENTS="$*"
+
cd $(dirname "$0")/..
cat .gitmodules | \
while true; do
@@ -12,5 +14,5 @@ while true; do
url=$3
read line; set -- $line
branch=$3
- git clone --filter=blob:none $url $path -b $branch --recursive
+ git clone --filter=blob:none $url $path -b $branch --recursive $ARGUMENTS
done