diff --git a/Makefile b/Makefile
index a07d7bdd9e2f1d89fcd46dd41022036045906d94..cb89c23fa8cf11c23a2492380fcea74bfb1de94e 100644
--- a/Makefile
+++ b/Makefile
@@ -9,3 +9,6 @@ dockerfiles: dockerfiles.dhall
 	mkdir -p dockerfiles
 	${DHALL} to-directory-tree --file=$< --output=$@
 
+clean:
+	rm gitlab-pipeline.dhall || echo "Skipping"
+	rm -r dockerfiles || echo "Skipping"
diff --git a/components/FEX.dhall b/components/FEX.dhall
new file mode 100644
index 0000000000000000000000000000000000000000..6d392dc410079efb1f01a8e70369d0153e22e9c3
--- /dev/null
+++ b/components/FEX.dhall
@@ -0,0 +1,35 @@
+let
+  CF = ../deps/Containerfile.dhall
+
+let
+  Llvm = ./Llvm.dhall
+
+let
+  BinariesSpec: Type =
+      { version : Text
+      }
+
+let
+  installArm64ECToWine: Text -> BinariesSpec -> CF.Type =
+    \(wineDest: Text) -> \(binSpec: BinariesSpec) ->
+      let
+        package: Text = "fex-emu-wine_${binSpec.version}_arm64.deb"
+      let
+        url: Text = "https://launchpad.net/~fex-emu/+archive/ubuntu/fex/+files/${package}"
+
+      in
+        CF.run "install FEX"
+                     [ "mkdir /tmp/fex"
+                     , "pushd /tmp/fex"
+                     , "wget ${url}"
+                     , "ar xv ./${package}"
+                     , "tar --zstd -xvf ./data.tar.zst"
+                     , "cp ./usr/lib/wine/aarch64-windows/* ${wineDest}/lib/wine/aarch64-windows/"
+                     , "popd"
+                     , "rm -Rf /tmp/fex"
+                     ]
+
+in
+{ BinariesSpec = BinariesSpec
+, install = installArm64ECToWine
+}
diff --git a/components/Llvm.dhall b/components/Llvm.dhall
index ec083bb038d62e606ae40e3d596dae9276769727..d68ec8e4cd67f90387e456255fd43b3bf1c65cf0 100644
--- a/components/Llvm.dhall
+++ b/components/Llvm.dhall
@@ -14,6 +14,7 @@ let
              , out_llc : Text
              , out_opt : Text
              , out_clang : Text
+             , out_clang_cpp : Text
              }
     , default = {}
     }
@@ -36,7 +37,8 @@ let
                      ]
         , out_llc = "${destDir}/bin/llc"
         , out_opt = "${destDir}/bin/opt"
-        , out_clang="${destDir}/bin/clang" }
+        , out_clang="${destDir}/bin/clang"
+        , out_clang_cpp="${destDir}/bin/clang++" }
 
 let
   llvmInstall: Optional Output.Type -> CF.Type =
