diff --git a/.gitattributes b/.gitattributes
index 4709b937ef..c69e378d2d 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -53,6 +53,10 @@
*.7z binary
*.ttf binary
*.stout binary
+*.so binary
+*.dll binary
+*.dylib binary
+*.jar binary
# Verify
*.verified.txt text eol=lf working-tree-encoding=UTF-8
diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index ada102fe57..2328aa0ac0 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -27,6 +27,8 @@ jobs:
with:
dotnet-version: '9.0.x'
dotnet-quality: 'preview'
+ - name: Install Workloads
+ run: dotnet workload restore
- name: Pack
# TODO decide whether we want experimental builds to use Debug or Release - using Release for now...
run: >-
@@ -70,6 +72,8 @@ jobs:
with:
dotnet-version: '8.0.x'
dotnet-quality: 'preview'
+ - name: Install Workloads
+ run: dotnet workload restore
- name: Restore
run: dotnet restore --runtime ${{ matrix.rid }}
- name: Test
diff --git a/.github/workflows/native.yml b/.github/workflows/native.yml
new file mode 100644
index 0000000000..55e14135d5
--- /dev/null
+++ b/.github/workflows/native.yml
@@ -0,0 +1,102 @@
+name: Native Builds
+on:
+ pull_request:
+ types: [opened, edited, synchronize]
+permissions:
+ pull-requests: write
+ contents: write
+env:
+ # A space-separated list of paths to native libraries to build.
+ NATIVE_LIBRARY_PATHS: "sources/SDL/Native"
+ # A space-separated list of submodule paths for each native library path. Use _ if a submodule is not used - this must
+ # match the number of spaces in NATIVE_LIBRARY_PATHS.
+ NATIVE_LIBRARY_SUBMODULE_PATHS: "eng/submodules/sdl"
+ # A space-separated list of shorthands to the native library paths that will build the native library for each native
+ # library path. This must match the number of spaces in NATIVE_LIBRARY_PATHS. If a shorthand builds multiple native
+ # binary paths, these will be deduplicated.
+ NATIVE_LIBRARY_SHORTHANDS: "SDL"
+jobs:
+ prerequisites:
+ name: PR Check
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - id: parse
+ name: Determine which native libraries the user has asked to build, and where to look for changes.
+ run: ./workflow-stage1.sh
+ working-directory: eng/native/buildsystem
+ env:
+ PR_COMMENT: ${{ github.event.pull_request.body }}
+ - uses: dorny/paths-filter@v3
+ id: filter
+ name: Determine which natives need to be rebuilt.
+ with:
+ filters: ${{ steps.parse.outputs.workflow_filters }}
+ - name: Find a warning message from a previous run, if applicable.
+ uses: peter-evans/find-comment@v3
+ id: fc
+ with:
+ issue-number: ${{ github.event.number }}
+ comment-author: "github-actions[bot]"
+ body-includes: "Some of the native library builds modified in this PR were not referenced in the PR description."
+ - id: strat
+ name: Create the matrix strategy for the native builds.
+ run: ./workflow-stage2.sh
+ working-directory: eng/native/buildsystem
+ env:
+ NATIVE_LIBRARY_APPLICABLE_SHORTHANDS: ${{ join(fromJSON(steps.filter.outputs.changes), ' ') }}
+ NATIVE_LIBRARY_USER_REFERENCED_SHORTHANDS: ${{ steps.parse.outputs.targets_referenced }}
+ PR_EXISTING_NOTICE_ID: ${{ steps.fc.outputs.comment-id }}
+ - name: Write a comment if needed.
+ if: ${{ steps.strat.outputs.comment_to_write }}
+ uses: peter-evans/create-or-update-comment@v4
+ with:
+ comment-id: ${{ steps.fc.outputs.comment-id }}
+ issue-number: ${{ github.event.number }}
+ body: ${{ steps.strat.outputs.comment_to_write }}
+ edit-mode: replace
+ outputs:
+ matrix_strategy: ${{ steps.strat.outputs.matrix_strategy }}
+ targets_referenced: ${{ steps.parse.outputs.targets_referenced }}
+ build:
+ needs: [prerequisites]
+ strategy:
+ matrix:
+ flat: ${{ fromJSON(needs.prerequisites.outputs.matrix_strategy) }}
+ runs-on: ${{ (startsWith(matrix.flat.runtime, 'osx') || startsWith(matrix.flat.runtime, 'ios') || startsWith(matrix.flat.runtime, 'tvos')) && 'macos-latest' || startsWith(matrix.flat.runtime, 'win') && 'windows-latest' || 'ubuntu-latest' }}
+ name: ${{ matrix.flat.target }} / ${{ matrix.flat.runtime }}
+ steps:
+ - uses: actions/checkout@v3
+ - run: |
+ echo "https://github.com/actions/upload-artifact/issues/174" > .workaround-${{ matrix.flat.target }}-${{ matrix.flat.runtime }}.txt
+ ${{ format('.{0}{1}', startsWith(matrix.flat.runtime, 'win') && '\' || '/', matrix.flat.exec) }}
+ working-directory: ${{ matrix.flat.dir }}
+ - uses: actions/upload-artifact@v4
+ with:
+ name: natives-${{ matrix.flat.target }}-${{ matrix.flat.runtime }}
+ path: |
+ ./.workaround-*.txt
+ ./${{ matrix.flat.dir }}/runtimes/${{ format('{0}{1}', matrix.flat.runtime, !contains(matrix.flat.runtime, '-') && '*' || '') }}/**/*
+ ./${{ matrix.flat.dir }}/lib/*${{ matrix.flat.runtime }}*/**/*
+ ./${{ matrix.flat.dir }}/*${{ matrix.flat.runtime }}*/**/*
+ commit:
+ name: Commit Binaries
+ needs: [prerequisites, build]
+ runs-on: ubuntu-latest
+ if: ${{ needs.prerequisites.outputs.targets_referenced }}
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ github.head_ref }}
+ - name: Download All Artifacts
+ uses: actions/download-artifact@v4
+ with:
+ pattern: natives-*
+ merge-multiple: true
+ - name: Commit Artifacts
+ run: |
+ git config --local user.email "9011267+dotnet-bot@users.noreply.github.com"
+ git config --local user.name "The Silk.NET Automaton"
+ git add .
+ git commit -m "Update native binaries for $(git rev-parse HEAD)"
+ git push
diff --git a/.gitignore b/.gitignore
index a92e1faac0..b97d80721c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -489,3 +489,12 @@ src/Website/Silk.NET.Statiq/cache
# Verify
*.received.*
+
+# Native Binaries
+!**/runtimes/*/native/*.dylib
+!**/runtimes/*/native/*.so
+!**/runtimes/*/native/*.dll
+!**/lib/**/*.aar
+build/
+!eng/build/
+.workaround*
diff --git a/Directory.Build.props b/Directory.Build.props
index 422df3b3dc..28890ca2d8 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -30,6 +30,7 @@
true
true
true
+ enable
@@ -64,10 +65,12 @@
true
SilkShippingControl;$(VersionDependsOn)
SilkShippingControl;$(PackageVersionDependsOn)
+ SilkNativePackaging;$(TargetsForTfmSpecificContentInPackage)
+ SilkShippingControl;$(GenerateNuspecDependsOn)
-
+
portable
true
true
diff --git a/Directory.Build.targets b/Directory.Build.targets
index 807f31cb54..7d0da4f662 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -139,6 +139,15 @@
+
+
+ false
+ false
+ true
+ NU5128;1591;$(NoWarn)
+ false
+
+
false
@@ -146,7 +155,9 @@
-
+
+
+
@@ -161,6 +172,7 @@
+
$([System.IO.File]::ReadAllText("$(MSBuildThisFileDirectory)docs/CHANGELOG.md"))
@@ -171,19 +183,81 @@
+ $(VersionSuffix)
$(SilkVersion)
$(SilkVersionSuffix)
$(SilkReleaseNotes)
$(SilkVersion)
$(SilkVersion)-$(VersionSuffix)
-
+
+
- true
- true
- true
- true
- full
+ $(MSBuildProjectDirectory)/version.txt
+ $([System.IO.File]::ReadAllText("$(SilkVersionTxtPath)").Trim())
+ $(PackageVersion)$(SilkOriginalVersionSuffix)
+ $(PackageVersion)-$(SilkOriginalVersionSuffix)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ true
+ true
+ full
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Silk.NET.sln b/Silk.NET.sln
index 45994a9bfc..139e7f1fac 100644
--- a/Silk.NET.sln
+++ b/Silk.NET.sln
@@ -95,6 +95,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Silk.NET", "sources\Core\Si
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Win32", "Win32", "{6E739132-EEAB-43A5-83C7-EB58C50D03A1}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Silk.NET.SDL.Native", "sources\SDL\Native\Silk.NET.SDL.Native.csproj", "{F16C0AB9-DE7E-4C09-9EE9-DAA8B8E935A6}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -153,6 +155,10 @@ Global
{6FA628B8-9696-4847-89F9-E58F470AF4FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6FA628B8-9696-4847-89F9-E58F470AF4FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6FA628B8-9696-4847-89F9-E58F470AF4FB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F16C0AB9-DE7E-4C09-9EE9-DAA8B8E935A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F16C0AB9-DE7E-4C09-9EE9-DAA8B8E935A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F16C0AB9-DE7E-4C09-9EE9-DAA8B8E935A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F16C0AB9-DE7E-4C09-9EE9-DAA8B8E935A6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -182,6 +188,7 @@ Global
{3CADD95A-179F-4ECF-A49D-4B753832C63C} = {475AEF7B-0154-4989-AF82-97E3A95A96AF}
{6FA628B8-9696-4847-89F9-E58F470AF4FB} = {5CD096DB-6C44-48F1-9093-AD4C84B6B7EC}
{6E739132-EEAB-43A5-83C7-EB58C50D03A1} = {DD29EA8F-B1A6-45AA-8D2E-B38DA56D9EF6}
+ {F16C0AB9-DE7E-4C09-9EE9-DAA8B8E935A6} = {EC4D7B06-D277-4411-BD7B-71A6D37683F0}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {78D2CF6A-60A1-43E3-837B-00B73C9DA384}
diff --git a/docs/for-contributors/build-system.md b/docs/for-contributors/build-system.md
index d25f34d605..09b72db789 100644
--- a/docs/for-contributors/build-system.md
+++ b/docs/for-contributors/build-system.md
@@ -83,6 +83,190 @@ top-level directory in `sources`. It is highly likely that we'll want to amend t
SilkTouch from this as this is unlikely to be useful to an end user. This is done using cursed MSBuild patterns that I
recommend just squinting at for ages until they click.
+### Native Packaging
+
+Native packaging is one of the most frustratingly difficult aspect of packaging a library such as Silk.NET in an
+effective, elegant way. Silk.NET 2.X had a fairly easy-to-maintain system, but there were some small issues we decided
+to factor into the rewrite.
+
+The primary goals in the native packaging system used for Silk.NET 3.0 are:
+- As in 2.X, ensuring our native binaries come from a trusted source (CI), and that executing these builds is as simple
+ as possible.
+- Making it as easy as possible to add a new native binary build.
+- Ensuring that the native binary builds are maximally low-maintenance, in-keeping with the native library author's
+ intent, and resistant to breakage when we update the native library version used.
+
+There are two parts to this: the GitHub Actions workflow and the MSBuild Usage. Obviously as this is the MSBuild Usage
+section, we'll discuss the latter here.
+
+NuGet's native packaging scheme in the simple case is fairly obvious - the native binaries are placed into the
+`runtimes/rid/native` directory of the package where `rid` is replaced with the appropriate runtime identifier. For fat
+binaries, we omit the architecture suffix. We automatically do this in the `SilkShippingControl` target (which is really
+just a kitchen sink of MSBuild fluff) in `Directory.Build.targets`, where all of the binaries are added as `None` items
+that are packed into the `runtimes` directory. The binaries are picked up from the project directory in the same
+`runtimes` directory structure as that which is added to the package.
+
+To create a new native package, first create a csproj with the following contents:
+```xml
+
+
+ net8.0
+ Native binaries for LIBRARY_NAME_HERE.
+ true
+
+
+```
+
+After that, create a `version.txt` that contains the `PackageVersion` for the native binary. Ideally you should create
+an `update.sh` script that will automatically update the submodule to the latest upstream release, and update the
+`version.txt` to contain that version. If your native library doesn't really have a versioning scheme (we've experienced
+this with some of the Google libraries e.g. ANGLE, SwiftShader, etc), then it's recommended that the version be set to
+a date-style version `YYYY.MM.DD` where the date used is the date of the commit the submodule is currently checked out
+to.
+
+Android is a bit of a unique case, as we not only have native binaries, we also have Java JARs in some cases. These need
+to be exposed to the .NET for Android toolchain to ensure these JARs are accessible. This toolchain produces an `aar`
+file which is added to the NuGet package, which incidentally includes both the JAR and the native binaries. Therefore,
+we exclude the android binaries from the `runtimes` directory in this case. If you have JARs, add the following to the
+native package csproj:
+```diff
+
+
+- net8.0
++ net8.0;net8.0-android
++ true
++ false
+
+
+```
+
+The JARs, Proguard configurations, and XML transforms (for the .NET for Android generator) will be picked up from an
+`android` subdirectory of the project folder. Native binaries will be picked up from `runtimes/android*/native` as
+usual, but obviously merged into the `aar` as above.
+
+iOS on the other hand is a lot simpler, however we still have some iOS-specific handling. Specifically, we inject a
+`targets` file that is pulled in by downstream packages to add the `NativeReference` with the appropriate flags. We have
+seen anecdotal evidence that modern .NET for iOS toolchains pull in `runtimes` `.a` files as `NativeReference`s
+automatically, however in some cases there are specific linker flags required which are not picked up automatically. The
+`.targets` file adds this. If these linker flags are required, add something similar to the following:
+```xml
+
+
+ -framework AudioToolbox -framework AVFoundation -framework CoreAudio -framework CoreBluetooth -framework CoreFoundation -framework CoreGraphics -framework CoreHaptics -framework CoreMotion -framework CoreVideo -framework GameController -framework IOKit -framework Metal -framework OpenGLES -framework QuartzCore -framework UIKit -framework Foundation
+
+
+```
+
+The `.targets` injected can be seen at `eng/native/nuget/NativeNuGetPackage.targets` with the `TO_BE_REPLACED`
+placeholders replaced in `Directory.Build.targets`.
+
+## Native Build Workflow
+
+As mentioned previously, we build all of our native binaries in CI to ensure they come from a trusted source and also to
+ensure silly mistakes like forgetting to update the binaries when we update the bindings don't happen. We check every
+single PR for changes to the native build and, if we detect any, tell the PR author that they need to declare those
+changes in their PR description. This is done by simply adding `/build-native sdl` for example in the description. This
+is to ensure an unrelated change or merge doesn't result in a rebuild of an unnecessary amount of native binaries, as
+was an issue with 2.X's build system. Also unlike 2.X, the binaries are committed straight to the PR rather than having
+a PR into that PR (as this was very annoying), in a single commit aggregating all the outputs from all of the builds.
+
+The workflow is split into three jobs:
+1. **PR Check** - runs on every PR, evaluates what binaries the author has indicated should be rebuilt.
+2. **Native Build** - a matrix job that uses a strategy determined dynamically as part of the PR Check to run all of the
+ required native builds on the appropriate runners.
+3. **Commit Native Binaries** - all the outputs from the matrix jobs are downloaded, aggregated, and then committed to
+ the PR.
+
+To add a new native build to this workflow, modify the `env` at the top of the `native.yml` GitHub Actions workflow:
+```yaml
+env:
+ # A space-separated list of paths to native libraries to build.
+ NATIVE_LIBRARY_PATHS: "sources/SDL/Native"
+ # A space-separated list of submodule paths for each native library path. Use _ if a submodule is not used - this must
+ # match the number of spaces in NATIVE_LIBRARY_PATHS.
+ NATIVE_LIBRARY_SUBMODULE_PATHS: "eng/submodules/sdl"
+ # A space-separated list of shorthands to the native library paths that will build the native library for each native
+ # library path. This must match the number of spaces in NATIVE_LIBRARY_PATHS. If a shorthand builds multiple native
+ # binary paths, these will be deduplicated.
+ NATIVE_LIBRARY_SHORTHANDS: "SDL"
+```
+
+This is obviously assuming the native library path is valid. After this, any PR that contains `/build-native whatever`
+where `whatever` is replaced with the "shorthand" added to `NATIVE_LIBRARY_SHORTHANDS` will run a native binary build on
+each PR change.
+
+After that, create the native package csproj as described in the MSBuild Usage section and add `build-rid.ext` scripts
+where `rid` is replaced with a runtime identifier and `ext` is replaced with `sh` or `cmd` if the build is running on
+Windows. All `osx`/`ios`/`tvos` prefixed RID builds run on macOS, all `win` prefixed RID builds run on Windows, and all
+other builds run on Linux. All of this again in the project directory/the directory added to `NATIVE_LIBRARY_PATHS`.
+
+Note that for Linux we strive to have compatibility with glibc 2.17 and above, which in our experience from 2.X is a
+happy medium in terms of wide compatibility and feature set in most cases. It's not easy to build for a specific glibc
+target on Linux, which is why we use `zig cc` for these targets. For CMake targets, this is easy as we include the
+relevant toolchain files all ready to use at `eng/native/cmake`. For the build scripts themselves, we include a
+`eng/native/buildsystem/download-zig.py` script which will download the zig toolchain to `eng/native/buildsystem/zig`,
+which should then be added to the `PATH`. This often looks similar to the following:
+```bash
+if [[ ! -z ${GITHUB_ACTIONS+x} ]]; then
+ ../../../eng/native/buildsystem/download-zig.py
+ export PATH="$PATH:$(readlink -f "../../../eng/native/buildsystem/zig")"
+fi
+```
+
+Note that there are no prerequisite actions run before the native build occurs in the Build job, so these need to be
+integrated into the build scripts, using the `GITHUB_ACTIONS` environment variable as appropriate. Other cases where
+this is used beyond downloading Zig is installing `apt` dependencies, installing Android toolchains using `sdkmanager`,
+etc.
+
+### PR Check
+
+First, the script located at `eng/native/buildsystem/workflow-stage1.sh` is run. This script outputs something similar
+to the following to `GITHUB_OUTPUT`:
+```
+workflow_filters<> $GITHUB_OUTPUT
+for item in $NATIVE_LIBRARY_UNIQUE_SHORTHANDS; do
+ # Add the submodule paths and a glob for the native folder to the workflow filters
+ workflow_filter="$item: ["
+ i=0
+ filter_delim=""
+ for target in ${NATIVE_LIBRARY_SHORTHANDS_ARRAY[@]}; do
+ if [[ "$target" == "$item" ]]; then
+ workflow_filter="$workflow_filter$filter_delim\"${NATIVE_LIBRARY_PATHS_ARRAY[$i]}/*\", \"${NATIVE_LIBRARY_SUBMODULE_PATHS_ARRAY[$i]}\""
+ filter_delim=", "
+ fi
+ i=$(expr $i + 1)
+ done
+ echo "$workflow_filter]" >> $GITHUB_OUTPUT
+done
+echo EOF >> $GITHUB_OUTPUT
+
+# Get a list of targets referenced by the user - we won't build anything we're not asked to build, but at the same time
+# we want to yell at them (in stage 2) if they've built something they've gone and modified.
+TARGETS_REFERENCED=""
+ref_delim=""
+while read line
+do
+ for item in $NATIVE_LIBRARY_UNIQUE_SHORTHANDS; do
+ if [[ ${line,,} =~ ^/build-native.*[[:space:]]${item,,}([[:space:]].*)?$ ]]; then
+ TARGETS_REFERENCED="$TARGETS_REFERENCED$ref_delim$item"
+ ref_delim=" "
+ continue
+ fi
+ done
+done <<< "$PR_COMMENT"
+echo "targets_referenced=$TARGETS_REFERENCED" >> $GITHUB_OUTPUT
diff --git a/eng/native/buildsystem/workflow-stage2.sh b/eng/native/buildsystem/workflow-stage2.sh
new file mode 100755
index 0000000000..e4a9c2cc7f
--- /dev/null
+++ b/eng/native/buildsystem/workflow-stage2.sh
@@ -0,0 +1,49 @@
+#!/usr/bin/env -S bash -eu
+. workflow-common.sh
+
+# Now we determine the jobs we actually want to run
+IFS=' ' read -a NATIVE_LIBRARY_APPLICABLE_SHORTHANDS_ARRAY <<< "$NATIVE_LIBRARY_APPLICABLE_SHORTHANDS"
+IFS=' ' read -a NATIVE_LIBRARY_USER_REFERENCED_SHORTHANDS_ARRAY <<< "$NATIVE_LIBRARY_USER_REFERENCED_SHORTHANDS"
+
+COMMENT="Some of the native library builds modified in this PR were not referenced in the PR description. Please ensure that the PR description contains \`/build-native $NATIVE_LIBRARY_APPLICABLE_SHORTHANDS\`. These libraries won't be rebuilt without this being specified. If you believe this is in error, then please write a comment explaining why and ignore this suggestion. This comment will be automatically updated if rectified."
+if [[ ${PR_EXISTING_NOTICE_ID:-0} == 0 ]]; then
+ PR_EXISTING_NOTICE_ID=""
+fi
+
+ANGRY_COMMENT=false
+if [ "${#NATIVE_LIBRARY_APPLICABLE_SHORTHANDS_ARRAY[@]}" -gt "${#NATIVE_LIBRARY_USER_REFERENCED_SHORTHANDS_ARRAY[@]}" ]; then
+ ANGRY_COMMENT=true
+else
+ COMMENT="All native library builds modified in this PR shall attempt to be built by CI."
+fi
+
+echo "matrix_strategy<> $GITHUB_OUTPUT
+echo "[" >> $GITHUB_OUTPUT
+json_open="{"
+for item in $NATIVE_LIBRARY_USER_REFERENCED_SHORTHANDS; do
+ i=0
+ for target in ${NATIVE_LIBRARY_SHORTHANDS_ARRAY[@]}; do
+ if [[ "$target" == "$item" ]]; then
+ shopt -s nullglob
+ for runtime_script in "../../../${NATIVE_LIBRARY_PATHS_ARRAY[$i]}"/build-*.*; do
+ runtime="$(basename "$runtime_script")"
+ runtime="${runtime:6}" # trim build- prefix
+ runtime="${runtime%.*}" # remove extension
+ echo "$json_open" >> $GITHUB_OUTPUT
+ json_open=",{"
+ echo " \"target\": \"$target\"," >> $GITHUB_OUTPUT
+ echo " \"runtime\": \"$runtime\"," >> $GITHUB_OUTPUT
+ # :9 trim ../../../ prefix
+ echo " \"exec\": \"$(basename "$runtime_script")\"," >> $GITHUB_OUTPUT
+ echo " \"dir\": \"$(dirname "${runtime_script:9}")\"" >> $GITHUB_OUTPUT
+ echo "}" >> $GITHUB_OUTPUT
+ done
+ fi
+ i=$(expr $i + 1)
+ done
+done
+echo "]" >> $GITHUB_OUTPUT
+echo EOF >> $GITHUB_OUTPUT
+if [[ $PR_EXISTING_NOTICE_ID != 0 && $PR_EXISTING_NOTICE_ID != "" || $ANGRY_COMMENT == true ]]; then
+ echo "comment_to_write=$COMMENT" >> $GITHUB_OUTPUT
+fi
diff --git a/eng/native/cmake/fudge.sh b/eng/native/cmake/fudge.sh
new file mode 100755
index 0000000000..4f616cf2fb
--- /dev/null
+++ b/eng/native/cmake/fudge.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+# Origignal script from https://github.com/ziglang/zig/issues/4911
+# Modified to add SILKDOTNET_ paths in response to some issues with SwiftShader
+
+args=""
+for arg in "$@"
+do
+ parg="$arg"
+
+ option=${arg%=*}
+ target=${arg#*=}
+ if [[ $option == "-march" || $option == "-mcpu" || $option == "-mtune" ]]; then
+ moveon=0
+ for replace in $SILKDOTNET_ReplaceArchitectureZigCcFlags
+ do
+ replacetarget=${replace%=*}
+ replacement=${replace#*=}
+ # echo $replacetarget A $replacement B $target END
+ if [[ $replacetarget == $target ]]; then
+ if [[ "$replacement" == "" ]]; then
+ moveon=1
+ else
+ target="$replacement"
+ fi
+ fi
+ done
+ if [[ $moveon == 1 || "$SILKDOTNET_RemoveAllPotentiallyProblematicZigCcFlags" == "1" ]]; then
+ continue
+ else
+ fixedTarget=${target//-/_}
+ parg="$option=$fixedTarget"
+ fi
+ fi
+ args="$args $parg"
+done
diff --git a/eng/native/cmake/zig-ar.cmd b/eng/native/cmake/zig-ar.cmd
new file mode 100755
index 0000000000..a97e9bd772
--- /dev/null
+++ b/eng/native/cmake/zig-ar.cmd
@@ -0,0 +1,2 @@
+@echo off
+zig ar %*
\ No newline at end of file
diff --git a/eng/native/cmake/zig-ar.sh b/eng/native/cmake/zig-ar.sh
new file mode 100755
index 0000000000..3d69448482
--- /dev/null
+++ b/eng/native/cmake/zig-ar.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+zig ar "$@"
diff --git a/eng/native/cmake/zig-c++.cmd b/eng/native/cmake/zig-c++.cmd
new file mode 100755
index 0000000000..2b066177e4
--- /dev/null
+++ b/eng/native/cmake/zig-c++.cmd
@@ -0,0 +1,3 @@
+@echo off
+: TODO add -march/-mtune handling if necessary
+zig c++ %*
\ No newline at end of file
diff --git a/eng/native/cmake/zig-c++.sh b/eng/native/cmake/zig-c++.sh
new file mode 100755
index 0000000000..fafec74d0c
--- /dev/null
+++ b/eng/native/cmake/zig-c++.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+. "$(dirname ${BASH_SOURCE[0]})/fudge.sh" $args
+zig c++ $args
diff --git a/eng/native/cmake/zig-cc.cmd b/eng/native/cmake/zig-cc.cmd
new file mode 100755
index 0000000000..b22d092542
--- /dev/null
+++ b/eng/native/cmake/zig-cc.cmd
@@ -0,0 +1,3 @@
+@echo off
+: TODO add -march/-mtune handling if necessary
+zig cc %*
\ No newline at end of file
diff --git a/eng/native/cmake/zig-cc.sh b/eng/native/cmake/zig-cc.sh
new file mode 100755
index 0000000000..a49268a952
--- /dev/null
+++ b/eng/native/cmake/zig-cc.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+. "$(dirname ${BASH_SOURCE[0]})/fudge.sh" $args
+zig cc $args
diff --git a/eng/native/cmake/zig-ranlib.cmd b/eng/native/cmake/zig-ranlib.cmd
new file mode 100755
index 0000000000..e0c5da410a
--- /dev/null
+++ b/eng/native/cmake/zig-ranlib.cmd
@@ -0,0 +1,2 @@
+@echo off
+zig ranlib %*
\ No newline at end of file
diff --git a/eng/native/cmake/zig-ranlib.sh b/eng/native/cmake/zig-ranlib.sh
new file mode 100755
index 0000000000..5caa38e278
--- /dev/null
+++ b/eng/native/cmake/zig-ranlib.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+zig ranlib "$@"
diff --git a/eng/native/cmake/zig-rc.cmd b/eng/native/cmake/zig-rc.cmd
new file mode 100755
index 0000000000..5c4482c8d6
--- /dev/null
+++ b/eng/native/cmake/zig-rc.cmd
@@ -0,0 +1,2 @@
+@echo off
+zig rc %*
\ No newline at end of file
diff --git a/eng/native/cmake/zig-rc.sh b/eng/native/cmake/zig-rc.sh
new file mode 100755
index 0000000000..4be7275e01
--- /dev/null
+++ b/eng/native/cmake/zig-rc.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+zig rc "$@"
diff --git a/eng/native/cmake/zig-toolchain-aarch64-linux-gnu.2.17.cmake b/eng/native/cmake/zig-toolchain-aarch64-linux-gnu.2.17.cmake
new file mode 100755
index 0000000000..3569631dda
--- /dev/null
+++ b/eng/native/cmake/zig-toolchain-aarch64-linux-gnu.2.17.cmake
@@ -0,0 +1,2 @@
+set(ZIG_TARGET "aarch64-linux-gnu.2.17")
+include(${CMAKE_CURRENT_LIST_DIR}/zig-toolchain.cmake)
diff --git a/eng/native/cmake/zig-toolchain-arm-linux-gnueabihf.2.17.cmake b/eng/native/cmake/zig-toolchain-arm-linux-gnueabihf.2.17.cmake
new file mode 100755
index 0000000000..74be23e020
--- /dev/null
+++ b/eng/native/cmake/zig-toolchain-arm-linux-gnueabihf.2.17.cmake
@@ -0,0 +1,2 @@
+set(ZIG_TARGET "arm-linux-gnueabihf.2.17")
+include(${CMAKE_CURRENT_LIST_DIR}/zig-toolchain.cmake)
diff --git a/eng/native/cmake/zig-toolchain-arm-linux-gnueabihf.2.34.cmake b/eng/native/cmake/zig-toolchain-arm-linux-gnueabihf.2.34.cmake
new file mode 100755
index 0000000000..d228f027a9
--- /dev/null
+++ b/eng/native/cmake/zig-toolchain-arm-linux-gnueabihf.2.34.cmake
@@ -0,0 +1,2 @@
+set(ZIG_TARGET "arm-linux-gnueabihf.2.34")
+include(${CMAKE_CURRENT_LIST_DIR}/zig-toolchain.cmake)
diff --git a/eng/native/cmake/zig-toolchain-x86_64-linux-gnu.2.17.cmake b/eng/native/cmake/zig-toolchain-x86_64-linux-gnu.2.17.cmake
new file mode 100755
index 0000000000..3810041742
--- /dev/null
+++ b/eng/native/cmake/zig-toolchain-x86_64-linux-gnu.2.17.cmake
@@ -0,0 +1,2 @@
+set(ZIG_TARGET "x86_64-linux-gnu.2.17")
+include(${CMAKE_CURRENT_LIST_DIR}/zig-toolchain.cmake)
diff --git a/eng/native/cmake/zig-toolchain.cmake b/eng/native/cmake/zig-toolchain.cmake
new file mode 100755
index 0000000000..94ed03c2e6
--- /dev/null
+++ b/eng/native/cmake/zig-toolchain.cmake
@@ -0,0 +1,40 @@
+include_guard()
+
+if(CMAKE_GENERATOR MATCHES "Visual Studio")
+ message(FATAL_ERROR "Visual Studio generator not supported, use: cmake -G Ninja")
+endif()
+
+if(NOT ZIG_TARGET MATCHES "^([a-zZ-Z0-9_]+)-([a-zZ-Z0-9_]+)-([a-zZ-Z0-9_.]+)$")
+ message(FATAL_ERROR "Expected -DZIG_TARGET=--")
+endif()
+
+set(ZIG_ARCH ${CMAKE_MATCH_1})
+set(ZIG_OS ${CMAKE_MATCH_2})
+set(ZIG_ABI ${CMAKE_MATCH_3})
+
+if(ZIG_OS STREQUAL "linux")
+ set(CMAKE_SYSTEM_NAME "Linux")
+elseif(ZIG_OS STREQUAL "windows")
+ set(CMAKE_SYSTEM_NAME "Windows")
+elseif(ZIG_OS STREQUAL "macos")
+ set(CMAKE_SYSTEM_NAME "Darwin")
+else()
+ message(WARNING "Unknown OS: ${ZIG_OS}")
+endif()
+
+set(CMAKE_SYSTEM_VERSION 1)
+set(CMAKE_SYSTEM_PROCESSOR ${ZIG_ARCH})
+
+if(WIN32)
+ set(SCRIPT_SUFFIX ".cmd")
+else()
+ set(SCRIPT_SUFFIX ".sh")
+endif()
+
+# This is working (thanks to Simon for finding this trick)
+set(CMAKE_AR "${CMAKE_CURRENT_LIST_DIR}/zig-ar${SCRIPT_SUFFIX}")
+set(CMAKE_RANLIB "${CMAKE_CURRENT_LIST_DIR}/zig-ranlib${SCRIPT_SUFFIX}")
+set(CMAKE_RC_COMPILER "${CMAKE_CURRENT_LIST_DIR}/zig-rc${SCRIPT_SUFFIX}")
+set(CMAKE_ASM_COMPILER "${CMAKE_CURRENT_LIST_DIR}/zig-cc${SCRIPT_SUFFIX}" -target ${ZIG_TARGET})
+set(CMAKE_C_COMPILER "${CMAKE_CURRENT_LIST_DIR}/zig-cc${SCRIPT_SUFFIX}" -target ${ZIG_TARGET})
+set(CMAKE_CXX_COMPILER "${CMAKE_CURRENT_LIST_DIR}/zig-c++${SCRIPT_SUFFIX}" -target ${ZIG_TARGET})
diff --git a/eng/native/nuget/NativeNuGetPackage.targets b/eng/native/nuget/NativeNuGetPackage.targets
new file mode 100644
index 0000000000..48b69cefe5
--- /dev/null
+++ b/eng/native/nuget/NativeNuGetPackage.targets
@@ -0,0 +1,23 @@
+
+
+
+ <_TO_BE_REPLACED_PROPERTY_PREFIX_IsMtouch Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios' or $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst' or $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tvos'">true
+
+
+
+ Static
+ True
+ True
+ False
+ TO_BE_REPLACED_MTOUCH_NATIVE_REFERENCE_LINKER_FLAGS
+
+
+ Static
+ True
+ True
+ False
+ TO_BE_REPLACED_MTOUCH_NATIVE_REFERENCE_LINKER_FLAGS
+
+
+
diff --git a/sources/Core/Core/Silk.NET.Core.csproj b/sources/Core/Core/Silk.NET.Core.csproj
index 5ae2cd8acf..098140a0ee 100644
--- a/sources/Core/Core/Silk.NET.Core.csproj
+++ b/sources/Core/Core/Silk.NET.Core.csproj
@@ -1,6 +1,7 @@
+
net8.0
enable
enable
@@ -9,8 +10,8 @@
-
-
+
+
diff --git a/sources/Core/Silk.NET/Silk.NET.csproj b/sources/Core/Silk.NET/Silk.NET.csproj
index 043345809c..cfd006eea2 100644
--- a/sources/Core/Silk.NET/Silk.NET.csproj
+++ b/sources/Core/Silk.NET/Silk.NET.csproj
@@ -6,9 +6,7 @@
enable
A package that will pull in all non-extension Silk.NET packages for every API.
You probably don't want all that, and it is strongly recommended to pull in only the packages you need instead. This package exists just to simplify project bring-up.
- false
- true
- NU5128
+ true
diff --git a/sources/SDL/Native/.gitignore b/sources/SDL/Native/.gitignore
new file mode 100644
index 0000000000..8a0e082fc5
--- /dev/null
+++ b/sources/SDL/Native/.gitignore
@@ -0,0 +1 @@
+!android/*.jar
diff --git a/sources/SDL/Native/Silk.NET.SDL.Native.csproj b/sources/SDL/Native/Silk.NET.SDL.Native.csproj
new file mode 100644
index 0000000000..cf694ad540
--- /dev/null
+++ b/sources/SDL/Native/Silk.NET.SDL.Native.csproj
@@ -0,0 +1,12 @@
+
+
+
+ net8.0;net8.0-android
+ Native binaries for SDL3.
+ true
+ true
+ -framework AudioToolbox -framework AVFoundation -framework CoreAudio -framework CoreBluetooth -framework CoreFoundation -framework CoreGraphics -framework CoreHaptics -framework CoreMotion -framework CoreVideo -framework GameController -framework IOKit -framework Metal -framework OpenGLES -framework QuartzCore -framework UIKit -framework Foundation
+ false
+
+
+
diff --git a/sources/SDL/Native/android/SDL3.jar b/sources/SDL/Native/android/SDL3.jar
new file mode 100644
index 0000000000..f19ae15904
Binary files /dev/null and b/sources/SDL/Native/android/SDL3.jar differ
diff --git a/sources/SDL/Native/android/proguard.txt b/sources/SDL/Native/android/proguard.txt
new file mode 100644
index 0000000000..fc0a4f5c92
--- /dev/null
+++ b/sources/SDL/Native/android/proguard.txt
@@ -0,0 +1,75 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in [sdk]/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# https://developer.android.com/build/shrink-code
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.SDLActivity {
+ java.lang.String nativeGetHint(java.lang.String); # Java-side doesn't use this, so it gets minified, but C-side still tries to register it
+ java.lang.String clipboardGetText();
+ boolean clipboardHasText();
+ void clipboardSetText(java.lang.String);
+ int createCustomCursor(int[], int, int, int, int);
+ void destroyCustomCursor(int);
+ android.content.Context getContext();
+ boolean getManifestEnvironmentVariables();
+ android.view.Surface getNativeSurface();
+ void initTouch();
+ boolean isAndroidTV();
+ boolean isChromebook();
+ boolean isDeXMode();
+ boolean isScreenKeyboardShown();
+ boolean isTablet();
+ void manualBackButton();
+ int messageboxShowMessageBox(int, java.lang.String, java.lang.String, int[], int[], java.lang.String[], int[]);
+ void minimizeWindow();
+ boolean openURL(java.lang.String);
+ void requestPermission(java.lang.String, int);
+ boolean showToast(java.lang.String, int, int, int, int);
+ boolean sendMessage(int, int);
+ boolean setActivityTitle(java.lang.String);
+ boolean setCustomCursor(int);
+ void setOrientation(int, int, boolean, java.lang.String);
+ boolean setRelativeMouseEnabled(boolean);
+ boolean setSystemCursor(int);
+ void setWindowStyle(boolean);
+ boolean shouldMinimizeOnFocusLoss();
+ boolean showTextInput(int, int, int, int, int);
+ boolean supportsRelativeMouse();
+ int openFileDescriptor(java.lang.String, java.lang.String);
+ boolean showFileDialog(java.lang.String[], boolean, boolean, int);
+}
+
+-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.HIDDeviceManager {
+ void closeDevice(int);
+ boolean initialize(boolean, boolean);
+ boolean openDevice(int);
+ boolean readReport(int, byte[], boolean);
+ int writeReport(int, byte[], boolean);
+}
+
+-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.SDLAudioManager {
+ void registerAudioDeviceCallback();
+ void unregisterAudioDeviceCallback();
+ void audioSetThreadPriority(boolean, int);
+}
+
+-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.SDLControllerManager {
+ void pollInputDevices();
+ void pollHapticDevices();
+ void hapticRun(int, float, int);
+ void hapticRumble(int, float, float, int);
+ void hapticStop(int);
+}
diff --git a/sources/SDL/Native/android/transform.xml b/sources/SDL/Native/android/transform.xml
new file mode 100644
index 0000000000..ca675b659c
--- /dev/null
+++ b/sources/SDL/Native/android/transform.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+ true
+ true
+ true
+
diff --git a/sources/SDL/Native/build-android.sh b/sources/SDL/Native/build-android.sh
new file mode 100755
index 0000000000..7b2714e6c8
--- /dev/null
+++ b/sources/SDL/Native/build-android.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env -S bash -eu
+
+if [ ! -e ../../../eng/submodules/sdl/CMakeLists.txt ]; then
+ git submodule update --init --recursive --depth 1 ../../../eng/submodules/sdl
+fi
+
+python="python"
+if [ ! -z "$GITHUB_ACTIONS" ]; then
+ # NDK already installed: https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2404-Readme.md
+ sdkmanager=( /usr/local/lib/android/sdk/cmdline-tools/*/bin/sdkmanager )
+ ${sdkmanager[-1]} --install "platforms;android-19"
+ sudo apt install python3.11 ninja-build
+ python="python3.11"
+fi
+
+$python ../../../eng/submodules/sdl/build-scripts/build-release.py --actions android --root ../../../eng/submodules/sdl
+mkdir -p runtimes/android-x86/native runtimes/android-x64/native runtimes/android-arm/native runtimes/android-arm64/native android
+cp ../../../eng/submodules/sdl/install-android/arm64-v8a-install/lib/libSDL3.so runtimes/android-arm64/native
+cp ../../../eng/submodules/sdl/install-android/armeabi-v7a-install/lib/libSDL3.so runtimes/android-arm/native
+cp ../../../eng/submodules/sdl/install-android/x86-install/lib/libSDL3.so runtimes/android-x86/native
+cp ../../../eng/submodules/sdl/install-android/x86_64-install/lib/libSDL3.so runtimes/android-x64/native
+jars=( ../../../eng/submodules/sdl/install-android/armeabi-v7a-install/share/java/SDL3/SDL3-*.jar )
+cp "${jars[1]}" android/SDL3.jar
+cp "$(dirname "${jars[1]}")/proguard.txt" android/proguard.txt
diff --git a/sources/SDL/Native/build-ios.sh b/sources/SDL/Native/build-ios.sh
new file mode 100755
index 0000000000..7bb8178036
--- /dev/null
+++ b/sources/SDL/Native/build-ios.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env -S bash -eu
+
+if [ ! -e ../../../eng/submodules/sdl/CMakeLists.txt ]; then
+ git submodule update --init --recursive --depth 1 ../../../eng/submodules/sdl
+fi
+
+rm -rf build
+mkdir build
+cd build
+cmake ../../../../eng/submodules/sdl -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphoneos "-DCMAKE_OSX_ARCHITECTURES=arm64;armv7s" -DCMAKE_OSX_DEPLOYMENT_TARGET=9.0 -DCMAKE_BUILD_TYPE=Release -DSDL_STATIC=ON
+cmake --build . --parallel
+cd ..
+mkdir -p runtimes/ios/native
+cp build/libSDL3.a runtimes/ios/native
diff --git a/sources/SDL/Native/build-iossimulator.sh b/sources/SDL/Native/build-iossimulator.sh
new file mode 100755
index 0000000000..6ae6577ddd
--- /dev/null
+++ b/sources/SDL/Native/build-iossimulator.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env -S bash -eu
+
+if [ ! -e ../../../eng/submodules/sdl/CMakeLists.txt ]; then
+ git submodule update --init --recursive --depth 1 ../../../eng/submodules/sdl
+fi
+
+rm -rf build
+mkdir build
+cd build
+cmake ../../../../eng/submodules/sdl -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphonesimulator "-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64" -DCMAKE_OSX_DEPLOYMENT_TARGET=9.0 -DCMAKE_BUILD_TYPE=Release -DSDL_STATIC=ON
+cmake --build . --parallel
+cd ..
+mkdir -p runtimes/iossimulator/native
+cp build/libSDL3.a runtimes/iossimulator/native
diff --git a/sources/SDL/Native/build-linux-arm.sh b/sources/SDL/Native/build-linux-arm.sh
new file mode 100755
index 0000000000..22d2ed4898
--- /dev/null
+++ b/sources/SDL/Native/build-linux-arm.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env -S bash -eu
+if [ ! -e ../../../eng/submodules/sdl/CMakeLists.txt ]; then
+ git submodule update --init --recursive --depth 1 ../../../eng/submodules/sdl
+fi
+
+if [[ ! -z ${GITHUB_ACTIONS+x} ]]; then
+ ../../../eng/native/buildsystem/download-zig.py
+ export PATH="$PATH:$(readlink -f "../../../eng/native/buildsystem/zig")"
+ sudo apt-get update
+ sudo apt-get install build-essential git make \
+ pkg-config cmake ninja-build gnome-desktop-testing libasound2-dev libpulse-dev \
+ libaudio-dev libjack-dev libsndio-dev libx11-dev libxext-dev \
+ libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev \
+ libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev \
+ libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev fcitx-libs-dev \
+ libpipewire-0.3-dev libwayland-dev libdecor-0-dev liburing-dev
+fi
+rm -rf build
+mkdir build
+cd build
+cmake ../../../../eng/submodules/sdl -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../../../../eng/native/cmake/zig-toolchain-arm-linux-gnueabihf.2.34.cmake
+cmake --build . --parallel
+cd ..
+mkdir -p runtimes/linux-arm/native
+cp build/libSDL3.so runtimes/linux-arm/native
diff --git a/sources/SDL/Native/build-linux-arm64.sh b/sources/SDL/Native/build-linux-arm64.sh
new file mode 100755
index 0000000000..e39d9b3ada
--- /dev/null
+++ b/sources/SDL/Native/build-linux-arm64.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env -S bash -eu
+if [ ! -e ../../../eng/submodules/sdl/CMakeLists.txt ]; then
+ git submodule update --init --recursive --depth 1 ../../../eng/submodules/sdl
+fi
+
+if [[ ! -z ${GITHUB_ACTIONS+x} ]]; then
+ ../../../eng/native/buildsystem/download-zig.py
+ export PATH="$PATH:$(readlink -f "../../../eng/native/buildsystem/zig")"
+ sudo apt-get update
+ sudo apt-get install build-essential git make \
+ pkg-config cmake ninja-build gnome-desktop-testing libasound2-dev libpulse-dev \
+ libaudio-dev libjack-dev libsndio-dev libx11-dev libxext-dev \
+ libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev \
+ libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev \
+ libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev fcitx-libs-dev \
+ libpipewire-0.3-dev libwayland-dev libdecor-0-dev liburing-dev
+fi
+rm -rf build
+mkdir build
+cd build
+cmake ../../../../eng/submodules/sdl -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../../../../eng/native/cmake/zig-toolchain-aarch64-linux-gnu.2.17.cmake
+cmake --build . --parallel
+cd ..
+mkdir -p runtimes/linux-arm64/native
+cp build/libSDL3.so runtimes/linux-arm64/native
diff --git a/sources/SDL/Native/build-linux-x64.sh b/sources/SDL/Native/build-linux-x64.sh
new file mode 100755
index 0000000000..eb6312105f
--- /dev/null
+++ b/sources/SDL/Native/build-linux-x64.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env -S bash -eu
+if [ ! -e ../../../eng/submodules/sdl/CMakeLists.txt ]; then
+ git submodule update --init --recursive --depth 1 ../../../eng/submodules/sdl
+fi
+
+if [[ ! -z ${GITHUB_ACTIONS+x} ]]; then
+ ../../../eng/native/buildsystem/download-zig.py
+ export PATH="$PATH:$(readlink -f "../../../eng/native/buildsystem/zig")"
+ sudo apt-get update
+ sudo apt-get install build-essential git make \
+ pkg-config cmake ninja-build gnome-desktop-testing libasound2-dev libpulse-dev \
+ libaudio-dev libjack-dev libsndio-dev libx11-dev libxext-dev \
+ libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev \
+ libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev \
+ libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev fcitx-libs-dev \
+ libpipewire-0.3-dev libwayland-dev libdecor-0-dev liburing-dev
+fi
+rm -rf build
+mkdir build
+cd build
+cmake ../../../../eng/submodules/sdl -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../../../../eng/native/cmake/zig-toolchain-x86_64-linux-gnu.2.17.cmake
+cmake --build . --parallel
+cd ..
+mkdir -p runtimes/linux-x64/native
+cp build/libSDL3.so runtimes/linux-x64/native
diff --git a/sources/SDL/Native/build-osx.sh b/sources/SDL/Native/build-osx.sh
new file mode 100755
index 0000000000..1fa03b62ff
--- /dev/null
+++ b/sources/SDL/Native/build-osx.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/env -S bash -eu
+if [ ! -e ../../../eng/submodules/sdl/CMakeLists.txt ]; then
+ git submodule update --init --recursive --depth 1 ../../../eng/submodules/sdl
+fi
+
+rm -rf build
+mkdir build
+cd build
+cmake ../../../../eng/submodules/sdl "-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64" -DCMAKE_OSX_DEPLOYMENT_TARGET=10.11 -DCMAKE_BUILD_TYPE=Release
+cmake --build . --parallel
+cd ..
+mkdir -p runtimes/osx/native
+cp build/libSDL3.dylib runtimes/osx/native
diff --git a/sources/SDL/Native/build-tvos.sh b/sources/SDL/Native/build-tvos.sh
new file mode 100755
index 0000000000..40190bf43c
--- /dev/null
+++ b/sources/SDL/Native/build-tvos.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env -S bash -eu
+
+if [ ! -e ../../../eng/submodules/sdl/CMakeLists.txt ]; then
+ git submodule update --init --recursive --depth 1 ../../../eng/submodules/sdl
+fi
+
+rm -rf build
+mkdir build
+cd build
+cmake ../../../../eng/submodules/sdl -DCMAKE_SYSTEM_NAME=tvOS -DCMAKE_OSX_SYSROOT=appletvos "-DCMAKE_OSX_ARCHITECTURES=arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET=9.0 -DCMAKE_BUILD_TYPE=Release -DSDL_STATIC=ON
+cmake --build . --parallel
+cd ..
+mkdir -p runtimes/tvos/native
+cp build/libSDL3.a runtimes/tvos/native
diff --git a/sources/SDL/Native/build-tvossimulator.sh b/sources/SDL/Native/build-tvossimulator.sh
new file mode 100755
index 0000000000..7a02d1d959
--- /dev/null
+++ b/sources/SDL/Native/build-tvossimulator.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env -S bash -eu
+
+if [ ! -e ../../../eng/submodules/sdl/CMakeLists.txt ]; then
+ git submodule update --init --recursive --depth 1 ../../../eng/submodules/sdl
+fi
+
+rm -rf build
+mkdir build
+cd build
+cmake ../../../../eng/submodules/sdl -DCMAKE_SYSTEM_NAME=tvOS -DCMAKE_OSX_SYSROOT=appletvsimulator "-DCMAKE_OSX_ARCHITECTURES=arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET=9.0 -DCMAKE_BUILD_TYPE=Release -DSDL_STATIC=ON
+cmake --build . --parallel
+cd ..
+mkdir -p runtimes/tvossimulator/native
+cp build/libSDL3.a runtimes/tvossimulator/native
diff --git a/sources/SDL/Native/build-win-arm64.cmd b/sources/SDL/Native/build-win-arm64.cmd
new file mode 100755
index 0000000000..568edc72dc
--- /dev/null
+++ b/sources/SDL/Native/build-win-arm64.cmd
@@ -0,0 +1,13 @@
+if not exist "../../../eng/submodules/sdl/CMakeLists.txt" (
+ git submodule update --init --recursive --depth 1 ..\..\..\eng\submodules\sdl
+)
+
+call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" arm64
+rd /s /q build
+mkdir build
+cd build
+cmake ..\..\..\..\eng\submodules\sdl -G Ninja -DCMAKE_BUILD_TYPE=Release
+cmake --build . --parallel
+cd ..
+mkdir runtimes\win-arm64\native
+copy build\SDL3.dll runtimes\win-arm64\native
diff --git a/sources/SDL/Native/build-win-x64.cmd b/sources/SDL/Native/build-win-x64.cmd
new file mode 100755
index 0000000000..692324d9be
--- /dev/null
+++ b/sources/SDL/Native/build-win-x64.cmd
@@ -0,0 +1,13 @@
+if not exist "../../../eng/submodules/sdl/CMakeLists.txt" (
+ git submodule update --init --recursive --depth 1 ..\..\..\eng\submodules\sdl
+)
+
+call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
+rd /s /q build
+mkdir build
+cd build
+cmake ..\..\..\..\eng\submodules\sdl -G Ninja -DCMAKE_BUILD_TYPE=Release
+cmake --build . --parallel
+cd ..
+mkdir runtimes\win-x64\native
+copy build\SDL3.dll runtimes\win-x64\native
diff --git a/sources/SDL/Native/runtimes/android-arm/native/libSDL3.so b/sources/SDL/Native/runtimes/android-arm/native/libSDL3.so
new file mode 100644
index 0000000000..cdf3cf8634
Binary files /dev/null and b/sources/SDL/Native/runtimes/android-arm/native/libSDL3.so differ
diff --git a/sources/SDL/Native/runtimes/android-arm64/native/libSDL3.so b/sources/SDL/Native/runtimes/android-arm64/native/libSDL3.so
new file mode 100644
index 0000000000..9f47629afd
Binary files /dev/null and b/sources/SDL/Native/runtimes/android-arm64/native/libSDL3.so differ
diff --git a/sources/SDL/Native/runtimes/android-x64/native/libSDL3.so b/sources/SDL/Native/runtimes/android-x64/native/libSDL3.so
new file mode 100644
index 0000000000..99f3b3ff3d
Binary files /dev/null and b/sources/SDL/Native/runtimes/android-x64/native/libSDL3.so differ
diff --git a/sources/SDL/Native/runtimes/android-x86/native/libSDL3.so b/sources/SDL/Native/runtimes/android-x86/native/libSDL3.so
new file mode 100644
index 0000000000..554284b093
Binary files /dev/null and b/sources/SDL/Native/runtimes/android-x86/native/libSDL3.so differ
diff --git a/sources/SDL/Native/runtimes/ios/native/libSDL3.a b/sources/SDL/Native/runtimes/ios/native/libSDL3.a
new file mode 100644
index 0000000000..2c93825e6c
Binary files /dev/null and b/sources/SDL/Native/runtimes/ios/native/libSDL3.a differ
diff --git a/sources/SDL/Native/runtimes/iossimulator/native/libSDL3.a b/sources/SDL/Native/runtimes/iossimulator/native/libSDL3.a
new file mode 100644
index 0000000000..ecdeb60db7
Binary files /dev/null and b/sources/SDL/Native/runtimes/iossimulator/native/libSDL3.a differ
diff --git a/sources/SDL/Native/runtimes/linux-arm/native/libSDL3.so b/sources/SDL/Native/runtimes/linux-arm/native/libSDL3.so
new file mode 100644
index 0000000000..7f3fc0a6da
Binary files /dev/null and b/sources/SDL/Native/runtimes/linux-arm/native/libSDL3.so differ
diff --git a/sources/SDL/Native/runtimes/linux-arm64/native/libSDL3.so b/sources/SDL/Native/runtimes/linux-arm64/native/libSDL3.so
new file mode 100644
index 0000000000..bea6391bff
Binary files /dev/null and b/sources/SDL/Native/runtimes/linux-arm64/native/libSDL3.so differ
diff --git a/sources/SDL/Native/runtimes/linux-x64/native/libSDL3.so b/sources/SDL/Native/runtimes/linux-x64/native/libSDL3.so
new file mode 100644
index 0000000000..2501d0cdc5
Binary files /dev/null and b/sources/SDL/Native/runtimes/linux-x64/native/libSDL3.so differ
diff --git a/sources/SDL/Native/runtimes/osx/native/libSDL3.dylib b/sources/SDL/Native/runtimes/osx/native/libSDL3.dylib
new file mode 100644
index 0000000000..561f1abb2b
Binary files /dev/null and b/sources/SDL/Native/runtimes/osx/native/libSDL3.dylib differ
diff --git a/sources/SDL/Native/runtimes/tvos/native/libSDL3.a b/sources/SDL/Native/runtimes/tvos/native/libSDL3.a
new file mode 100644
index 0000000000..46b2f4f9e8
Binary files /dev/null and b/sources/SDL/Native/runtimes/tvos/native/libSDL3.a differ
diff --git a/sources/SDL/Native/runtimes/tvossimulator/native/libSDL3.a b/sources/SDL/Native/runtimes/tvossimulator/native/libSDL3.a
new file mode 100644
index 0000000000..6a9d4f65bc
Binary files /dev/null and b/sources/SDL/Native/runtimes/tvossimulator/native/libSDL3.a differ
diff --git a/sources/SDL/Native/runtimes/win-arm64/native/SDL3.dll b/sources/SDL/Native/runtimes/win-arm64/native/SDL3.dll
new file mode 100644
index 0000000000..e65f0e40e5
Binary files /dev/null and b/sources/SDL/Native/runtimes/win-arm64/native/SDL3.dll differ
diff --git a/sources/SDL/Native/runtimes/win-x64/native/SDL3.dll b/sources/SDL/Native/runtimes/win-x64/native/SDL3.dll
new file mode 100644
index 0000000000..809595df2d
Binary files /dev/null and b/sources/SDL/Native/runtimes/win-x64/native/SDL3.dll differ
diff --git a/sources/SDL/Native/update.sh b/sources/SDL/Native/update.sh
new file mode 100755
index 0000000000..10c428e3f8
--- /dev/null
+++ b/sources/SDL/Native/update.sh
@@ -0,0 +1,23 @@
+#!/usr/bin/env -S bash -eu
+if [ ! -e ../../../eng/submodules/sdl/CMakeLists.txt ]; then
+ git submodule update --init --recursive --depth 1 ../../../eng/submodules/sdl
+fi
+verout="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")/version.txt"
+(
+ cd ../../../eng/submodules/sdl
+ git fetch --tags
+ IFS=' ' read -a latest <<< "$(git for-each-ref --sort=-committerdate --count=1 --contains=HEAD "refs/tags/release-3*")"
+ if [[ "${latest:-}" == "" && "$(git describe --tags --exact-match)" == "preview-"* ]]; then
+ IFS=' ' read -a latest <<< "$(git for-each-ref --sort=-committerdate --count=1 --contains=HEAD "refs/tags/preview-3*")"
+ fi
+ if [[ "${latest:-}" != "" ]]; then
+ git checkout "${latest[0]}"
+ ver="$(git describe --tags --exact-match)"
+ if [[ "$ver" == "preview-"* ]]; then
+ echo "${ver:8}-preview" > "$verout"
+ else
+ echo "${ver:8}" > "$verout"
+ fi
+ fi
+)
+git add ../../../eng/submodules/sdl version.txt
diff --git a/sources/SDL/Native/version.txt b/sources/SDL/Native/version.txt
new file mode 100644
index 0000000000..e5924268c2
--- /dev/null
+++ b/sources/SDL/Native/version.txt
@@ -0,0 +1,2 @@
+3.1.6-preview
+