diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 663ac721cc3b3d7b9dafc1a6f9ef922e7f1f0548_LmdpdGxhYi1jaS55bWw=..70819efe25e896879b7426a55f942e43d922d7d5_LmdpdGxhYi1jaS55bWw= 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -2,22 +2,7 @@
   # Reuse libxml2 image
   image: registry.gitlab.gnome.org/gnome/libxml2
   script:
-    - |
-      git clone --depth 1 https://gitlab.gnome.org/GNOME/libxml2.git
-      cd libxml2
-      sh autogen.sh $CONFIG
-      make -j$(nproc)
-      cd ..
-      sh autogen.sh $CONFIG --with-libxml-src=libxml2
-      # Don't run make in "doc" directory
-      for target in libxslt libexslt xsltproc python tests/plugins; do
-          make -j$(nproc) -C $target V=1 CFLAGS="$CFLAGS -Werror"
-      done
-      make -j$(nproc) -C tests/fuzz V=1 CFLAGS="$CFLAGS -Werror" testTargets
-      make -s -C tests tests | tee test.log
-      make -s -C xsltproc tests | tee -a test.log
-      grep -qv '^## Running' test.log && exit 1
-      make -s -C python tests
+    - sh .gitlab-ci/test.sh
 
 gcc:
   extends: .test
@@ -57,9 +42,37 @@
     CC: clang
     CFLAGS: "-O2 -g -fno-omit-frame-pointer -fsanitize=memory -Wimplicit-int-conversion -Wno-error=cast-align"
 
+.mingw:
+  tags:
+    - win32-ps
+  variables:
+    CONFIG: "--without-crypto"
+    CHERE_INVOKING: "yes"
+  before_script:
+    - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12"
+    - $Env:Path="C:\msys64\$Env:MINGW_PATH\bin;C:\msys64\usr\bin;$Env:Path"
+    - bash -lc 'sh .gitlab-ci/setup_mingw.sh'
+  script:
+    - bash -lc 'sh .gitlab-ci/test.sh'
+
+mingw:w64-x86_64:shared:
+  extends: .mingw
+  variables:
+    CFLAGS: "-O2"
+    MSYSTEM: MINGW64
+    MINGW_PATH: mingw64
+
+# Disabled, GCC missing?
+.mingw:msys:shared:
+  extends: .mingw
+  variables:
+    CFLAGS: "-O2"
+    MSYSTEM: MSYS
+    MINGW_PATH: usr
+
 .cmake:linux:
   image: registry.gitlab.gnome.org/gnome/libxml2
   before_script:
     - git clone --depth 1 https://gitlab.gnome.org/GNOME/libxml2.git libxml2-source
     - cmake -DBUILD_SHARED_LIBS=$BUILD_SHARED_LIBS -DCMAKE_INSTALL_PREFIX=libxml2-install -DCMAKE_BUILD_TYPE=RelWithDebInfo -DLIBXML2_WITH_TESTS=OFF -S libxml2-source -B libxml2-build
     - cmake --build libxml2-build --target install
@@ -60,11 +73,9 @@
 .cmake:linux:
   image: registry.gitlab.gnome.org/gnome/libxml2
   before_script:
     - git clone --depth 1 https://gitlab.gnome.org/GNOME/libxml2.git libxml2-source
     - cmake -DBUILD_SHARED_LIBS=$BUILD_SHARED_LIBS -DCMAKE_INSTALL_PREFIX=libxml2-install -DCMAKE_BUILD_TYPE=RelWithDebInfo -DLIBXML2_WITH_TESTS=OFF -S libxml2-source -B libxml2-build
     - cmake --build libxml2-build --target install
-    - mkdir -p libxml2-install/share/libxml2
-    - cp libxml2-source/Copyright libxml2-install/share/libxml2
     - export CMAKE_PREFIX_PATH=$CI_PROJECT_DIR/libxml2-install:$CMAKE_PREFIX_PATH
     - export PATH=$CI_PROJECT_DIR/libxml2-install/bin:$PATH
     - export LD_LIBRARY_PATH=$CI_PROJECT_DIR/libxml2-install/bin:$LD_LIBRARY_PATH
@@ -120,6 +131,8 @@
 .cmake:mingw:
   tags:
     - win32-ps
+  variables:
+    CHERE_INVOKING: "yes"
   before_script:
     - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12"
     - $Env:Path="C:\msys64\$Env:MINGW_PATH\bin;C:\msys64\usr\bin;$Env:Path"
@@ -123,19 +136,8 @@
   before_script:
     - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12"
     - $Env:Path="C:\msys64\$Env:MINGW_PATH\bin;C:\msys64\usr\bin;$Env:Path"
