@@ -347,10 +347,61 @@ let prepare_command_for_windows cmd =
347347 quote-handling is to prepend an empty string before the command name.
348348 Space seems to work, too - and the ouput is nicer *)
349349 let cmd = " " ^ cmd in
350- Array. append (Lazy. force windows_shell) [|" -c" ; cmd|]
350+ let shell = Lazy. force windows_shell in
351+ let all = Array. append shell [|" -c" ; cmd|] in
352+ (* [maybe_quote] was copied from ocaml/otherlibs/unix/unix_win32.ml *)
353+ let maybe_quote f =
354+ if f = " "
355+ || String. exists (function ' ' | '\"' | '\t' -> true | _ -> false ) f
356+ then Filename. quote f
357+ else f
358+ in
359+ (* Compute the size of the command as computed by "unix_win32.ml" in [make_cmdline]
360+ ( + 1 because we count an extra space at the beginning, but it's ok because we
361+ just want an over approximation) *)
362+ let size = Array. fold_left (fun acc x ->
363+ acc
364+ + 1 (* space separate *)
365+ + (String. length (maybe_quote x)))
366+ in
367+ (* cygwin seems to truncate command line at 8k (sometimes).
368+ See https://cygwin.com/pipermail/cygwin/2014-May/215364.html.
369+ While the limit might be 8192, some experiment show that it might be a bit less.
370+ Such logic exists in the fdopen repo with a limit of 7900. Let's reuse that as it
371+ has been tested for a while.
372+ *)
373+ if size < = 7900
374+ then all, None
375+ else
376+ let oc_closed = ref false in
377+ let file_deleted = ref false in
378+ let fname,oc =
379+ Filename. open_temp_file
380+ ~mode: [Open_binary ]
381+ " ocamlbuildtmp"
382+ " .sh"
383+ in
384+ let cleanup () =
385+ if not ! file_deleted then begin
386+ file_deleted:= true ;
387+ try Sys. remove fname with _ -> ()
388+ end
389+ in
390+ try
391+ output_string oc cmd;
392+ oc_closed:= true ;
393+ close_out oc;
394+ Array. append shell [| " -e" ; fname |], Some cleanup
395+ with
396+ | x ->
397+ if not ! oc_closed then
398+ close_out_noerr oc;
399+ cleanup () ;
400+ raise x
351401
352402let sys_command_win32 cmd =
353- let args = prepare_command_for_windows cmd in
403+ let args, cleanup = prepare_command_for_windows cmd in
404+ let res =
354405 try
355406 let oc = Unix. open_process_args_out args.(0 ) args in
356407 match Unix. close_process_out oc with
@@ -362,6 +413,9 @@ let sys_command_win32 cmd =
362413 raise *)
363414 log.dprintf (- 1 ) " %s: %s" cmd (Printexc. to_string x);
364415 1
416+ in
417+ Option. iter (fun f -> f () ) cleanup;
418+ res
365419
366420let sys_command =
367421 if Sys. win32 then
0 commit comments