diff --git a/components/LlvmMingw.dhall b/components/LlvmMingw.dhall
new file mode 100644
index 0000000000000000000000000000000000000000..d52d4420aaaa730834604009a7ee4cb7ced48467
--- /dev/null
+++ b/components/LlvmMingw.dhall
@@ -0,0 +1,49 @@
+let
+  CF = ../deps/Containerfile.dhall
+
+let
+  Archive: Type = <TAR_XZ | ZIP>
+
+let
+  BindistSpec: Type =
+      { -- there are two sources of such toolchain:
+        -- https://github.com/mstorsjo/llvm-mingw (it has msvcrt but no arm64ec)
+        -- https://github.com/bylaws/llvm-mingw (it has arm64ec but no msvcrt)
+        -- for all our purposes we need ucrt (not msvscrt) and arm64ec, so, `bylaws` is more suitable
+        source : Text
+      , version : Text
+      , crt : Text
+      , os : Text
+      , archive : Archive
+      }
+
+let
+  installFromBindistTo: Text -> BindistSpec -> CF.Type =
+    \(destDir: Text) -> \(bindist: BindistSpec) ->
+      let
+        url: Text = "https://github.com/${bindist.source}/llvm-mingw/releases/download/${bindist.version}/llvm-mingw-${bindist.version}-${bindist.crt}-${bindist.os}."
+                      ++ merge { TAR_XZ = "tar.xz", ZIP = "zip" } bindist.archive
+
+      let
+        unpack : List Text = merge
+          { TAR_XZ = [ "curl -L ${url} | tar -xJC ."
+                     ]
+
+          , ZIP = [ "wget -q -O llvm-mingw-tmp.zip '${url}'"
+                  , "unzip llvm-mingw-tmp.zip -d ."
+                  , "rm llvm-mingw-tmp.zip"
+                  ]
+          } bindist.archive
+
+      in
+        CF.run "install LLVM MinGW for ${bindist.os}"
+          (unpack # [ "mkdir ${destDir}"
+                    , "cp -R llvm-mingw-*/* ${destDir}"
+                    , "rm -R llvm-mingw-*"
+                    ])
+
+in
+{ BindistSpec = BindistSpec
+, Archive = Archive
+, installFromBindistTo = installFromBindistTo
+}
diff --git a/components/MSYS2.dhall b/components/MSYS2.dhall
new file mode 100644
index 0000000000000000000000000000000000000000..a4124af53928672796dc474f67fa322419de6e9a
--- /dev/null
+++ b/components/MSYS2.dhall
@@ -0,0 +1,39 @@
+let
+  Prelude = ../deps/Prelude.dhall
+
+let
+  CF = ../deps/Containerfile.dhall
+
+let
+  BindistSpec: Type =
+      { version_year : Text
+      , version_month : Text
+      , version_day : Text
+      , wine_version : Text
+      , build_date : Text
+      , build_time : Text
+      }
+
+let
+  installFromBindistTo: Text -> BindistSpec -> Text -> CF.Type =
+    \(userHome: Text) -> \(bindist: BindistSpec) -> \(winePrefix: Text) ->
+      let
+        url: Text = "https://gitlab.haskell.org/api/v4/projects/3815/packages/generic/wine-msys2-env/${bindist.wine_version}-${bindist.version_year}_${bindist.version_month}_${bindist.version_day}-${bindist.build_date}_${bindist.build_time}/wine-msys2-env-deb12.tar.xz"
+
+      let
+        drive_c: Text = "${userHome}/.wine/drive_c"
+      let
+        runMSYS: Text = "${winePrefix}/bin/wine c:/msys64/usr/bin/bash.exe -l -c" -- option `-l` is strictly important
+
+      in
+        CF.env (toMap { MSYSTEM = "CLANGARM64" })
+        # CF.run "download & install MSYS2"
+                     [ "curl -L ${url} | tar -Jx -C ${drive_c}"
+                       -- Test MSYS2 works
+                     , "${runMSYS} ' '"
+                     ]
+
+in
+{ BindistSpec = BindistSpec
+, install = installFromBindistTo
+}
diff --git a/components/Wine.dhall b/components/Wine.dhall
new file mode 100644
index 0000000000000000000000000000000000000000..5259ee82e99538531b7653c7e3be26ab829ddf31
--- /dev/null
+++ b/components/Wine.dhall
@@ -0,0 +1,24 @@
+let
+  CF = ../deps/Containerfile.dhall
+
+let
+  BindistSpec: Type =
+      { version : Text
+      }
+
+let
+  installForArm64EC: BindistSpec -> CF.Type =
+    \(spec: BindistSpec) ->
+      let
+        url: Text = "https://gitlab.haskell.org/api/v4/projects/3815/packages/generic/wine-arm64ec-msys2/${spec.version}/wine-arm64ec-msys2-deb12.tar.xz"
+
+      in
+        CF.run "install Wine"
+                     [ "curl -L ${url} | tar -xJC /"
+                     ]
+
+in
+{ BindistSpec = BindistSpec
+, installForArm64EC = installForArm64EC
+, installedPath = "/opt/wine-arm64ec-msys2-deb12"
+}
diff --git a/images/debian.dhall b/images/debian.dhall
index 0effc067adbf1561a04a692973f0c9d4a08b8b18..af0b1d21e8a1ac10b8bffccc97c827a48d13cfb0 100644
--- a/images/debian.dhall
+++ b/images/debian.dhall
@@ -14,6 +14,14 @@ let
   Cabal = ../components/Cabal.dhall
 let
   Image = ../Image.dhall
+let
+  LlvmMinGW = ../components/LlvmMingw.dhall
+let
+  Wine = ../components/Wine.dhall
+let
+  FEX = ../components/FEX.dhall
+let
+  MSYS2 = ../components/MSYS2.dhall
 
 let
   docker_base_url: Text = "registry.gitlab.haskell.org/ghc/ci-images"
@@ -143,8 +151,8 @@ let
       ]
 
 let
