# syntax=docker/dockerfile:1.6 # # Pre-built CI test image. Extends the hexpm/elixir image with: # * build-essential + git + curl + ca-certificates + cdo # * hex + rebar # * Precompiled EXLA NIF cached at ~/.cache/xla/ # # When mix test runs with this image, EXLA's cached_make finds the # precompiled libexla.so and skips the OOM-prone g++ C++ compilation # entirely. Rebuild this image whenever mix.exs changes elixir/exla/xla # versions or c_src/ files change (the cache key auto-invalidates). # # Built by .forgejo/workflows/build-ci-image.yaml. ARG ELIXIR_IMAGE="docker.io/hexpm/elixir:1.20.1-erlang-29.0.2-debian-trixie-20260518-slim" FROM ${ELIXIR_IMAGE} AS builder # Install build tools and runtime test deps (cdo is needed by tests). RUN export DEBIAN_FRONTEND=noninteractive && \ apt-get update -qq && \ apt-get install -y -qq git curl ca-certificates build-essential cdo && \ rm -rf /var/lib/apt/lists/* # Install hex + rebar RUN mix local.hex --force && mix local.rebar --force # Precompile EXLA to populate ~/.cache/xla/ with both the downloaded # XLA archive and the compiled libexla.so. We only need mix.exs + # mix.lock + vendor + minimal config — no full project checkout. WORKDIR /tmp/exla_warm # Copy only what's needed for deps.get + deps.compile exla COPY mix.exs mix.lock /tmp/exla_warm/ COPY vendor /tmp/exla_warm/vendor # Minimal config — nx needs :default_backend to exist RUN mkdir -p /tmp/exla_warm/config && \ printf 'import Config\nconfig :nx, :default_backend, EXLA.Backend\n' > /tmp/exla_warm/config/config.exs # Fetch deps and compile EXLA. The cached_make compiler downloads the XLA # archive, extracts it, compiles the C++ NIF, and caches libexla.so at # ~/.cache/xla/exla/{cache_key}/libexla.so. This layer is cached by # Docker until mix.exs/mix.lock/vendor change. RUN mix deps.get && mix deps.compile exla # Clean up the temp project — the cache in ~/.cache/xla/ persists in # the image and is what matters. RUN rm -rf /tmp/exla_warm FROM ${ELIXIR_IMAGE} AS final # Install runtime test deps RUN export DEBIAN_FRONTEND=noninteractive && \ apt-get update -qq && \ apt-get install -y -qq git curl ca-certificates build-essential cdo && \ rm -rf /var/lib/apt/lists/* # Install hex + rebar RUN mix local.hex --force && mix local.rebar --force # Copy the precompiled EXLA cache from the builder stage. This is the # ~/.cache/xla/ directory containing the XLA archive download and the # compiled libexla.so keyed by exact Elixir/ERTS/exla/xla/c_src versions. COPY --from=builder /root/.cache/xla /root/.cache/xla WORKDIR /app