-    - pacman --noconfirm -Syu
-    - pacman --noconfirm -S
-        $Env:MINGW_PACKAGE_PREFIX-cmake
-        $Env:MINGW_PACKAGE_PREFIX-libiconv
-        $Env:MINGW_PACKAGE_PREFIX-ninja
-        $Env:MINGW_PACKAGE_PREFIX-python
-        $Env:MINGW_PACKAGE_PREFIX-python2
-        $Env:MINGW_PACKAGE_PREFIX-xz
-        $Env:MINGW_PACKAGE_PREFIX-zlib
-    - if (-not (Test-Path 7za.exe)) {
-        Invoke-WebRequest -Uri https://www.7-zip.org/a/7z1900-extra.7z -OutFile 7z1900-extra.7z ;
-        cmake -E tar xf 7z1900-extra.7z 7za.exe
-      }
+    - bash -lc 'sh .gitlab-ci/setup_mingw.sh'
+    - .gitlab-ci/Install-7-Zip
     - git clone --depth 1 https://gitlab.gnome.org/GNOME/libxml2.git libxml2-source
     - cmake -G Ninja -DBUILD_SHARED_LIBS=$Env:BUILD_SHARED_LIBS -DCMAKE_INSTALL_PREFIX=libxml2-install -DLIBXML2_WITH_TESTS=OFF -S libxml2-source -B libxml2-build
     - cmake --build libxml2-build --config RelWithDebInfo --target install
@@ -139,8 +141,6 @@
     - git clone --depth 1 https://gitlab.gnome.org/GNOME/libxml2.git libxml2-source
     - cmake -G Ninja -DBUILD_SHARED_LIBS=$Env:BUILD_SHARED_LIBS -DCMAKE_INSTALL_PREFIX=libxml2-install -DLIBXML2_WITH_TESTS=OFF -S libxml2-source -B libxml2-build
     - cmake --build libxml2-build --config RelWithDebInfo --target install
-    - New-Item -ItemType Directory libxml2-install\share\libxml2
-    - Copy-Item libxml2-source\Copyright libxml2-install\share\libxml2
     - $Env:CMAKE_PREFIX_PATH="$Env:CI_PROJECT_DIR\libxml2-install;$Env:CMAKE_PREFIX_PATH"
     - $Env:Path="$Env:CI_PROJECT_DIR\libxml2-install\bin;$Env:Path"
   script:
@@ -149,5 +149,5 @@
     - New-Item -ItemType Directory libxslt-install\share\libxslt
     - Copy-Item Copyright libxslt-install\share\libxslt
   after_script:
-    - .\7za.exe a libxslt-$Env:CI_COMMIT_SHORT_SHA-$Env:MINGW_PACKAGE_PREFIX-$Env:SUFFIX.7z .\libxslt-install\*
+    - .\7za.exe a libxslt-$Env:CI_COMMIT_SHORT_SHA-$Env:MSYSTEM-$Env:SUFFIX.7z .\libxslt-install\*
   cache:
@@ -153,6 +153,6 @@
   cache:
-    key: "$MINGW_PACKAGE_PREFIX"
+    key: "$MSYSTEM"
     paths:
       - 7za.exe
   artifacts:
     paths:
@@ -155,8 +155,8 @@
     paths:
       - 7za.exe
   artifacts:
     paths:
-      - libxslt-$Env:CI_COMMIT_SHORT_SHA-$Env:MINGW_PACKAGE_PREFIX-$Env:SUFFIX.7z
+      - libxslt-$Env:CI_COMMIT_SHORT_SHA-$Env:MSYSTEM-$Env:SUFFIX.7z
     expire_in: 1 day
 
 cmake:mingw:w64-i686:shared:
@@ -165,7 +165,7 @@
     - schedules
   variables:
     BUILD_SHARED_LIBS: "ON"
-    MINGW_PACKAGE_PREFIX: mingw-w64-i686
+    MSYSTEM: MINGW32
     MINGW_PATH: mingw32
     SUFFIX: shared
 
@@ -175,7 +175,7 @@
     - schedules
   variables:
     BUILD_SHARED_LIBS: "OFF"
-    MINGW_PACKAGE_PREFIX: mingw-w64-i686
+    MSYSTEM: MINGW32
     MINGW_PATH: mingw32
     SUFFIX: static
 
@@ -183,7 +183,7 @@
   extends: .cmake:mingw
   variables:
     BUILD_SHARED_LIBS: "ON"
-    MINGW_PACKAGE_PREFIX: mingw-w64-x86_64
+    MSYSTEM: MINGW64
     MINGW_PATH: mingw64
     SUFFIX: shared
 
@@ -193,7 +193,7 @@
     - schedules
   variables:
     BUILD_SHARED_LIBS: "OFF"
-    MINGW_PACKAGE_PREFIX: mingw-w64-x86_64
+    MSYSTEM: MINGW64
     MINGW_PATH: mingw64
     SUFFIX: static
 