-  installLlvmFromApt : Text -> Optional Llvm.Config =
-      \(ver : Text) -> Some
+  installLlvmFromAptStrict : Text -> Llvm.Config =
+      \(ver : Text) ->
           { action = CF.run "install llvm" [ "apt-get install -qy wget software-properties-common gnupg lsb-release"
                                                          , "wget https://apt.llvm.org/llvm.sh"
                                                          , "chmod +x llvm.sh"
@@ -153,8 +161,13 @@ let
           , out_llc = "/usr/bin/llc-${ver}"
           , out_opt = "/usr/bin/opt-${ver}"
           , out_clang = "/usr/bin/clang-${ver}"
+          , out_clang_cpp = "/usr/bin/clang++-${ver}"
           }
 
+let
+  installLlvmFromApt : Text -> Optional Llvm.Config =
+      \(ver : Text) -> Some (installLlvmFromAptStrict ver)
+
   -- Workaround for https://github.com/llvm/llvm-project/issues/62475
 let
   installLlvmFromAptBookworm : Text -> Optional Llvm.Config =
@@ -168,6 +181,7 @@ let
           , out_llc = "/usr/bin/llc-${ver}"
           , out_opt = "/usr/bin/opt-${ver}"
           , out_clang = "/usr/bin/clang-${ver}"
+          , out_clang_cpp = "/usr/bin/clang++-${ver}"
           }
 
 
@@ -434,6 +448,103 @@ let debian12Images: List Image.Type =
     , extraPackages = [ ] : List Text
     }
 
