Port SDL3 release scripts to SDL2

[skip ci]

(cherry picked from commit 8291b1be36)
This commit is contained in:
Anonymous Maarten 2024-09-16 22:56:12 +02:00
parent e9f5f3ac1f
commit 025fc35c87
14 changed files with 1214 additions and 21 deletions

406
.github/workflows/release.yml vendored Normal file
View file

@ -0,0 +1,406 @@
name: 'release'
run-name: 'Create SDL release artifacts for ${{ inputs.commit }}'
on:
workflow_dispatch:
inputs:
commit:
description: 'Commit of SDL'
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:
sparse-checkout: 'build-scripts/build-release.py'
- name: 'Set up SDL sources'
uses: actions/checkout@v4
with:
path: 'SDL'
fetch-depth: 0
- name: 'Build Source archive'
id: releaser
shell: bash
run: |
python build-scripts/build-release.py \
--create source \
--commit ${{ inputs.commit }} \
--project SDL2 \
--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: 'Download source archives'
uses: actions/download-artifact@v4
with:
name: sources
path: '${{ github.workspace }}'
- name: 'Unzip ${{ needs.src.outputs.src-zip }}'
id: zip
run: |
mkdir /tmp/zipdir
cd /tmp/zipdir
unzip "${{ github.workspace }}/${{ 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: |
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: 'Compare contents of ${{ needs.src.outputs.src-zip }} and ${{ needs.src.outputs.src-tar-gz }}'
run: |
diff /tmp/zipdir /tmp/tardir
- name: 'Test versioning'
shell: bash
run: |
${{ steps.tar.outputs.path }}/build-scripts/test-versioning.sh
- name: 'CMake (configure + build + tests + examples)'
run: |
cmake -S ${{ steps.tar.outputs.path }} -B /tmp/build -DSDL_TEST_LIBRARY=TRUE -DSDL_TESTS=TRUE -DSDL_EXAMPLES=TRUE
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.10'
- name: 'Fetch build-release.py'
uses: actions/checkout@v4
with:
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: 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: 'Build SDL2.dmg'
id: releaser
shell: bash
run: |
python build-scripts/build-release.py \
--create framework \
--commit ${{ inputs.commit }} \
--project SDL2 \
--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: 'Download source archives'
uses: actions/download-artifact@v4
with:
name: sources
path: '${{ github.workspace }}'
- name: 'Download ${{ needs.dmg.outputs.dmg }}'
uses: actions/download-artifact@v4
with:
name: dmg
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: '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 }}.framework" ]; then
echo "Cannot find ${{ needs.src.outputs.project }}.framework!"
exit 1
fi
echo "mount_point=$mount_point">>$GITHUB_OUTPUT
- name: 'CMake (configure + build) Darwin'
run: |
set -e
cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
-DTEST_FULL=FALSE \
-DTEST_STATIC=FALSE \
-DTEST_TEST=FALSE \
-DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount_point }}" \
-DCMAKE_SYSTEM_NAME=Darwin \
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
-Werror=dev \
-B build_darwin
cmake --build build_darwin --config Release --verbose
cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
-DTEST_FULL=FALSE \
-DTEST_STATIC=FALSE \
-DTEST_TEST=FALSE \
-DCMAKE_PREFIX_PATH="${{ steps.mount.outputs.mount_point }}" \
-DCMAKE_SYSTEM_NAME=Darwin \
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
-Werror=dev \
-B build_darwin_2
cmake --build build_darwin --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.10'
- name: 'Fetch build-release.py'
uses: actions/checkout@v4
with:
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: 'Build MSVC binary archives'
id: releaser
run: |
python build-scripts/build-release.py `
--create win32 `
--commit ${{ inputs.commit }} `
--project SDL2 `
--root "${{ steps.zip.outputs.path }}" `
--github `
--debug
- name: 'Store MSVC archives'
uses: actions/upload-artifact@v4
with:
name: win32
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:
sparse-checkout: '.github/actions/setup-ninja/action.yml'
- name: 'Download source archives'
uses: actions/download-artifact@v4
with:
name: sources
path: '${{ github.workspace }}'
- name: 'Download MSVC binaries'
uses: actions/download-artifact@v4
with:
name: win32
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: '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: Set up ninja
uses: ./.github/actions/setup-ninja
- 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_FULL=FALSE `
-DTEST_STATIC=FALSE `
-DTEST_SHARED=TRUE `
-DTEST_TEST=TRUE `
-DCMAKE_SUPPRESS_REGENERATION=TRUE `
-DCMAKE_PREFIX_PATH="${{ steps.bin.outputs.path }}"
Start-Sleep -Seconds 2
cmake --build build_x86 --config Release --verbose
#ctest --test-dir build_x86 --no-tests=error -C Release --output-on-failure
- 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_FULL=FALSE `
-DTEST_STATIC=FALSE `
-DTEST_SHARED=TRUE `
-DTEST_TEST=TRUE `
-DCMAKE_SUPPRESS_REGENERATION=TRUE `
-DCMAKE_PREFIX_PATH="${{ steps.bin.outputs.path }}"
Start-Sleep -Seconds 2
cmake --build build_x64 --config Release --verbose
#ctest --test-dir build_x64 --no-tests=error -C Release --output-on-failure
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.10'
- name: 'Fetch build-release.py'
uses: actions/checkout@v4
with:
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
run: |
python build-scripts/build-release.py \
--create mingw \
--commit ${{ inputs.commit }} \
--project SDL2 \
--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: '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: 'Download MinGW binaries'
uses: actions/download-artifact@v4
with:
name: mingw
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: 'Untar ${{ 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 }}"
echo "path=/tmp/mingw-tardir/${{ needs.src.outputs.project }}-${{ needs.src.outputs.version }}" >>$GITHUB_OUTPUT
- name: 'CMake (configure + build) i686'
run: |
set -e
cmake -S "${{ steps.src.outputs.path }}/cmake/test" \
-DCMAKE_BUILD_TYPE="Release" \
-DTEST_FULL=FALSE \
-DTEST_STATIC=TRUE \
-DTEST_TEST=TRUE \
-DCMAKE_PREFIX_PATH="${{ steps.bin.outputs.path }}" \
-DCMAKE_TOOLCHAIN_FILE="${{ steps.src.outputs.path }}/build-scripts/cmake-toolchain-mingw64-i686.cmake" \
-DCMAKE_C_FLAGS="-DSDL_DISABLE_SSE4_2" \
-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_FULL=FALSE \
-DTEST_STATIC=TRUE \
-DTEST_TEST=TRUE \
-DCMAKE_PREFIX_PATH="${{ steps.bin.outputs.path }}" \
-DCMAKE_TOOLCHAIN_FILE="${{ steps.src.outputs.path }}/build-scripts/cmake-toolchain-mingw64-x86_64.cmake" \
-DCMAKE_C_FLAGS="-DSDL_DISABLE_SSE4_2" \
-Werror=dev \
-B build_x64
cmake --build build_x64 --config Release --verbose

