diff --git a/.github/actions/build-gha-docker-image/action.yaml b/.github/actions/build-gha-docker-image/action.yaml
new file mode 100644
index 0000000..357d975
--- /dev/null
+++ b/.github/actions/build-gha-docker-image/action.yaml
@@ -0,0 +1,58 @@
+# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions
+# https://docs.github.com/en/actions/use-cases-and-examples/publishing-packages/publishing-docker-images#publishing-images-to-github-packages
+name: 'Build docker image for use in GitHub Actions'
+description: 'Builds a docker image for use in GitHub Actions for a given compiler and a given compiler version.'
+
+inputs:
+  compiler-name:
+    description: 'The Fortran compiler to install.'
+    required: true
+  compiler-version:
+    description: 'The compiler version to install.'
+    required: true
+  docker-registry-name:
+    description: 'The docker registry to publish to.'
+    default: 'ghcr.io'
+  docker-registry-username:
+    description: 'The username to login to the docker registry with.'
+    required: true
+  docker-registry-password:
+    description: 'The password to login to the docker registry with.'
+    required: true
+  image-name:
+    description: 'The name of the docker image.'
+    required: true
+
+runs:
+  using: 'composite'
+  steps:
+    - name: "Log in to the container registry"
+      uses: docker/login-action@v3
+      with:
+        registry: ${{ inputs.docker-registry-name }}
+        username: ${{ inputs.docker-registry-username }}
+        password: ${{ inputs.docker-registry-password }}
+
+    - name: "Extract metadata (tags, labels) for docker"
+      id: meta
+      uses: docker/metadata-action@v5
+      with:
+        images: ${{ inputs.docker-registry-name }}/${{ inputs.image-name }}
+        tags: |
+          type=raw,value=linux-${{ inputs.compiler-name }}-${{ inputs.compiler-version }}
+          type=sha
+          type=ref,enable=true,priority=600,prefix=,suffix=,event=branch
+          type=ref,enable=true,priority=600,prefix=,suffix=,event=tag
+          type=ref,enable=true,priority=600,prefix=pr-,suffix=,event=pr
+
+    - name: "Build and push docker image"
+      id: push
+      uses: docker/build-push-action@v6
+      with:
+        context: docker/github-actions/
+        build-args: |
+          COMPILER=${{ inputs.compiler-name }}
+          VERSION=${{ inputs.compiler-version }}
+        push: true
+        tags: ${{ steps.meta.outputs.tags }}
+        labels: ${{ steps.meta.outputs.labels }}
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 4648aa1..e3a1bf1 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -54,162 +54,193 @@ jobs:
       # debugging
       - name: Show matrix
         run: echo "${{ toJSON(fromJSON(steps.matrix.outputs.matrix)) }}"
-    
-  test:
-    name: Test
-    needs: options
-    runs-on: ${{ matrix.os }}
-    continue-on-error: ${{ needs.options.outputs.mode == 'report' }}
-    strategy:
-      fail-fast: false
-      matrix: ${{ fromJSON(needs.options.outputs.matrix) }}
-    steps:
-      - name: Checkout repository
-        uses: actions/checkout@v4
-
-      - name: Setup Fortran
-        id: setup-fortran
-        continue-on-error: ${{ needs.options.outputs.mode == 'report' }}
-        uses: ./
-        with:
-          compiler: ${{ matrix.toolchain.compiler }}
-          version: ${{ matrix.toolchain.version }}
-
-      # - name: Debug with tmate
-      #   uses: mxschmitt/action-tmate@v3
-
-      - name: Test Fortran compiler
-        if: steps.setup-fortran.outcome == 'success'
-        uses: ./.github/actions/test-fc
-        with:
-          compiler: ${{ matrix.toolchain.compiler }}
-          version: ${{ matrix.toolchain.version }}
-      
-      - name: Test C compiler
-        continue-on-error: true
-        if: needs.options.outputs.mode == 'report' && steps.setup-fortran.outcome == 'success'
-        uses: ./.github/actions/test-cc
-        with:
-          compiler: ${{ matrix.toolchain.compiler }}
-          version: ${{ matrix.toolchain.version }}
-      
-      - name: Test C++ compiler
-        continue-on-error: true
-        if: needs.options.outputs.mode == 'report' && steps.setup-fortran.outcome == 'success'
-        uses: ./.github/actions/test-cxx
-        with:
-          compiler: ${{ matrix.toolchain.compiler }}
-          version: ${{ matrix.toolchain.version }}
 