@@ -209,11 +209,8 @@
         Expand-Archive cmake-$Env:CMAKE_VERSION-win64-x64.zip -DestinationPath .
       }
     - $Env:Path="$Env:CI_PROJECT_DIR\cmake-$Env:CMAKE_VERSION-win64-x64\bin;$Env:Path"
-    - if (-not (Test-Path 7za.exe)) {
-        Invoke-WebRequest -Uri https://www.7-zip.org/a/7z1900-extra.7z -OutFile 7z1900-extra.7z ;
-        cmake -E tar xf 7z1900-extra.7z 7za.exe
-      }
+    - .gitlab-ci/Install-7-Zip
     - git clone --depth 1 https://gitlab.gnome.org/GNOME/libxml2.git libxml2-source
     - cmake -DBUILD_SHARED_LIBS="$Env:BUILD_SHARED_LIBS" -DCMAKE_INSTALL_PREFIX=libxml2-install -DLIBXML2_WITH_ICONV=OFF -DLIBXML2_WITH_LZMA=OFF -DLIBXML2_WITH_PYTHON=OFF -DLIBXML2_WITH_ZLIB=OFF -S libxml2-source -B libxml2-build
     - cmake --build libxml2-build --config Debug --target install
     - cmake --build libxml2-build --config Release --target install
@@ -216,9 +213,7 @@
     - git clone --depth 1 https://gitlab.gnome.org/GNOME/libxml2.git libxml2-source
     - cmake -DBUILD_SHARED_LIBS="$Env:BUILD_SHARED_LIBS" -DCMAKE_INSTALL_PREFIX=libxml2-install -DLIBXML2_WITH_ICONV=OFF -DLIBXML2_WITH_LZMA=OFF -DLIBXML2_WITH_PYTHON=OFF -DLIBXML2_WITH_ZLIB=OFF -S libxml2-source -B libxml2-build
     - cmake --build libxml2-build --config Debug --target install
     - cmake --build libxml2-build --config Release --target install
-    - New-Item -ItemType Directory libxml2-install\share\libxml2
-    - Copy-Item libxml2-source\Copyright libxml2-install\share\libxml2
     - $Env:CMAKE_PREFIX_PATH="$Env:CI_PROJECT_DIR\libxml2-install;$Env:CMAKE_PREFIX_PATH"
     - $Env:Path="$Env:CI_PROJECT_DIR\libxml2-install\bin;$Env:Path"
   script:
diff --git a/.gitlab-ci/Install-7-Zip.ps1 b/.gitlab-ci/Install-7-Zip.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..70819efe25e896879b7426a55f942e43d922d7d5_LmdpdGxhYi1jaS9JbnN0YWxsLTctWmlwLnBzMQ==
--- /dev/null
+++ b/.gitlab-ci/Install-7-Zip.ps1
@@ -0,0 +1,4 @@
+if (-not (Test-Path 7za.exe)) {
+    Invoke-WebRequest -Uri https://www.7-zip.org/a/7z1900-extra.7z -OutFile 7z1900-extra.7z
+    cmake -E tar xf 7z1900-extra.7z 7za.exe
+}
diff --git a/.gitlab-ci/setup_mingw.sh b/.gitlab-ci/setup_mingw.sh
new file mode 100644
index 0000000000000000000000000000000000000000..70819efe25e896879b7426a55f942e43d922d7d5_LmdpdGxhYi1jaS9zZXR1cF9taW5ndy5zaA==
--- /dev/null
+++ b/.gitlab-ci/setup_mingw.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+prefix=
+if [ -n "$MINGW_PACKAGE_PREFIX" ]; then
+    prefix="${MINGW_PACKAGE_PREFIX}-"
+fi
+
+pacman --noconfirm -Syu
+pacman --noconfirm -S --needed \
+    ${prefix}autotools \
+    ${prefix}cmake \
+    ${prefix}libiconv \
+    ${prefix}ninja \
+    ${prefix}python \
+    ${prefix}xz \
+    ${prefix}zlib
diff --git a/.gitlab-ci/test.sh b/.gitlab-ci/test.sh
new file mode 100644
index 0000000000000000000000000000000000000000..70819efe25e896879b7426a55f942e43d922d7d5_LmdpdGxhYi1jaS90ZXN0LnNo
--- /dev/null
+++ b/.gitlab-ci/test.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+set -e
+
+git clone --depth 1 https://gitlab.gnome.org/GNOME/libxml2.git
+cd libxml2
+sh autogen.sh $CONFIG
+make -j$(nproc)
+cd ..
+
+sh autogen.sh $CONFIG --with-libxml-src=libxml2
+make -j$(nproc) V=1 CFLAGS="$CFLAGS -Werror"
+make -s -C tests tests | tee test.log
+make -s -C xsltproc tests | tee -a test.log
+grep -qv '^## Running' test.log && exit 1
+make -s -C python tests