+, ( let
+      home_dir = "/home/ghc"
+
+    let
+      cabal_index_state = "2025-03-20T17:30:02Z"
+
+    let
+      msys_cabal_version = "3.14.1.1"
+
+    let deb = DebianImage.toDocker DebianImage::
+    { name = "aarch64-linux-deb12-wine"
+    , fromImage = "arm64v8/debian:bookworm"
+    , runnerTags = [ "aarch64-linux" ]
+    , bootstrapGhc = { version = "9.12.2", triple = "aarch64-deb12-linux" }
+    , llvm = installLlvmFromApt "19"
+    , cabalSource = Cabal.fromUpstreamBindist { version = "3.14.1.1", triple = "aarch64-linux-deb12" }
+    , extraPackages = [
+        , "zstd" -- uncompress debs for FEX dlls
+      ] : List Text
+    }
+    in deb with image = deb.image
+        # [CF.Statement.User "root"]
+        # CF.workdir "/root/"
+
+        -- Its purpose is to test the building of cross-compiled GHC for Aarch64 Windows from Linux
+        -- At the moment GHC supports LLVM =< 19, where 20250114@mstorsjo is 19.1.7
+        # LlvmMinGW.installFromBindistTo "/opt/llvm-mingw-linux"
+          { source = "mstorsjo", version = "20250114", crt = "ucrt"
+          , os = "ubuntu-20.04-aarch64", archive = LlvmMinGW.Archive.TAR_XZ
+          }
+
+        # Wine.installForArm64EC { version = "10.4" }
+        # FEX.install Wine.installedPath { version = "2503~j" }
+
+        # [CF.Statement.User "ghc"]
+        # CF.workdir "${home_dir}/"
+        # CF.env (toMap { WINEPREFIX = "${home_dir}/.wine", WINEDEBUG = "-all" })
+
+        # CF.run "init Wine drives for selected user with FEX registry preinstall"
+          [ "${Wine.installedPath}/bin/wine reg.exe ADD 'HKLM\\Software\\Microsoft\\Wow64\\amd64' /ve /t REG_SZ /d 'libarm64ecfex.dll' /f"
+          -- Forcely keep all registry changes are persistent
+          , "${Wine.installedPath}/bin/wineserver -k 15"
+          ]
+
+        # MSYS2.install home_dir { wine_version = "10.4", version_year = "2025", version_month = "02", version_day = "21", build_date = "20250326", build_time = "0916" } Wine.installedPath
+
+        # CF.run "install GHC"
+          [ "mkdir ${home_dir}/.wine/drive_c/msys64/opt/ghc-bootstrap"
+          , "curl -L https://downloads.haskell.org/~ghc/9.12.2/ghc-9.12.2-x86_64-unknown-mingw32.tar.xz | tar -Jx -C ${home_dir}/.wine/drive_c/msys64/opt/ghc-bootstrap --strip-components=1"
+          , "echo 'export PATH=/opt/ghc-bootstrap/bin:$PATH' >> ${home_dir}/.wine/drive_c/msys64/home/ghc/.bash_profile"
+          , "echo 'export GHC=/opt/ghc-bootstrap/bin/ghc' >> ${home_dir}/.wine/drive_c/msys64/home/ghc/.bash_profile"
+          , "${Wine.installedPath}/bin/wine c:/msys64/usr/bin/bash.exe -l -c 'ghc --version'"
+          ]
+        # CF.run "install Cabal"
+          [ "mkdir -p ${home_dir}/.wine/drive_c/msys64/opt/cabal/{bin,dir}"
+          , "wget -q -O tmp.zip https://downloads.haskell.org/cabal/cabal-install-${msys_cabal_version}/cabal-install-${msys_cabal_version}-x86_64-windows.zip"
+          , "unzip tmp.zip -d Cabal-msys2"
+          , "cp ./Cabal-msys2/cabal.exe ${home_dir}/.wine/drive_c/msys64/opt/cabal/bin/"
+          , "rm tmp.zip"
+          , "rm -r ./Cabal-msys2"
+          , "echo 'export PATH=/opt/cabal/dir/bin:/opt/cabal/bin:$PATH' >>  ${home_dir}/.wine/drive_c/msys64/home/ghc/.bash_profile"
+          , "echo 'export CABAL=/opt/cabal/bin/cabal' >> ${home_dir}/.wine/drive_c/msys64/home/ghc/.bash_profile"
+            -- Double escaping: one for Dhall, second for Bash
+          , "echo 'export CABAL_CONFIG=C:\\\\msys64\\\\opt\\\\cabal\\\\cabal.conf' >> ${home_dir}/.wine/drive_c/msys64/home/ghc/.bash_profile"
+          , "echo 'export CABAL_DIR=C:\\\\msys64\\\\opt\\\\cabal\\\\dir' >> ${home_dir}/.wine/drive_c/msys64/home/ghc/.bash_profile"
+          , "${Wine.installedPath}/bin/wine c:/msys64/usr/bin/bash.exe -l -c 'cabal user-config init'"
+            -- Wine/FEX has a bug: it seemed that cabal install is terminated prematurely when it stops writing into stdout/stderr for long time.
+            -- To prevent showing much garbage at the terminal use `2>/dev/null`, i.e.:
+            -- # hadrian/build clean 2>/dev/null
+            -- (MSYS2's bash prompt begins with `#`)
+          , "sed -i 's/  -- ghc-options:/  ghc-options: -v/g' ${home_dir}/.wine/drive_c/msys64/opt/cabal/cabal.conf"
+            -- The install method should be COPY because MSYS2 does not support symlinking under Wine
+          , "sed -i 's/-- install-method:/install-method: copy/g' ${home_dir}/.wine/drive_c/msys64/opt/cabal/cabal.conf"
+            -- Set Cabal registry to specific revision, yep, we need pass same index state reference twice.
+          , "sed -i 's/-- index-state:/index-state: ${cabal_index_state}/g' ${home_dir}/.wine/drive_c/msys64/opt/cabal/cabal.conf"
+          , "${Wine.installedPath}/bin/wine c:/msys64/usr/bin/bash.exe -l -c 'cabal update \"hackage.haskell.org,${cabal_index_state}\"'"
+          ]
+
+        # CF.run "install GHC build deps"
+          [ ''
+            ${Wine.installedPath}/bin/wine c:/msys64/usr/bin/bash.exe -l -c 'cabal v2-install \
+              --constraint="alex ^>= 3.5.2.0" \
+              --constraint="happy ^>= 2.1.5" \
+              --constraint="hscolour ^>= 1.25" \
+            '' ++ Prelude.Text.concatSep " " [ "hscolour", "happy", "alex" ] ++ "'"
+          , "echo 'export ALEX=/opt/cabal/dir/bin/alex' >> ${home_dir}/.wine/drive_c/msys64/home/ghc/.bash_profile"
+          , "echo 'export HAPPY=/opt/cabal/dir/bin/happy' >> ${home_dir}/.wine/drive_c/msys64/home/ghc/.bash_profile"
+          , "echo 'export HSCOLOUR=/opt/cabal/dir/bin/HsColour' >> ${home_dir}/.wine/drive_c/msys64/home/ghc/.bash_profile"
+          ]
+
+        -- At the moment GHC supports LLVM =< 19, where 20250114@mstorsjo is 19.1.7
+        # LlvmMinGW.installFromBindistTo "${home_dir}/.wine/drive_c/msys64/opt/llvm-mingw-windows"
+          { source = "mstorsjo", version = "20250114", crt = "ucrt"
+          , os = "aarch64", archive = LlvmMinGW.Archive.ZIP
+          }
+  )
+
 , DebianImage.toDocker DebianImage::
     { name = "i386-linux-deb12"
     , fromImage = "i386/debian:bookworm"