GitHub Action

Compile on every push, fail the job on errors, and get each error marked on its source line in the PR:

- uses: actions/checkout@v6
- uses: psyb0t/docker-mql-compiler@master
  with:
    paths: |
      MQL5/Experts
      MQL4/Indicators/Bands.mq4

It runs on ubuntu-latest. That’s Ubuntu 26.04 with Linux 7.0 now, where Docker’s default seccomp filter refuses the userfaultfd call Wine makes at startup and Wine dies with wine: socket : Function not implemented. The action passes its own seccomp/wine.json (Docker’s default profile plus userfaultfd), so you don’t have to do a damn thing.

The inputs and outputs are declared in action.yml.

Input Default What it does
paths . Files or directories to compile, one per line
include none Extra -I directories, one per line
werror false Fail on warnings
image the release matching the action’s ref Image to run; a branch ref like @master runs :latest
cache true Keep the 2 GB toolchain in the Actions cache, so only the first run pays the 90-second install
cache-dir under RUNNER_TEMP Where the toolchain lives on the runner

Outputs: results (the path of the JSON Lines file), total, compiled, failed. The job summary gets a table of every file. Paths in annotations are relative to the repository root, so run it from there (the default).

Running the image by hand

The command is just a thin docker run. Doing it yourself:

# run from the directory that holds MQL5/
docker run --rm --init \
  --user "$(id -u):$(id -g)" \
  --security-opt seccomp=seccomp/wine.json \
  -v "$PWD":/src \
  -v mql-compiler-cache:/cache \
  psyb0t/mql-compiler:latest MQL5/Experts

Mount your sources at /src (the image’s working directory, so relative paths start there) and keep /cache on a volume. Skip the volume and every single run reinstalls the whole toolchain, which gets old fast. The image only sees what you mount, so mount the MQL4/MQL5 directory or its parent, never just Experts, or your Include stays outside. Add -e MQL_COMPILER_MT4_URL=... and -e MQL_COMPILER_MT5_URL=... for other installers. An -I directory has to be mounted too. --init lets Ctrl-C reach the compiler, which --watch needs. --security-opt seccomp=... points at a copy of this repo’s seccomp/wine.json; on Linux older than 7.0 you can leave it out. The command does the same thing with each directory mounted at its own host path and -w "$PWD", which is why its output shows your real paths.