1
.gitignore vendored
View file

@ -16,6 +16,7 @@ gen
Build
buildbot
/VERSION.txt
dist
*.so
*.so.*

View file

@ -44,22 +44,6 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC70.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC70.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC70.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC70.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>

View file

@ -79,6 +79,8 @@ endif()
unset(_sdl2_library)
unset(_sdl2_dll_library)
set(SDL2_SDL2-static_FOUND FALSE)
set(_sdl2main_library "${SDL2_LIBDIR}/SDL2main.lib")
if(EXISTS "${_sdl2main_library}")
if(NOT TARGET SDL2::SDL2main)
@ -110,7 +112,7 @@ if(EXISTS "${_sdl2test_library}")
endif()
set(SDL2_SDL2test_FOUND TRUE)
else()
set(SDL2_SDL2_FOUND FALSE)
set(SDL2_SDL2test_FOUND FALSE)
endif()
unset(_sdl2test_library)

640
build-scripts/build-release.py Executable file
View file

@ -0,0 +1,640 @@
#!/usr/bin/env python
import argparse
import collections
import contextlib
import datetime
import glob
import io
import json
import logging
import os
from pathlib import Path
import platform
import re
import shutil
import subprocess
import sys
import tarfile
import tempfile
import textwrap
import typing
import zipfile
logger = logging.getLogger(__name__)
VcArchDevel = collections.namedtuple("VcArchDevel", ("dll", "pdb", "imp", "main", "test"))
GIT_HASH_FILENAME = ".git-hash"
ANDROID_AVAILABLE_ABIS = [
"armeabi-v7a",
"arm64-v8a",
"x86",
"x86_64",
]
ANDROID_MINIMUM_API = 19
ANDROID_TARGET_API = 29
ANDROID_MINIMUM_NDK = 21
class Executer:
def __init__(self, root: Path, dry: bool=False):
self.root = root
self.dry = dry
def run(self, cmd, stdout=False, dry_out=None, force=False):
sys.stdout.flush()
logger.info("Executing args=%r", cmd)
if self.dry and not force:
if stdout:
return subprocess.run(["echo", "-E", dry_out or ""], stdout=subprocess.PIPE if stdout else None, text=True, check=True, cwd=self.root)
else:
return subprocess.run(cmd, stdout=subprocess.PIPE if stdout else None, text=True, check=True, cwd=self.root)
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.run(vswhere_cmd, stdout=True, dry_out="/tmp").stdout.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.run(vswhere_cmd, stdout=True, dry_out="/tmp/MSBuild.exe").stdout.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: str, platform: str, configuration: str, projects: list[Path]):
assert projects, "Need at least one project to build"
vsdev_cmd_str = f"\"{self.vsdevcmd}\" -arch={arch}"
msbuild_cmd_str = " && ".join([f"\"{self.msbuild}\" \"{project}\" /m /p:BuildInParallel=true /p:Platform={platform} /p:Configuration={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 Releaser:
def __init__(self, project: str, commit: str, root: Path, dist_path: Path, section_printer: SectionPrinter, executer: Executer, cmake_generator: str):
self.project = project
self.version = self.extract_sdl_version(root=root, project=project)
self.root = root
self.commit = commit
self.dist_path = dist_path
self.section_printer = section_printer
self.executer = executer
self.cmake_generator = cmake_generator
self.artifacts: dict[str, Path] = {}
@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)
TreeItem = collections.namedtuple("TreeItem", ("path", "mode", "data", "time"))
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.run(["git", "log", "--name-status", '--pretty=time=%cI', self.commit], stdout=True, dry_out=dry_out).stdout.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 = datetime.datetime.fromisoformat(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
assert set(path_times.keys()) == set_paths
return path_times
@staticmethod
def _path_filter(path: str):
if path.startswith(".git"):
return False
return True
def _get_git_contents(self) -> dict[str, TreeItem]:
contents_tgz = subprocess.check_output(["git", "archive", "--format=tar.gz", self.commit, "-o", "/dev/stdout"], text=False)
contents = tarfile.open(fileobj=io.BytesIO(contents_tgz), mode="r:gz")
filenames = tuple(m.name for m in contents if m.isfile())
assert "src/SDL.c" in filenames
assert "include/SDL.h" in filenames
file_times = self._get_file_times(filenames)
git_contents = {}
for ti in contents:
if not ti.isfile():
continue
if not self._path_filter(ti.name):
continue
contents_file = contents.extractfile(ti.name)
assert contents_file, f"{ti.name} is not a file"
git_contents[ti.name] = self.TreeItem(path=ti.name, mode=ti.mode, data=contents_file.read(), time=file_times[ti.name])
return git_contents
def create_source_archives(self) -> None:
archive_base = f"{self.project}-{self.version}"
git_contents = self._get_git_contents()
git_files = list(git_contents.values())
assert len(git_contents) == len(git_files)
latest_mod_time = max(item.time for item in git_files)
git_files.append(self.TreeItem(path="VERSION.txt", data=f"{self.version}\n".encode(), mode=0o100644, time=latest_mod_time))
git_files.append(self.TreeItem(path=GIT_HASH_FILENAME, data=f"{self.commit}\n".encode(), mode=0o100644, time=latest_mod_time))
git_files.sort(key=lambda v: v.time)
zip_path = self.dist_path / f"{archive_base}.zip"
logger.info("Creating .zip source archive (%s)...", zip_path)
if self.dry:
zip_path.touch()
else:
with zipfile.ZipFile(zip_path, "w", compression=zipfile.ZIP_DEFLATED) as zip_object:
for git_file in git_files:
file_data_time = (git_file.time.year, git_file.time.month, git_file.time.day, git_file.time.hour, git_file.time.minute, git_file.time.second)
zip_info = zipfile.ZipInfo(filename=f"{archive_base}/{git_file.path}", date_time=file_data_time)
zip_info.external_attr = git_file.mode << 16
zip_info.compress_type = zipfile.ZIP_DEFLATED
zip_object.writestr(zip_info, data=git_file.data)
self.artifacts["src-zip"] = zip_path
tar_types = (
(".tar.gz", "gz"),
(".tar.xz", "xz"),
)
for ext, comp in tar_types:
tar_path = self.dist_path / f"{archive_base}{ext}"
logger.info("Creating %s source archive (%s)...", ext, tar_path)
if self.dry:
tar_path.touch()
else:
with tarfile.open(tar_path, f"w:{comp}") as tar_object:
for git_file in git_files:
tar_info = tarfile.TarInfo(f"{archive_base}/{git_file.path}")
tar_info.mode = git_file.mode
tar_info.size = len(git_file.data)
tar_info.mtime = git_file.time.timestamp()
tar_object.addfile(tar_info, fileobj=io.BytesIO(git_file.data))
if tar_path.suffix == ".gz":
# Zero the embedded timestamp in the gzip'ed tarball
with open(tar_path, "r+b") as f:
f.seek(4, 0)
f.write(b"\x00\x00\x00\x00")
self.artifacts[f"src-tar-{comp}"] = tar_path
def create_framework(self, configuration: str="Release") -> None:
dmg_in = self.root / f"Xcode/SDL/build/{self.project}.dmg"
dmg_in.unlink(missing_ok=True)
self.executer.run(["xcodebuild", "-project", str(self.root / "Xcode/SDL/SDL.xcodeproj"), "-target", "Standard DMG", "-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 _tar_add_git_hash(self, tar_object: tarfile.TarFile, root: typing.Optional[str]=None, time: typing.Optional[datetime.datetime]=None):
if not time:
time = datetime.datetime(year=2024, month=4, day=1)
path = GIT_HASH_FILENAME
if root:
path = f"{root}/{path}"
tar_info = tarfile.TarInfo(path)
tar_info.mode = 0o100644
tar_info.size = len(self.git_hash_data)
tar_info.mtime = int(time.timestamp())
tar_object.addfile(tar_info, fileobj=io.BytesIO(self.git_hash_data))
def _zip_add_git_hash(self, zip_file: zipfile.ZipFile, root: typing.Optional[str]=None, time: typing.Optional[datetime.datetime]=None):
if not time:
time = datetime.datetime(year=2024, month=4, day=1)
path = GIT_HASH_FILENAME
if root:
path = f"{root}/{path}"
file_data_time = (time.year, time.month, time.day, time.hour, time.minute, time.second)
zip_info = zipfile.ZipInfo(filename=path, date_time=file_data_time)
zip_info.external_attr = 0o100644 << 16
zip_info.compress_type = zipfile.ZIP_DEFLATED
zip_file.writestr(zip_info, data=self.git_hash_data)
def create_mingw_archives(self) -> None:
build_type = "Release"
mingw_archs = ("i686", "x86_64")
build_parent_dir = self.root / "build-mingw"
zip_path = self.dist_path / f"{self.project}-devel-{self.version}-mingw.zip"
tar_exts = ("gz", "xz")
tar_paths = { ext: self.dist_path / f"{self.project}-devel-{self.version}-mingw.tar.{ext}" for ext in tar_exts}
arch_install_paths = {}
arch_files = {}
for arch in mingw_archs:
build_path = build_parent_dir / f"build-{arch}"
install_path = build_parent_dir / f"install-{arch}"
arch_install_paths[arch] = install_path
shutil.rmtree(install_path, ignore_errors=True)
build_path.mkdir(parents=True, exist_ok=True)
with self.section_printer.group(f"Configuring MinGW {arch}"):
self.executer.run([
"cmake", "-S", str(self.root), "-B", str(build_path),
"--fresh",
f'''-DCMAKE_C_FLAGS="-ffile-prefix-map={self.root}=/src/{self.project}"''',
f'''-DCMAKE_CXX_FLAGS="-ffile-prefix-map={self.root}=/src/{self.project}"''',
"-DSDL_SHARED=ON",
"-DSDL_STATIC=ON",
"-DSDL_DISABLE_INSTALL_DOCS=ON",
"-DSDL_TEST_LIBRARY=ON",
"-DSDL_TESTS=OFF",
"-DCMAKE_INSTALL_BINDIR=bin",
"-DCMAKE_INSTALL_DATAROOTDIR=share",
"-DCMAKE_INSTALL_INCLUDEDIR=include",
"-DCMAKE_INSTALL_LIBDIR=lib",
f"-DCMAKE_BUILD_TYPE={build_type}",
f"-DCMAKE_TOOLCHAIN_FILE={self.root}/build-scripts/cmake-toolchain-mingw64-{arch}.cmake",
f"-G{self.cmake_generator}",
f"-DCMAKE_INSTALL_PREFIX={install_path}",
])
with self.section_printer.group(f"Build MinGW {arch}"):
self.executer.run(["cmake", "--build", str(build_path), "--verbose", "--config", build_type])
with self.section_printer.group(f"Install MinGW {arch}"):
self.executer.run(["cmake", "--install", str(build_path), "--strip", "--config", build_type])
arch_files[arch] = list(Path(r) / f for r, _, files in os.walk(install_path) for f in files)
extra_files = (
("mingw/pkg-support/INSTALL.txt", ""),
("mingw/pkg-support/Makefile", ""),
("mingw/pkg-support/cmake/sdl2-config.cmake", "cmake/"),
("mingw/pkg-support/cmake/sdl2-config-version.cmake", "cmake/"),
("BUGS.txt", ""),
("CREDITS.txt", ""),
("README-SDL.txt", ""),
("WhatsNew.txt", ""),
("LICENSE.txt", ""),
("README.md", ""),
)
test_files = list(Path(r) / f for r, _, files in os.walk(self.root / "test") for f in files)
# FIXME: split SDL2.dll debug information into debug library
# objcopy --only-keep-debug SDL2.dll SDL2.debug.dll
# objcopy --add-gnu-debuglink=SDL2.debug.dll SDL2.dll
# objcopy --strip-debug SDL2.dll
for comp in tar_exts:
logger.info("Creating %s...", tar_paths[comp])
with tarfile.open(tar_paths[comp], f"w:{comp}") as tar_object:
arc_root = f"{self.project}-{self.version}"
for file_path, arcdirname in extra_files:
assert not arcdirname or arcdirname[-1] == "/"
arcname = f"{arc_root}/{arcdirname}{Path(file_path).name}"
tar_object.add(self.root / file_path, arcname=arcname)
for arch in mingw_archs:
install_path = arch_install_paths[arch]
arcname_parent = f"{arc_root}/{arch}-w64-mingw32"
for file in arch_files[arch]:
arcname = os.path.join(arcname_parent, file.relative_to(install_path))
tar_object.add(file, arcname=arcname)
for test_file in test_files:
arcname = f"{arc_root}/test/{test_file.relative_to(self.root/'test')}"
tar_object.add(test_file, arcname=arcname)
self._tar_add_git_hash(tar_object=tar_object, root=arc_root)
self.artifacts[f"mingw-devel-tar-{comp}"] = tar_paths[comp]
def build_vs(self, arch: str, platform: str, vs: VisualStudio, configuration: str="Release") -> VcArchDevel:
dll_path = self.root / f"VisualC/SDL/{platform}/{configuration}/{self.project}.dll"
pdb_path = self.root / f"VisualC/SDL/{platform}/{configuration}/{self.project}.pdb"
imp_path = self.root / f"VisualC/SDL/{platform}/{configuration}/{self.project}.lib"
test_path = self.root / f"VisualC/SDLtest/{platform}/{configuration}/{self.project}test.lib"
main_path = self.root / f"VisualC/SDLmain/{platform}/{configuration}/{self.project}main.lib"
dll_path.unlink(missing_ok=True)
pdb_path.unlink(missing_ok=True)
imp_path.unlink(missing_ok=True)
test_path.unlink(missing_ok=True)
main_path.unlink(missing_ok=True)
projects = [
self.root / "VisualC/SDL/SDL.vcxproj",
self.root / "VisualC/SDLmain/SDLmain.vcxproj",
self.root / "VisualC/SDLtest/SDLtest.vcxproj",
]
with self.section_printer.group(f"Build {arch} VS binary"):
vs.build(arch=arch, platform=platform, configuration=configuration, projects=projects)
if self.dry:
dll_path.parent.mkdir(parents=True, exist_ok=True)
dll_path.touch()
pdb_path.touch()
imp_path.touch()
main_path.parent.mkdir(parents=True, exist_ok=True)
main_path.touch()
test_path.parent.mkdir(parents=True, exist_ok=True)
test_path.touch()
assert dll_path.is_file(), f"{self.project}.dll has not been created"
assert pdb_path.is_file(), f"{self.project}.pdb has not been created"
assert imp_path.is_file(), f"{self.project}.lib has not been created"
assert main_path.is_file(), f"{self.project}main.lib has not been created"
assert test_path.is_file(), f"{self.project}est.lib has not been created"
zip_path = self.dist_path / f"{self.project}-{self.version}-win32-{arch}.zip"
zip_path.unlink(missing_ok=True)
logger.info("Creating %s", zip_path)
with zipfile.ZipFile(zip_path, mode="w", compression=zipfile.ZIP_DEFLATED) as zf:
logger.debug("Adding %s", dll_path.name)
zf.write(dll_path, arcname=dll_path.name)
logger.debug("Adding %s", "README-SDL.txt")
zf.write(self.root / "README-SDL.txt", arcname="README-SDL.txt")
self._zip_add_git_hash(zip_file=zf)
self.artifacts[f"VC-{arch}"] = zip_path
return VcArchDevel(dll=dll_path, pdb=pdb_path, imp=imp_path, main=main_path, test=test_path)
def build_vs_devel(self, arch_vc: dict[str, VcArchDevel]) -> None:
zip_path = self.dist_path / f"{self.project}-devel-{self.version}-VC.zip"
archive_prefix = f"{self.project}-{self.version}"
def zip_file(zf: zipfile.ZipFile, path: Path, arcrelpath: str):
arcname = f"{archive_prefix}/{arcrelpath}"
logger.debug("Adding %s to %s", path, arcname)
zf.write(path, arcname=arcname)
def zip_directory(zf: zipfile.ZipFile, directory: Path, arcrelpath: str):
for f in directory.iterdir():
if f.is_file():
arcname = f"{archive_prefix}/{arcrelpath}/{f.name}"
logger.debug("Adding %s to %s", f, arcname)
zf.write(f, arcname=arcname)
with zipfile.ZipFile(zip_path, mode="w", compression=zipfile.ZIP_DEFLATED) as zf:
for arch, binaries in arch_vc.items():
zip_file(zf, path=binaries.dll, arcrelpath=f"lib/{arch}/{binaries.dll.name}")
zip_file(zf, path=binaries.imp, arcrelpath=f"lib/{arch}/{binaries.imp.name}")
zip_file(zf, path=binaries.pdb, arcrelpath=f"lib/{arch}/{binaries.pdb.name}")
zip_file(zf, path=binaries.main, arcrelpath=f"lib/{arch}/{binaries.main.name}")
zip_file(zf, path=binaries.test, arcrelpath=f"lib/{arch}/{binaries.test.name}")
zip_directory(zf, directory=self.root / "include", arcrelpath="include")
zip_directory(zf, directory=self.root / "docs", arcrelpath="docs")
zip_directory(zf, directory=self.root / "VisualC/pkg-support/cmake", arcrelpath="cmake")
for txt in ("BUGS.txt", "README-SDL.txt", "WhatsNew.txt"):
zip_file(zf, path=self.root / txt, arcrelpath=txt)
zip_file(zf, path=self.root / "LICENSE.txt", arcrelpath="COPYING.txt")
zip_file(zf, path=self.root / "README.md", arcrelpath="README.txt")
self._zip_add_git_hash(zip_file=zf, root=archive_prefix)
self.artifacts["VC-devel"] = zip_path
@classmethod
def extract_sdl_version(cls, root: Path, project: str) -> str:
with open(root / f"include/SDL_version.h", "r") as f:
text = f.read()
major = next(re.finditer(r"^#define SDL_MAJOR_VERSION\s+([0-9]+)$", text, flags=re.M)).group(1)
minor = next(re.finditer(r"^#define SDL_MINOR_VERSION\s+([0-9]+)$", text, flags=re.M)).group(1)
micro = next(re.finditer(r"^#define SDL_PATCHLEVEL\s+([0-9]+)$", text, flags=re.M)).group(1)
return f"{major}.{minor}.{micro}"
def main(argv=None) -> int:
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 SDL")
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("--project", required=True, help="Name of the project (e.g. SDL2")
parser.add_argument("--create", choices=["source", "mingw", "win32", "framework", "android"], required=True, action="append", 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('--android-abis', dest="android_abis", nargs="*", choices=ANDROID_AVAILABLE_ABIS, default=list(ANDROID_AVAILABLE_ABIS), 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")
args = parser.parse_args(argv)
logging.basicConfig(level=args.loglevel, format='[%(levelname)s] %(message)s')
args.actions = set(args.actions)
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()
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
else:
args.commit = executer.run(["git", "rev-parse", args.commit], stdout=True, dry_out="e5812a9fd2cda317b503325a702ba3c1c37861d9").stdout.strip()
logger.info("Using commit %s", args.commit)
releaser = Releaser(
project=args.project,
commit=args.commit,
root=args.root,
dist_path=args.dist_path,
executer=executer,
section_printer=section_printer,
cmake_generator=args.cmake_generator,
)
if root_is_maybe_archive:
logger.warning("Building from archive. Skipping clean git tree check.")
else:
porcelain_status = executer.run(["git", "status", "--ignored", "--porcelain"], stdout=True, dry_out="\n").stdout.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.")
with section_printer.group("Arguments"):
print(f"project = {args.project}")
print(f"version = {releaser.version}")
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"cmake_generator = {args.cmake_generator}")
releaser.prepare()
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 "framework" in args.actions:
if platform.system() != "Darwin" and not args.dry:
parser.error("framework artifact(s) can only be built on Darwin")
releaser.create_framework()
if "win32" in args.actions:
if platform.system() != "Windows" and not args.dry:
parser.error("win32 artifact(s) can only be built on Windows")
with section_printer.group("Find Visual Studio"):
vs = VisualStudio(executer=executer)
x86 = releaser.build_vs(arch="x86", platform="Win32", vs=vs)
x64 = releaser.build_vs(arch="x64", platform="x64", vs=vs)
with section_printer.group("Create SDL VC development zip"):
arch_vc = {
"x86": x86,
"x64": x64,
}
releaser.build_vs_devel(arch_vc)
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")
if not args.android_abis:
parser.error("Need at least one Android ABI")
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}")
print(f"android_abis = {args.android_abis}")
releaser.create_android_archives(
android_api=args.android_api,
android_home=args.android_home,
android_ndk_home=args.android_ndk_home,
android_abis=args.android_abis,
)
with section_printer.group("Summary"):
print(f"artifacts = {releaser.artifacts}")
if args.github:
if args.dry:
os.environ["GITHUB_OUTPUT"] = "/tmp/github_output.txt"
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())

View file

@ -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()

View file

@ -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()

41
build-scripts/create-release.py Executable file
View file

@ -0,0 +1,41 @@
#!/usr/bin/env python
import argparse
from pathlib import Path
import logging
import re
import subprocess
ROOT = Path(__file__).resolve().parents[1]
def determine_project() -> str:
text = (ROOT / "CMakeLists.txt").read_text()
match = next(re.finditer(r"project\((?P<project>[a-zA-Z0-9_]+)\s+", text, flags=re.M))
project_with_version = match["project"]
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())

View file

@ -27,6 +27,12 @@ add_feature_info("TEST_SHARED" TEST_SHARED "Test linking with shared library")
option(TEST_STATIC "Test linking to static SDL2 library" ON)
add_feature_info("TEST_STATIC" TEST_STATIC "Test linking with static library")
option(TEST_TEST "Test linking to SDL3_test library" ON)
add_feature_info("TEST_TEST" TEST_STATIC "Test linking to SDL test library")
option(TEST_FULL "Run complete SDL test suite" OFF)
add_feature_info("TEST_FULL" TEST_FULL "Build full SDL testsuite")
if(TEST_SHARED)
find_package(SDL2 REQUIRED CONFIG COMPONENTS SDL2)
if(EMSCRIPTEN OR (WIN32 AND NOT WINDOWS_STORE))
@ -75,6 +81,11 @@ if(TEST_SHARED)
generate_export_header(sharedlib-shared-vars EXPORT_MACRO_NAME MYLIBRARY_EXPORT)
target_compile_definitions(sharedlib-shared-vars PRIVATE "EXPORT_HEADER=\"${CMAKE_CURRENT_BINARY_DIR}/sharedlib-shared-vars_export.h\"")
set_target_properties(sharedlib-shared-vars PROPERTIES C_VISIBILITY_PRESET "hidden")
if(TEST_TEST)
add_executable(sdltest-shared sdltest.c)
target_link_libraries(sdltest-shared PRIVATE SDL2::SDL2main SDL2::SDL2test SDL2::SDL2)
endif()
endif()
if(TEST_STATIC)
@ -111,6 +122,21 @@ if(TEST_STATIC)
target_link_libraries(cli-static-vars PRIVATE ${SDL2_STATIC_LIBRARIES})
target_include_directories(cli-static-vars PRIVATE ${SDL2_INCLUDE_DIRS})
endif()
if(CMAKE_Swift_COMPILER)
add_executable(swift-static main.swift)
target_include_directories(swift-static PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/swift")
target_link_libraries(swift-static PRIVATE SDL2::SDL2-static)
endif()
endif()
if(TEST_FULL)
enable_testing()
set(SDL_TESTS_TIMEOUT_MULTIPLIER "1" CACHE STRING "Test timeout multiplier")
set(SDL_TESTS_LINK_SHARED ${TEST_SHARED})
add_definitions(-DNO_BUILD_CONFIG)
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/../../test" SDL_test)
endif()
message(STATUS "SDL2_PREFIX: ${SDL2_PREFIX}")

9
cmake/test/sdltest.c Normal file
View file

@ -0,0 +1,9 @@
#include "SDL.h"
#include "SDL_test.h"
int main(int argc, char *argv[]) {
SDLTest_CommonState state;
SDLTest_CommonDefaultArgs(&state, argc, argv);
return 0;
}

View file

@ -0,0 +1,18 @@
The 32-bit files are in i686-w64-mingw32
The 64-bit files are in x86_64-w64-mingw32
To install SDL for native development:
make native
To install SDL for cross-compiling development:
make cross
Look at the example programs in ./test, and check out online documentation:
http://wiki.libsdl.org/
Join the SDL developer mailing list if you want to join the community:
http://www.libsdl.org/mailing-list.php
That's it!
Sam Lantinga <slouken@libsdl.org>

View file

@ -0,0 +1,30 @@
#
# Makefile for installing the mingw32 version of the SDL library
CROSS_PATH := /usr/local
ARCHITECTURES := i686-w64-mingw32 x86_64-w64-mingw32
all install:
@echo "Type \"make native\" to install 32-bit to /usr"
@echo "Type \"make cross\" to install 32-bit and 64-bit to $(CROSS_PATH)"
native:
make install-package arch=i686-w64-mingw32 prefix=/usr
cross:
for arch in $(ARCHITECTURES); do \
make install-package arch=$$arch prefix=$(CROSS_PATH)/$$arch; \
done
install-package:
@if test -d $(arch) && test -d $(prefix); then \
(cd $(arch) && cp -rv bin include lib share $(prefix)/); \
sed "s|^prefix=.*|prefix=$(prefix)|" <$(arch)/bin/sdl2-config >$(prefix)/bin/sdl2-config; \
chmod 755 $(prefix)/bin/sdl2-config; \
sed "s|^libdir=.*|libdir=\'$(prefix)/lib\'|" <$(arch)/lib/libSDL2.la >$(prefix)/lib/libSDL2.la; \
sed "s|^libdir=.*|libdir=\'$(prefix)/lib\'|" <$(arch)/lib/libSDL2main.la >$(prefix)/lib/libSDL2main.la; \
sed "s|^prefix=.*|prefix=$(prefix)|" <$(arch)/lib/pkgconfig/sdl2.pc >$(prefix)/lib/pkgconfig/sdl2.pc; \
else \
echo "*** ERROR: $(arch) or $(prefix) does not exist!"; \
exit 1; \
fi

View file

@ -2,9 +2,9 @@
# This file is meant to be placed in a cmake subfolder of SDL2-devel-2.x.y-mingw
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
set(sdl2_config_path "${CMAKE_CURRENT_LIST_DIR}/../i686-w64-mingw32/lib/cmake/SDL2/sdl2-config-version.cmake")
set(sdl2_config_path "${CMAKE_CURRENT_LIST_DIR}/../i686-w64-mingw32/lib/cmake/SDL2/SDL2ConfigVersion.cmake")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(sdl2_config_path "${CMAKE_CURRENT_LIST_DIR}/../x86_64-w64-mingw32/lib/cmake/SDL2/sdl2-config-version.cmake")
set(sdl2_config_path "${CMAKE_CURRENT_LIST_DIR}/../x86_64-w64-mingw32/lib/cmake/SDL2/SDL2ConfigVersion.cmake")
else()
set(PACKAGE_VERSION_UNSUITABLE TRUE)
return()

View file

@ -2,9 +2,9 @@
# This file is meant to be placed in a cmake subfolder of SDL2-devel-2.x.y-mingw
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
set(sdl2_config_path "${CMAKE_CURRENT_LIST_DIR}/../i686-w64-mingw32/lib/cmake/SDL2/sdl2-config.cmake")
set(sdl2_config_path "${CMAKE_CURRENT_LIST_DIR}/../i686-w64-mingw32/lib/cmake/SDL2/SDL2Config.cmake")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(sdl2_config_path "${CMAKE_CURRENT_LIST_DIR}/../x86_64-w64-mingw32/lib/cmake/SDL2/sdl2-config.cmake")
set(sdl2_config_path "${CMAKE_CURRENT_LIST_DIR}/../x86_64-w64-mingw32/lib/cmake/SDL2/SDL2Config.cmake")
else()
set(SDL2_FOUND FALSE)
return()