Skip to content

Embed cygwin's setup.exe on windows as a fallback when cygwin.com is unavailable#6526

Merged
dra27 merged 2 commits intoocaml:masterfrom
kit-ty-kate:embed-cygwin
Jun 5, 2025
Merged

Embed cygwin's setup.exe on windows as a fallback when cygwin.com is unavailable#6526
dra27 merged 2 commits intoocaml:masterfrom
kit-ty-kate:embed-cygwin

Conversation

@kit-ty-kate
Copy link
Copy Markdown
Member

@kit-ty-kate kit-ty-kate commented Jun 2, 2025

Supersedes #6523
Fixes #6498
related #6474

@kit-ty-kate kit-ty-kate added this to the 2.4.0~alpha3 milestone Jun 2, 2025
@rjbou rjbou self-requested a review June 2, 2025 12:10
configure.ac Outdated
Comment on lines +92 to +119
AC_ARG_WITH([embed-cygwin-setup],
AS_HELP_STRING([--embed-cygwin-setup],["Embed Cygwin's setup.exe into the executable"]))

AS_IF([test "x${with_embed_cygwin_setup}" = "xyes"],[
curl --silent -Lo cygwin-setup.exe https://cygwin.com/setup-x86_64.exe
ocaml shell/embed.ml cygwin-setup.exe > src/state/opamEmbedCygwinSetup.ml
])

Copy link
Copy Markdown
Member

@dra27 dra27 Jun 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

embedded rather than embed? So --with-embedded-cygwin-setup (or it could just be --with-cygwin-setup?):

Suggested change
AC_ARG_WITH([embed-cygwin-setup],
AS_HELP_STRING([--embed-cygwin-setup],["Embed Cygwin's setup.exe into the executable"]))
AS_IF([test "x${with_embed_cygwin_setup}" = "xyes"],[
curl --silent -Lo cygwin-setup.exe https://cygwin.com/setup-x86_64.exe
ocaml shell/embed.ml cygwin-setup.exe > src/state/opamEmbedCygwinSetup.ml
])
AC_ARG_WITH([embedded-cygwin-setup],
AS_HELP_STRING([--with-embedded-cygwin-setup],["Embed Cygwin's setup.exe into the executable"]))
AS_IF([test "x${with_embedded_cygwin_setup}" = "xyes"],[
curl --silent -Lo cygwin-setup.exe https://cygwin.com/setup-x86_64.exe
ocaml shell/embed.ml cygwin-setup.exe > src/state/opamEmbedCygwinSetup.ml
])

In passing, to avoid compulsory network access in configure when using this, it'd be tempting to support --with-embedded-cygwin-setup meaning to download and --with-embedded-cygwin-setup=setup-x86_64.exe to use a local copy

shell/embed.ml Outdated
@@ -0,0 +1,22 @@
let add_chan buf chan =
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(* General module to embed content.
   Usage: 'ocaml shell/embed.ml > opamEmbedModule.ml'
*)
let add_chan buf chan =

configure.ac Outdated
AC_ARG_WITH([vendored-deps],
AS_HELP_STRING([--with-vendored-deps],[Use vendored dependencies instead of any available in the compiler installation]))

AC_ARG_WITH([embed-cygwin-setup],
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to make this option available only on Windows system ?

configure.ac Outdated
AS_HELP_STRING([--embed-cygwin-setup],["Embed Cygwin's setup.exe into the executable"]))