-      - name: Create compatibility report
-        if: needs.options.outputs.mode == 'report'
-        shell: bash
-        run: |
-          mkdir -p compat
-          support=$([ "${{ steps.setup-fortran.outcome }}" == "success" ] && echo "✓" || echo "")
-          prefix="${{ matrix.os }},${{ matrix.toolchain.compiler }},${{ matrix.toolchain.version }}"
-          report="compat/${prefix//,/_}.csv"
-          echo "$prefix,$support" >> "$report"
-          cat "$report"
 
-      - name: Upload compatibility report
-        if: needs.options.outputs.mode == 'report'
-        uses: actions/upload-artifact@v4
-        with:
-          name: compat-${{ matrix.os }}-${{ matrix.toolchain.compiler }}-${{ matrix.toolchain.version }}
-          path: compat/*.csv
-  
-  compat:
-    name: Report compatibility
-    needs: 
-      - options
-      - test
-    if: needs.options.outputs.mode == 'report'
+  build-and-push-docker-image:
+    name: 'Build and push docker image'
     runs-on: ubuntu-latest
+    timeout-minutes: 12
     permissions:
-      contents: write
-      pull-requests: write
+      contents: read
+      packages: write
+      attestations: write
+      id-token: write
+    strategy:
+      fail-fast: false
+      matrix:
+        include:
+          - compiler-name: 'gcc'
+            compiler-version: '13'
     steps:
-
-      - name: Checkout repository
+      - name: "Checkout repository"
         uses: actions/checkout@v4
 
-      - name: Setup Python
-        uses: actions/setup-python@v4
-        with:
-          python-version: 3.9
-
-      - name: Install packages
-        run: pip install -r requirements.txt
-
-      - name: Download reports
-        uses: actions/download-artifact@v4
-        with:
-          pattern: compat-*
-          path: compat
-          merge-multiple: true
-
-      - name: Concatenate reports
-        run: |
-          echo "runner,compiler,version,support" > .github/compat/long_compat.csv
-          cat compat/*.csv >> .github/compat/long_compat.csv
-
-      - name: Make wide reports
-        working-directory: .github/compat
-        run: |
-          python wide_compat_reports.py "long_compat.csv" "compat.csv"
-          cat compat.md
-
-      - name: Upload artifacts
-        uses: actions/upload-artifact@v4
+      - name: 'Build and push docker image'
+        uses: ./.github/actions/build-gha-docker-image
         with:
-          name: compat
-          path: |
-            .github/compat/long_compat.csv
-            .github/compat/compat.csv
-            .github/compat/compat.md
-
-      - name: Check for changes
-        working-directory: .github/compat
-        id: diff
-        run: |
-          if ! [ -f compat.csv ]; then
-            echo "diff=false" >> $GITHUB_OUTPUT
-            exit 0
-          fi
-
-          diff=$(git diff compat.csv)
-          if [[ $diff == "" ]]; then
-            echo "No changes found"
-            echo "diff=false" >> $GITHUB_OUTPUT
-          else
-            echo "Changes found:"
-            echo "$diff"
-            echo "diff=true" >> $GITHUB_OUTPUT
-          fi
-
-      - name: Update README
-        if: ${{ steps.diff.outputs.diff == 'true' }}
-        run: python .github/compat/update_compat_table.py ".github/compat/compat.md" "README.md"
-
-      - name: Print README diff
-        if: ${{ steps.diff.outputs.diff == 'true' }}
-        run: git diff README.md
+          compiler-name: ${{ matrix.compiler-name }}
+          compiler-version: ${{ matrix.compiler-version }}
+          docker-registry-name: 'ghcr.io'
+          docker-registry-username: ${{ github.actor }}
+          docker-registry-password: ${{ secrets.GITHUB_TOKEN }}
+          image-name: ${{ github.repository }}
 
-      - name: Create pull request
-        if: ${{ steps.diff.outputs.diff == 'true' }}
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-        run: |
-          git config user.name "github-actions[bot]"
-          git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
-          
-          now=$(date +'%Y-%m-%dT%H-%M-%S')
-          updated_branch="compat_$now"
-          default_branch="${{ github.event.repository.default_branch }}"
-          
-          git switch -c "$updated_branch"
-          git add .github/compat/*compat.csv README.md
-          git commit -m "Update compatibility matrix"
-          git push -u origin "$updated_branch"
-          gh pr create -B "$default_branch" -H "$updated_branch" --title "Update compatibility matrix" --body-file .github/compat/compat.md
+    
+#  test:
+#    name: Test
+#    needs: options
+#    runs-on: ${{ matrix.os }}
+#    continue-on-error: ${{ needs.options.outputs.mode == 'report' }}
+#    strategy:
+#      fail-fast: false
+#      matrix: ${{ fromJSON(needs.options.outputs.matrix) }}
+#    steps:
+#      - name: Checkout repository
+#        uses: actions/checkout@v4
+#
+#      - name: Setup Fortran
+#        id: setup-fortran
+#        continue-on-error: ${{ needs.options.outputs.mode == 'report' }}
+#        uses: ./
+#        with:
+#          compiler: ${{ matrix.toolchain.compiler }}
+#          version: ${{ matrix.toolchain.version }}
+#
+#      # - name: Debug with tmate
+#      #   uses: mxschmitt/action-tmate@v3
+#
+#      - name: Test Fortran compiler
+#        if: steps.setup-fortran.outcome == 'success'
+#        uses: ./.github/actions/test-fc
+#        with:
+#          compiler: ${{ matrix.toolchain.compiler }}
+#          version: ${{ matrix.toolchain.version }}
+#      
+#      - name: Test C compiler
+#        continue-on-error: true
+#        if: needs.options.outputs.mode == 'report' && steps.setup-fortran.outcome == 'success'
+#        uses: ./.github/actions/test-cc
+#        with:
+#          compiler: ${{ matrix.toolchain.compiler }}
+#          version: ${{ matrix.toolchain.version }}
+#      
+#      - name: Test C++ compiler
+#        continue-on-error: true
+#        if: needs.options.outputs.mode == 'report' && steps.setup-fortran.outcome == 'success'
+#        uses: ./.github/actions/test-cxx
+#        with:
+#          compiler: ${{ matrix.toolchain.compiler }}
+#          version: ${{ matrix.toolchain.version }}
+#
+#      - name: Create compatibility report
+#        if: needs.options.outputs.mode == 'report'
+#        shell: bash
+#        run: |
+#          mkdir -p compat
+#          support=$([ "${{ steps.setup-fortran.outcome }}" == "success" ] && echo "✓" || echo "")
+#          prefix="${{ matrix.os }},${{ matrix.toolchain.compiler }},${{ matrix.toolchain.version }}"
+#          report="compat/${prefix//,/_}.csv"
+#          echo "$prefix,$support" >> "$report"
+#          cat "$report"
+#
+#      - name: Upload compatibility report
+#        if: needs.options.outputs.mode == 'report'
+#        uses: actions/upload-artifact@v4
+#        with:
+#          name: compat-${{ matrix.os }}-${{ matrix.toolchain.compiler }}-${{ matrix.toolchain.version }}
+#          path: compat/*.csv
+#  
+#  compat:
+#    name: Report compatibility
+#    needs: 
+#      - options
+#      - test
+#    if: needs.options.outputs.mode == 'report'
+#    runs-on: ubuntu-latest
+#    permissions:
+#      contents: write
+#      pull-requests: write
+#    steps:
+#
+#      - name: Checkout repository
+#        uses: actions/checkout@v4
+#
+#      - name: Setup Python
+#        uses: actions/setup-python@v4
+#        with:
+#          python-version: 3.9
+#
+#      - name: Install packages
+#        run: pip install -r requirements.txt
+#
+#      - name: Download reports
+#        uses: actions/download-artifact@v4
+#        with:
+#          pattern: compat-*
+#          path: compat
+#          merge-multiple: true
+#
+#      - name: Concatenate reports
+#        run: |
+#          echo "runner,compiler,version,support" > .github/compat/long_compat.csv
+#          cat compat/*.csv >> .github/compat/long_compat.csv
+#
+#      - name: Make wide reports
+#        working-directory: .github/compat
+#        run: |
+#          python wide_compat_reports.py "long_compat.csv" "compat.csv"
+#          cat compat.md
+#
+#      - name: Upload artifacts
+#        uses: actions/upload-artifact@v4
+#        with:
+#          name: compat
+#          path: |
+#            .github/compat/long_compat.csv
+#            .github/compat/compat.csv
+#            .github/compat/compat.md
+#
+#      - name: Check for changes
+#        working-directory: .github/compat
+#        id: diff
+#        run: |
+#          if ! [ -f compat.csv ]; then
+#            echo "diff=false" >> $GITHUB_OUTPUT
+#            exit 0
+#          fi
+#
+#          diff=$(git diff compat.csv)
+#          if [[ $diff == "" ]]; then
+#            echo "No changes found"
+#            echo "diff=false" >> $GITHUB_OUTPUT
+#          else
+#            echo "Changes found:"
+#            echo "$diff"
+#            echo "diff=true" >> $GITHUB_OUTPUT
+#          fi
+#
+#      - name: Update README
+#        if: ${{ steps.diff.outputs.diff == 'true' }}
+#        run: python .github/compat/update_compat_table.py ".github/compat/compat.md" "README.md"
+#
+#      - name: Print README diff
+#        if: ${{ steps.diff.outputs.diff == 'true' }}
+#        run: git diff README.md
+#
+#      - name: Create pull request
+#        if: ${{ steps.diff.outputs.diff == 'true' }}
+#        env:
+#          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+#        run: |
+#          git config user.name "github-actions[bot]"
+#          git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
+#          
+#          now=$(date +'%Y-%m-%dT%H-%M-%S')
+#          updated_branch="compat_$now"
+#          default_branch="${{ github.event.repository.default_branch }}"
+#          
+#          git switch -c "$updated_branch"
+#          git add .github/compat/*compat.csv README.md
+#          git commit -m "Update compatibility matrix"
+#          git push -u origin "$updated_branch"
+#          gh pr create -B "$default_branch" -H "$updated_branch" --title "Update compatibility matrix" --body-file .github/compat/compat.md
diff --git a/docker/github-actions/Dockerfile b/docker/github-actions/Dockerfile
new file mode 100644
index 0000000..4de2fa3
--- /dev/null
+++ b/docker/github-actions/Dockerfile
@@ -0,0 +1,19 @@
+FROM ubuntu:24.04
+
+ARG COMPILER
+ARG VERSION
+
+# Update dependencies.
+RUN apt update && apt -y upgrade
+
+# Create a directory for the GITHUB_* files
+RUN mkdir -p /etc/github-actions
+
+# Copy in the script for use when running this container, to populate the runtime environment.
+COPY --chmod=755 ./update-job-environment.sh /etc/github-actions/update-job-environment.sh
+
+# Install the specified Fortran compiler.
+COPY --follow-symlinks ./main.sh /tmp/main.sh
+COPY --follow-symlinks ./setup-fortran.sh /tmp/setup-fortran.sh
+COPY --chmod=755 ./run-setup-fortran.sh /tmp/run-setup-fortran.sh
+RUN env GITHUB_ENV=/etc/github-actions/ENV GITHUB_PATH=/etc/github-actions/PATH /tmp/run-setup-fortran.sh
diff --git a/docker/github-actions/main.sh b/docker/github-actions/main.sh
new file mode 120000
index 0000000..f7a862b
--- /dev/null
+++ b/docker/github-actions/main.sh
@@ -0,0 +1 @@
+../../main.sh
\ No newline at end of file
diff --git a/docker/github-actions/run-setup-fortran.sh b/docker/github-actions/run-setup-fortran.sh
new file mode 100755
index 0000000..4e035ac
--- /dev/null
+++ b/docker/github-actions/run-setup-fortran.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+set -e
+
+# Install necessary dependencies.
+apt install -y make software-properties-common sudo
+
+# Run setup-fortran.
+cd /tmp
+source main.sh
+cd -
+
+# Add the value of exported compiler environment variables to the set of environment variables to persist.
+for v in FC CC CXX; do
+  if [ ! -z "${!v}" ]; then
+    echo "${v}=${!v}" >> ${GITHUB_ENV}
+  fi
+done
diff --git a/docker/github-actions/setup-fortran.sh b/docker/github-actions/setup-fortran.sh
new file mode 120000
index 0000000..2765f1f
--- /dev/null
+++ b/docker/github-actions/setup-fortran.sh
@@ -0,0 +1 @@
+../../setup-fortran.sh
\ No newline at end of file
diff --git a/docker/github-actions/update-job-environment.sh b/docker/github-actions/update-job-environment.sh
new file mode 100755
index 0000000..63932b7
--- /dev/null
+++ b/docker/github-actions/update-job-environment.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+# This script is to be run within a GitHub Action job step, and is used to update the runtime
+# environment variables based on environment variables setup during build time.
+set -uex
+
+D=/etc/github-actions
+
+for v in ENV PATH; do
+  if [ -r ${D}/${v} ]; then
+    env_var=GITHUB_${v}
+    if env | grep -q "^${env_var}="; then
+      cat ${D}/${v} >> ${!env_var}
+    fi
+  fi
+done