From 6fa59d98ba054fed5dfd06e3fa12d96085006e7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Decroy=C3=A8re?= Date: Thu, 27 Aug 2026 12:16:37 +0200 Subject: [PATCH 1/6] Publish releases automatically --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 076ac1b..0827673 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -45,5 +45,5 @@ jobs: with: name: Release ${{ env.BUILD_DATE }} tag_name: v${{ env.BUILD_DATE }} - draft: true + draft: false files: ./release/**/*.zip From 0740bad69c83f252bd967fa76639e8fb36221f30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Decroy=C3=A8re?= Date: Thu, 27 Aug 2026 12:44:01 +0200 Subject: [PATCH 2/6] Carry Metal Shader Converter across releases --- .github/workflows/release.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0827673..09e5591 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,6 +3,12 @@ name: Release on: push: branches: [ main ] + paths-ignore: + - '.github/**' + - 'README.md' + +permissions: + contents: write jobs: build-dxc: @@ -39,6 +45,30 @@ jobs: uses: actions/download-artifact@v8 with: path: ./release + + - name: Carry Forward Metal Shader Converter + env: + GH_TOKEN: ${{ github.token }} + shell: bash + run: | + SOURCE_TAG="$(gh api "repos/${GITHUB_REPOSITORY}/releases/latest" --jq '.tag_name' 2>/dev/null || true)" + + if [[ -z "$SOURCE_TAG" ]]; then + echo "No previous release found; skipping Metal Shader Converter carry-forward." + exit 0 + fi + + mkdir -p ./release/metal-shader-converter + + if gh release download "$SOURCE_TAG" \ + --repo "$GITHUB_REPOSITORY" \ + --pattern '*_MetalShaderConverter_*' \ + --dir ./release/metal-shader-converter; then + echo "Carried Metal Shader Converter packages forward from $SOURCE_TAG." + else + echo "No Metal Shader Converter packages found on $SOURCE_TAG." + rm -rf ./release/metal-shader-converter + fi - name: Create Release uses: softprops/action-gh-release@v3 From 4d087b4262e3c9023c91c03f5bcf23c2e203a3e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Decroy=C3=A8re?= Date: Thu, 27 Aug 2026 12:44:59 +0200 Subject: [PATCH 3/6] Add Metal Shader Converter import workflow --- .../import-metal-shader-converter.yml | 304 ++++++++++++++++++ 1 file changed, 304 insertions(+) create mode 100644 .github/workflows/import-metal-shader-converter.yml diff --git a/.github/workflows/import-metal-shader-converter.yml b/.github/workflows/import-metal-shader-converter.yml new file mode 100644 index 0000000..b6a4e43 --- /dev/null +++ b/.github/workflows/import-metal-shader-converter.yml @@ -0,0 +1,304 @@ +name: Import Metal Shader Converter + +on: + workflow_dispatch: + inputs: + version: + description: 'Metal Shader Converter version used in package names (for example: 4.0 beta 2)' + required: true + type: string + macos_asset: + description: 'Exact macOS Apple package filename uploaded to the source release' + required: false + type: string + windows_asset: + description: 'Exact Windows Apple package filename uploaded to the source release' + required: false + type: string + target_release: + description: 'Release tag that receives the normalized packages; empty uses the latest published release' + required: false + type: string + +permissions: + contents: write + +jobs: + prepare: + runs-on: ubuntu-latest + outputs: + ready: ${{ steps.prepare.outputs.ready }} + target_release: ${{ steps.prepare.outputs.target_release }} + version_tag: ${{ steps.prepare.outputs.version_tag }} + steps: + - name: Prepare Import + id: prepare + env: + GH_TOKEN: ${{ github.token }} + SOURCE_TAG: metal-shader-converter-source + VERSION: ${{ inputs.version }} + MACOS_ASSET: ${{ inputs.macos_asset }} + WINDOWS_ASSET: ${{ inputs.windows_asset }} + REQUESTED_TARGET_RELEASE: ${{ inputs.target_release }} + shell: bash + run: | + set -euo pipefail + + VERSION_TAG="$(printf '%s' "$VERSION" | sed -E 's/[^A-Za-z0-9]+/_/g; s/^_+//; s/_+$//')" + echo "version_tag=$VERSION_TAG" >> "$GITHUB_OUTPUT" + + TARGET_RELEASE="$REQUESTED_TARGET_RELEASE" + if [[ -z "$TARGET_RELEASE" ]]; then + TARGET_RELEASE="$(gh api "repos/${GITHUB_REPOSITORY}/releases/latest" --jq '.tag_name')" + fi + echo "target_release=$TARGET_RELEASE" >> "$GITHUB_OUTPUT" + + if ! gh release view "$SOURCE_TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then + gh release create "$SOURCE_TAG" \ + --repo "$GITHUB_REPOSITORY" \ + --target main \ + --title 'Metal Shader Converter source inbox' \ + --notes 'Temporary private workflow inbox for Apple Metal Shader Converter installers. Upload the macOS and Windows downloads here, then rerun the Import Metal Shader Converter workflow.' \ + --draft + + echo "ready=false" >> "$GITHUB_OUTPUT" + echo "::notice title=Metal Shader Converter inbox created::Open the draft release '$SOURCE_TAG', upload the Apple macOS and Windows packages, then rerun this workflow with their exact filenames." + exit 0 + fi + + if [[ -z "$MACOS_ASSET" || -z "$WINDOWS_ASSET" ]]; then + echo "::error::The source inbox already exists. Provide macos_asset and windows_asset with the exact filenames uploaded to the draft release '$SOURCE_TAG'." + echo "Available assets:" + gh release view "$SOURCE_TAG" --repo "$GITHUB_REPOSITORY" --json assets --jq '.assets[].name' || true + exit 1 + fi + + ASSETS="$(gh release view "$SOURCE_TAG" --repo "$GITHUB_REPOSITORY" --json assets --jq '.assets[].name')" + + if ! grep -Fxq "$MACOS_ASSET" <<< "$ASSETS"; then + echo "::error::macOS source asset '$MACOS_ASSET' was not found in '$SOURCE_TAG'." + exit 1 + fi + + if ! grep -Fxq "$WINDOWS_ASSET" <<< "$ASSETS"; then + echo "::error::Windows source asset '$WINDOWS_ASSET' was not found in '$SOURCE_TAG'." + exit 1 + fi + + echo "ready=true" >> "$GITHUB_OUTPUT" + + package-macos: + needs: prepare + if: needs.prepare.outputs.ready == 'true' + runs-on: macos-latest + steps: + - name: Download Apple Package + env: + GH_TOKEN: ${{ github.token }} + SOURCE_TAG: metal-shader-converter-source + SOURCE_ASSET: ${{ inputs.macos_asset }} + shell: bash + run: | + set -euo pipefail + mkdir -p source + gh release download "$SOURCE_TAG" \ + --repo "$GITHUB_REPOSITORY" \ + --pattern "$SOURCE_ASSET" \ + --dir source + + - name: Extract Apple Package + env: + SOURCE_ASSET: ${{ inputs.macos_asset }} + shell: bash + run: | + set -euo pipefail + + SOURCE_FILE="$PWD/source/$SOURCE_ASSET" + mkdir -p work/raw work/expanded + + case "${SOURCE_FILE,,}" in + *.zip) + ditto -x -k "$SOURCE_FILE" work/raw + ;; + *.pkg) + pkgutil --expand-full "$SOURCE_FILE" work/expanded/source-package + ;; + *.dmg) + mkdir -p work/mount + hdiutil attach "$SOURCE_FILE" -readonly -nobrowse -mountpoint "$PWD/work/mount" + cp -R work/mount/. work/raw/ + hdiutil detach "$PWD/work/mount" + ;; + *) + cp "$SOURCE_FILE" work/raw/ + ;; + esac + + index=0 + while IFS= read -r -d '' package; do + index=$((index + 1)) + pkgutil --expand-full "$package" "work/expanded/package-$index" + done < <(find work/raw -type f -name '*.pkg' -print0) + + - name: Normalize macOS Package + env: + VERSION_TAG: ${{ needs.prepare.outputs.version_tag }} + shell: bash + run: | + set -euo pipefail + + LIBRARY="$(find work -type f -name 'libmetalirconverter.dylib' -print -quit)" + HEADER="$(find work -type f -path '*/metal_irconverter/metal_irconverter.h' -print -quit)" + + if [[ -z "$LIBRARY" || -z "$HEADER" ]]; then + echo "Metal Shader Converter library/header not found after extracting the Apple package." + echo "Files containing metalirconverter:" + find work -type f | grep -i 'metal.*irconverter' || true + exit 1 + fi + + mkdir -p publish/include publish/lib + cp "$LIBRARY" publish/lib/ + + INCLUDE_ROOT="${HEADER%/metal_irconverter/metal_irconverter.h}" + while IFS= read -r -d '' include_dir; do + cp -R "$include_dir" publish/include/ + done < <(find "$INCLUDE_ROOT" -maxdepth 1 -type d -name 'metal_irconverter*' -print0) + + lipo -archs publish/lib/libmetalirconverter.dylib | tr ' ' '\n' | grep -Fxq arm64 + + PACKAGE="macos_MetalShaderConverter_${VERSION_TAG}_arm64.zip" + (cd publish && zip -r "../$PACKAGE" include lib) + echo "PACKAGE=$PACKAGE" >> "$GITHUB_ENV" + + - name: Upload macOS Package + uses: actions/upload-artifact@v7 + with: + name: metal-shader-converter-macos + path: ${{ env.PACKAGE }} + compression-level: 0 + + package-windows: + needs: prepare + if: needs.prepare.outputs.ready == 'true' + runs-on: windows-latest + steps: + - name: Download Apple Package + env: + GH_TOKEN: ${{ github.token }} + SOURCE_TAG: metal-shader-converter-source + SOURCE_ASSET: ${{ inputs.windows_asset }} + shell: pwsh + run: | + New-Item -ItemType Directory -Force source | Out-Null + gh release download $env:SOURCE_TAG ` + --repo $env:GITHUB_REPOSITORY ` + --pattern $env:SOURCE_ASSET ` + --dir source + + - name: Extract Apple Package + env: + SOURCE_ASSET: ${{ inputs.windows_asset }} + shell: pwsh + run: | + $ErrorActionPreference = 'Stop' + + $sourceFile = Join-Path $PWD "source/$env:SOURCE_ASSET" + $raw = Join-Path $PWD 'work/raw' + New-Item -ItemType Directory -Force $raw | Out-Null + + $extension = [System.IO.Path]::GetExtension($sourceFile).ToLowerInvariant() + + if ($extension -eq '.zip') { + Expand-Archive -Path $sourceFile -DestinationPath $raw -Force + } + elseif ($extension -eq '.msi') { + $process = Start-Process msiexec.exe -Wait -PassThru -ArgumentList @('/a', "`"$sourceFile`"", '/qn', "TARGETDIR=`"$raw`"") + if ($process.ExitCode -ne 0) { throw "msiexec extraction failed with exit code $($process.ExitCode)" } + } + else { + & 7z x $sourceFile "-o$raw" -y + if ($LASTEXITCODE -ne 0) { + throw '7-Zip could not extract the Apple Windows package. Re-upload it as a ZIP containing the installer contents and rerun the workflow.' + } + } + + $nestedMsi = Get-ChildItem $raw -Recurse -File -Filter '*.msi' + $index = 0 + foreach ($msi in $nestedMsi) { + $index++ + $destination = Join-Path $PWD "work/msi-$index" + New-Item -ItemType Directory -Force $destination | Out-Null + $process = Start-Process msiexec.exe -Wait -PassThru -ArgumentList @('/a', "`"$($msi.FullName)`"", '/qn', "TARGETDIR=`"$destination`"") + if ($process.ExitCode -ne 0) { throw "Nested MSI extraction failed with exit code $($process.ExitCode)" } + } + + - name: Normalize Windows Package + env: + VERSION_TAG: ${{ needs.prepare.outputs.version_tag }} + shell: pwsh + run: | + $ErrorActionPreference = 'Stop' + + $library = Get-ChildItem work -Recurse -File -Filter 'metalirconverter.lib' | Select-Object -First 1 + $dll = Get-ChildItem work -Recurse -File -Filter 'metalirconverter.dll' | Select-Object -First 1 + $header = Get-ChildItem work -Recurse -File -Filter 'metal_irconverter.h' | Where-Object { $_.Directory.Name -eq 'metal_irconverter' } | Select-Object -First 1 + + if (-not $library -or -not $dll -or -not $header) { + Write-Host 'Metal Shader Converter library/header not found after extracting the Apple package.' + Get-ChildItem work -Recurse -File | Where-Object { $_.Name -match 'metal.*irconverter' } | Select-Object -ExpandProperty FullName + throw 'Unable to normalize Metal Shader Converter for Windows.' + } + + New-Item -ItemType Directory -Force publish/include, publish/lib | Out-Null + Copy-Item $library.FullName publish/lib/ + Copy-Item $dll.FullName publish/lib/ + + $includeRoot = Split-Path (Split-Path $header.FullName -Parent) -Parent + Get-ChildItem $includeRoot -Directory -Filter 'metal_irconverter*' | ForEach-Object { + Copy-Item $_.FullName publish/include/ -Recurse + } + + $package = "windows_MetalShaderConverter_$env:VERSION_TAG`_x64.zip" + Compress-Archive -Path publish/* -DestinationPath $package -Force + "PACKAGE=$package" | Out-File -FilePath $env:GITHUB_ENV -Append + + - name: Upload Windows Package + uses: actions/upload-artifact@v7 + with: + name: metal-shader-converter-windows + path: ${{ env.PACKAGE }} + compression-level: 0 + + publish: + needs: [prepare, package-macos, package-windows] + if: needs.prepare.outputs.ready == 'true' + runs-on: ubuntu-latest + steps: + - name: Download Normalized Packages + uses: actions/download-artifact@v8 + with: + pattern: metal-shader-converter-* + path: packages + merge-multiple: true + + - name: Upload Packages to Release + env: + GH_TOKEN: ${{ github.token }} + TARGET_RELEASE: ${{ needs.prepare.outputs.target_release }} + SOURCE_TAG: metal-shader-converter-source + MACOS_ASSET: ${{ inputs.macos_asset }} + WINDOWS_ASSET: ${{ inputs.windows_asset }} + shell: bash + run: | + set -euo pipefail + + ls -lh packages + gh release upload "$TARGET_RELEASE" packages/*.zip \ + --repo "$GITHUB_REPOSITORY" \ + --clobber + + gh release delete-asset "$SOURCE_TAG" "$MACOS_ASSET" --repo "$GITHUB_REPOSITORY" --yes || true + gh release delete-asset "$SOURCE_TAG" "$WINDOWS_ASSET" --repo "$GITHUB_REPOSITORY" --yes || true + + echo "Metal Shader Converter packages uploaded to $TARGET_RELEASE." From 9f3f36c96719314b3420c704d4f102847701a1ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Decroy=C3=A8re?= Date: Thu, 27 Aug 2026 12:45:27 +0200 Subject: [PATCH 4/6] Document Metal Shader Converter import flow --- README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 026954e..a3671ca 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,20 @@ It currently provides: - DirectXShaderCompiler (Windows x64, Linux x64, macOS arm64) - SPIRV-Cross (Windows x64, Linux x64, macOS arm64) +- Apple Metal Shader Converter (Windows x64, macOS arm64) DirectXShaderCompiler is built from source on every platform because upstream DXC still does not publish macOS binaries. Building all platforms from the same source revision also keeps the package layout and compiler revision consistent. +Metal Shader Converter is distributed by Apple behind the Apple Developer downloads login, so the source installers cannot be fetched unattended by GitHub Actions. The repository keeps the remaining work automated: + +1. Run the **Import Metal Shader Converter** workflow once. If needed, it creates a draft release named `metal-shader-converter-source` that acts as a temporary inbox. +2. Download the macOS and Windows Metal Shader Converter packages from Apple and upload both files to that draft release. +3. Run **Import Metal Shader Converter** again with the converter version and the exact two uploaded filenames. +4. The workflow extracts the Apple installers, normalizes the `include/` and `lib/` package layout, validates the macOS arm64 library, and uploads the resulting packages to the latest published release (or a release tag supplied manually). +5. The temporary Apple installer assets are removed from the draft inbox after a successful import. + +Published releases automatically carry the latest Metal Shader Converter packages forward, so a DXC or SPIRV-Cross update does not require another Apple download unless Metal Shader Converter itself changes. + **Important** -These compiled binaries are not officially supported by Microsoft or Khronos. +The DXC and SPIRV-Cross binaries built by this repository are not officially supported by Microsoft or Khronos. Metal Shader Converter is Apple software redistributed here for Elemental's build tooling; its use remains subject to Apple's applicable terms. From 92bf454630ece5b93755e7484f61a85928bb2939 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Decroy=C3=A8re?= Date: Thu, 27 Aug 2026 12:46:12 +0200 Subject: [PATCH 5/6] Fix macOS importer compatibility --- .github/workflows/import-metal-shader-converter.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/import-metal-shader-converter.yml b/.github/workflows/import-metal-shader-converter.yml index b6a4e43..e388558 100644 --- a/.github/workflows/import-metal-shader-converter.yml +++ b/.github/workflows/import-metal-shader-converter.yml @@ -116,14 +116,14 @@ jobs: SOURCE_FILE="$PWD/source/$SOURCE_ASSET" mkdir -p work/raw work/expanded - case "${SOURCE_FILE,,}" in - *.zip) + case "$SOURCE_FILE" in + *.zip|*.ZIP) ditto -x -k "$SOURCE_FILE" work/raw ;; - *.pkg) + *.pkg|*.PKG) pkgutil --expand-full "$SOURCE_FILE" work/expanded/source-package ;; - *.dmg) + *.dmg|*.DMG) mkdir -p work/mount hdiutil attach "$SOURCE_FILE" -readonly -nobrowse -mountpoint "$PWD/work/mount" cp -R work/mount/. work/raw/ @@ -138,7 +138,7 @@ jobs: while IFS= read -r -d '' package; do index=$((index + 1)) pkgutil --expand-full "$package" "work/expanded/package-$index" - done < <(find work/raw -type f -name '*.pkg' -print0) + done < <(find work/raw -type f \( -name '*.pkg' -o -name '*.PKG' \) -print0) - name: Normalize macOS Package env: From 08f5beea012a39fbb6c0407bf7ef317fd5f6d637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Decroy=C3=A8re?= Date: Thu, 27 Aug 2026 12:47:28 +0200 Subject: [PATCH 6/6] Limit DXC CI to compiler changes --- .github/workflows/build-dxc-ci.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build-dxc-ci.yml b/.github/workflows/build-dxc-ci.yml index 8703a8d..a10116f 100644 --- a/.github/workflows/build-dxc-ci.yml +++ b/.github/workflows/build-dxc-ci.yml @@ -2,6 +2,11 @@ name: Build DXC CI on: pull_request: + paths: + - 'src/DirectXShaderCompiler' + - 'src/DirectXShaderCompiler/**' + - '.github/workflows/build-dxc.yml' + - '.github/workflows/build-dxc-ci.yml' workflow_dispatch: jobs: