How to set the stacksize for ocamlopt.opt.exe on MinGW cygwin host

I maintain the distribution of a larger OCaml project (Coq Platform) and one of the OCaml files in there needs a stack size of 64MB for the compiler (ocamlopt.opt.exe) to compile (32 MB is not enough). I know that I can use editbin to change the stack size after the facts on Windows, but there is no open source alternative of editbin I know of. In the OCaml configure file (I am still on 4.14.2) I see:

  x86_64-w64-mingw32) :
    flexdll_chain='mingw64'
    flexlink_flags="-chain $flexdll_chain -stack 33554432" ;; #(

but I don’t see a way to set flexlink_flags directly in case one doesn’t like the default. Should I just patch the configure file (easy enough in opam)?

What I am unsure of: is the option used for the executables ocamlopt generates or for ocamlopt itself or both?

Unfortunately, there is no way to customize the stack size currently. Patching the ./configure script is one way. You can also use the editbin.exe tool to modify the stack size after the fact (using the /STACK option).

Cheers,
Nicolas

Hi Nicolas,

yes, as I wrote I am aware of editbin, but this is about an open source SW distribution and it is difficult to rely on proprietary software - even if it is freely installable.

I will go ahead and patch the configure file via opam.

Best regards,

Michael

Sorry, I had missed your mentioning editbin. Incidentally, at LexiFi we had the same need to avoid depending on the MSVC toolchain so we just reimplemented the needed functionality in OCaml :slight_smile:

(* Modify the stack size of the resulting PE executable.

   See https://learn.microsoft.com/en-us/windows/win32/debug/pe-format for a
   description of the PE format. *)

let perform ~__FUNCTION__ f fd ofs len buf =
  if Bytes.length buf < len then invalid_arg __FUNCTION__;
  let _ = Unix.lseek fd ofs SEEK_SET in
  let rec loop ofs len =
    if len <= 0 then ()
    else begin
      let n = f fd buf ofs len in
      if n = 0 then raise End_of_file;
      loop (ofs + n) (len - n)
    end
  in
  loop 0 len

let really_read = perform ~__FUNCTION__ Unix.read
let really_write = perform ~__FUNCTION__ Unix.write

let read_bytes fd ofs len =
  let buf = Bytes.create len in
  really_read fd ofs len buf;
  Bytes.unsafe_to_string buf

let read_int f len fd ofs =
  f (read_bytes fd ofs len) 0

let read_int32 = read_int String.get_int32_le 4
let read_int16 = read_int String.get_int16_le 2

let write_int f len =
  let buf = Bytes.create len in
  fun fd ofs n ->
    f buf 0 n;
    really_write fd ofs len buf

let write_int64 = write_int Bytes.set_int64_le 8

let set_stack_size out n =
  assert (Sys.word_size = 64);
  let fd = Unix.openfile out [O_RDWR; O_SHARE_DELETE] 0o755 in
  let base = Option.get (Int32.unsigned_to_int (read_int32 fd 0x3c)) in
  let sign = read_bytes fd base 4 in
  if sign <> "PE\000\000" then Printf.ksprintf failwith "Invalid PE Signature: %S" sign;
  let base = base + 24 in
  let sign = read_int16 fd base in
  if sign <> 0x20b then Printf.ksprintf failwith "Invalid PE Optional Header Signature: 0x%x" sign;
  write_int64 fd (base + 72) n

(it assumes a 64-bit COFF binary)

Cheers,
Nicolas

2 Likes

Hi Nicolas,

great, many thanks! This solution has the advantage that I can supply a script to patch ocamlc and coqc after the fact as needed by the user. Usually one does not know in advance the stack size one will need and quite a few researchers would appreciate if they could just try if their code would work with just a larger stack size.

IMHO it would be worthwhile to supply this tool as opam package on Windows.

Best regards,

Michael

1 Like