Cygwin CI journey

Setting up Cygwin CI environment for testing one of my projects took more than fifty trial-and-error attempts - that's why I think it will be useful to leave some written notes on the issues I've encountered. Here is the end result - GitHub CI running some Makefile tests in Cygwin.

Cygwin gotchas

  • Cygwin installer likes to fail silently, providing only cryptic exit codes (127 or -1073741571)

    %CYGWIN_ROOT%\setup.exe --quiet-mode --verbose --no-desktop --download --local-install --no-verify --site %CYGWIN_MIRROR% --local-package-dir %CYGWIN_PACKAGE_CACHE% --root %CYGWIN_ROOT%
    Starting cygwin install, version 2.897
    User has backup/restore rights
    io_stream_cygfile: fopen(/etc/setup/setup.rc) failed 2 No such file or directory
    Current Directory: cache\cygwin-packages
    Could not open service McShield for query, start and stop. McAfee may not be installed, or we don't have access.
    root: d:\a\Makefile.venv\Makefile.venv\cache\cygwin system
    Selected local directory: cache\cygwin-packages
    ##[error]Process completed with exit code -1073741571.
    

    At least some of those errors can be avoided by providing full absolute paths to the installer and any argument values instead of relative ones.

    In the end I've switched to Chocolatey to handle the installation for me. It's certainly better but still requires calling setup.exe to install custom packages.

  • Since Cygwin installation and configuration are usually pretty slow (~3 min), CI setup benefits a lot from caching this step between runs. Unfortunately, default GitHub actions for caching can't help with Cygwin root, because Windows is pretty hostile to an average Joe trying to make symlinks.

    Instead, I've added a separate step that calls tar --dereference explicitly and leaves only a simple archive for the caching action to handle. Please note that tar uses exit code 1 to indicate that everything was OK, but some warnings were printed to stderr. Also, order of command line arguments matters, at least for --exclude values. That was pretty unexpected for me.

  • You need to be careful when invoking apps under Cygwin - some environment variables may be inherited from cmd session. For example, $PATH will almost certainly point to binaries outside Cygwin root. I found that explicitly defining $PATH simplifies matters a lot.

PowerShell/cmd peculiarities

Since host OS is still Windows, you get to encounter all the usual PowerShell/cmd quirks. I tripped over the fact that PowerShell does not like double-dashed --GNU-style options, and over weird nested quotes required to properly combine environment variables and special characters in one value in cmd.

GitHub CI

Some of my attempts were just me trying to work around GitHub CI limitations. For example, dynamically calculating the value of environment variable based on values of other variables. This looks quite ugly:

- name: Use absolute path for CYGWIN_ROOT
  run: echo "::set-env name=CYGWIN_ROOT::${env:GITHUB_WORKSPACE}\${env:CYGWIN_ROOT}"

I've also failed at proper syntax for YAML multiline strings more times than I'm comfortable admitting :)