AS_IF([test "x${with_embed_cygwin_setup}" = "xyes"],[
curl --silent -Lo cygwin-setup.exe https://cygwin.com/setup-x86_64.exe
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to check the hash ?

{|(* THIS FILE IS AUTOMATICALLY GENERATED, EDIT configure.ac & shell/embed.ml INSTEAD *)
let content = Some "%s"
|}
(String.escaped content_setup)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We loose some compression by not using base64 (2.1M vs 1.5M)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not what i'm observing. Base64 doesn't compress; on the contrary as far as i know it makes the data bigger due to its encoding.
Test done encoding my local /usr/bin/cat ELF binary:

  • base64: 1.87MB
  • String.escaped: 1.77MB

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Erm, apples and oranges are being compared here - the base64 version was writing an actual base64 string into the executable - so the setup executable will be 33% larger. This version is writing the OCaml string constant to the source file ... so the data in the executable will be a verbatim copy of the original executable (plus a tiny bit of overhead from the marshal header)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, I tested the base64 tool and diffed the generated file, not the library directly in the code.

@kit-ty-kate kit-ty-kate force-pushed the embed-cygwin branch 2 times, most recently from 82a6d99 to 88711e8 Compare June 3, 2025 13:07
@kit-ty-kate kit-ty-kate requested a review from rjbou June 3, 2025 14:43
@kit-ty-kate kit-ty-kate marked this pull request as ready for review June 3, 2025 14:43
@rjbou
Copy link
Copy Markdown
Collaborator

rjbou commented Jun 3, 2025

Good to go once the local test validated

Copy link
Copy Markdown
Member

@dra27 dra27 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested - both for opam init and opam update --depexts and also the configure option with a local copy of an older setup.exe ... it's working beautifully!

A couple of minor suggestions in configure.ac, a couple of totally optional thoughts on the crunching... the log/warning at init is the only thing which I think ought to be done (in particular, it means that CI runs which happen to use a cached copy should clearly display it, etc.)

configure.ac Outdated
AS_IF([test "x$with_cygwin_setup" != "x"],[
AS_CASE([$with_cygwin_setup],
[yes], [
curl --silent -LO https://cygwin.com/sha512.sum
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file includes checksums for the 32-bit setup program which causes this:

shasum: setup-x86.exe: No such file or directory
setup-x86.exe: FAILED open or read
setup-x86_64.exe: OK
shasum: WARNING: 1 listed file could not be read

Possibly just:

Suggested change
curl --silent -LO https://cygwin.com/sha512.sum
curl --silent -L https://cygwin.com/sha512.sum | grep -F x86_64 > sha512.sum

which then has:

checking OCaml Sys.os_type... Win32
setup-x86_64.exe: OK
checking for gawk... gawk

configure.ac Outdated
CYGWIN_SETUP=setup-x86_64.exe
],
[no], [],
[CYGWIN_SETUP=$with_cygwin_setup])
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Means that a Cygwin path can be used to specify the file (e.g. $PWD/cache, etc.)

Suggested change
[CYGWIN_SETUP=$with_cygwin_setup])
[CYGWIN_SETUP="$(cygpath -m "$with_cygwin_setup")"])

src/state/dune Outdated
(deps ../../shell/crunch.ml (glob_files shellscripts/*.*sh))
(action (with-stdout-to %{targets} (run ocaml %{deps}))))

; Embed Cygwin mechanism (done in the configure script on Windows if requested)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two completely optional observations, just having spotted it: Embedded, rather than Embed? It could be processed in crunch.ml, but it's not like adding a module particularly matters?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

crunch.ml does something slightly different with regards to \n so i'd rather not overcomplicate this PR. We can definitely look into merging the two later though if you want. If you're fine with that i'll open a separate issue to fix later.

else
begin match OpamEmbedCygwinSetup.content with
| None -> Printexc.raise_with_backtrace exn backtrace
| Some setup_exe_content -> OpamFilename.write dst setup_exe_content
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it ought to at least display a log entry that it wrote from an internal copy, or even better a warning, e.g.

Suggested change
| Some setup_exe_content -> OpamFilename.write dst setup_exe_content
| Some setup_exe_content ->
OpamConsole.warning "Cygwin setup Failed to download - using embedded copy instead";
OpamFilename.write dst setup_exe_content

@kit-ty-kate
Copy link
Copy Markdown
Member Author

@dra27 i believe that's everything included

@dra27
Copy link
Copy Markdown
Member

dra27 commented Jun 4, 2025

There was a typo in the change that meant setup was no longer downloaded - I spotted the "unclean" files while checking that and, as I'm on a train, also happened to spot that it ignores errors if the download fails, which is the backdrop for the other two commits!

kit-ty-kate and others added 2 commits June 5, 2025 06:10
…unavailable

Co-authored-by: Raja Boujbel <raja.boujbel@ocamlpro.com>
Co-authored-by: David Allsopp <david.allsopp@metastack.com>
@dra27
Copy link
Copy Markdown
Member

dra27 commented Jun 5, 2025

Spectrum is green!

@dra27 dra27 merged commit fee851c into ocaml:master Jun 5, 2025
56 checks passed
@kit-ty-kate kit-ty-kate deleted the embed-cygwin branch June 5, 2025 11:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

setup.exe: embed in Windows binary

3 participants