--- ./Makefile
+++ ./Makefile
@@ -57,16 +57,16 @@
 	cat findlib.conf.in | \
 	    $(SH) tools/patch '@SITELIB@' '$(OCAML_SITELIB)' >findlib.conf
 	if ./tools/cmd_from_same_dir ocamlc; then \
-		echo 'ocamlc="ocamlc.opt"' >>findlib.conf; \
+		echo 'ocamlc="ocamlc.opt$(EXEC_SUFFIX)"' >>findlib.conf; \
 	fi
 	if ./tools/cmd_from_same_dir ocamlopt; then \
-		echo 'ocamlopt="ocamlopt.opt"' >>findlib.conf; \
+		echo 'ocamlopt="ocamlopt.opt$(EXEC_SUFFIX)"' >>findlib.conf; \
 	fi
 	if ./tools/cmd_from_same_dir ocamldep; then \
-		echo 'ocamldep="ocamldep.opt"' >>findlib.conf; \
+		echo 'ocamldep="ocamldep.opt$(EXEC_SUFFIX)"' >>findlib.conf; \
 	fi
 	if ./tools/cmd_from_same_dir ocamldoc; then \
-		echo 'ocamldoc="ocamldoc.opt"' >>findlib.conf; \
+		echo 'ocamldoc="ocamldoc.opt$(EXEC_SUFFIX)"' >>findlib.conf; \
 	fi
 
 .PHONY: install-doc
--- ./src/findlib/findlib_config.mlp
+++ ./src/findlib/findlib_config.mlp
@@ -24,3 +24,5 @@
     | "MacOS" -> ""        (* don't know *)
     | _ -> failwith "Unknown Sys.os_type"
 ;;
+
+let exec_suffix = "@EXEC_SUFFIX@";;
--- ./src/findlib/findlib.ml
+++ ./src/findlib/findlib.ml
@@ -28,15 +28,20 @@
 let conf_ldconf = ref "";;
 let conf_ignore_dups_in = ref ([] : string list);;
 
-let ocamlc_default = "ocamlc";;
-let ocamlopt_default = "ocamlopt";;
-let ocamlcp_default = "ocamlcp";;
-let ocamloptp_default = "ocamloptp";;
-let ocamlmklib_default = "ocamlmklib";;
-let ocamlmktop_default = "ocamlmktop";;
-let ocamldep_default = "ocamldep";;
-let ocamlbrowser_default = "ocamlbrowser";;
-let ocamldoc_default = "ocamldoc";;
+let add_exec str =
+  match Findlib_config.exec_suffix with
+  | "" -> str
+  | a  -> str ^ a ;;
+let ocamlc_default = add_exec "ocamlc";;
+let ocamlopt_default = add_exec "ocamlopt";;
+let ocamlcp_default = add_exec "ocamlcp";;
+let ocamloptp_default = add_exec "ocamloptp";;
+let ocamlmklib_default = add_exec "ocamlmklib";;
+let ocamlmktop_default = add_exec "ocamlmktop";;
+let ocamldep_default = add_exec "ocamldep";;
+let ocamlbrowser_default = add_exec "ocamlbrowser";;
+let ocamldoc_default = add_exec "ocamldoc";;
+
 
 
 let init_manually 
--- ./src/findlib/fl_package_base.ml
+++ ./src/findlib/fl_package_base.ml
@@ -133,7 +133,15 @@
 	  List.find (fun def -> def.def_var = "exists_if") p.package_defs  in
 	let files = Fl_split.in_words def.def_value in
 	List.exists 
-	  (fun file -> Sys.file_exists (Filename.concat d' file))
+	  (fun file ->
+            let fln = Filename.concat d' file in
+            let e = Sys.file_exists fln in
+            (* necessary for ppx executables *)
+            if e || Sys.os_type <> "Win32" || Filename.check_suffix fln ".exe" then
+              e
+            else
+              Sys.file_exists (fln ^ ".exe")
+          )
 	  files
       with Not_found -> true in
 
--- ./src/findlib/fl_split.ml
+++ ./src/findlib/fl_split.ml
@@ -126,10 +126,17 @@
     | '/' | '\\' -> true
     | _ -> false in
   let norm_dir_win() =
-    if l >= 1 && s.[0] = '/' then
-      Buffer.add_char b '\\' else Buffer.add_char b s.[0];
-    if l >= 2 && s.[1] = '/' then
-      Buffer.add_char b '\\' else Buffer.add_char b s.[1];
+    if l >= 1 then (
+      if s.[0] = '/' then
+        Buffer.add_char b '\\'
+      else
+        Buffer.add_char b s.[0] ;
+      if l >= 2 then
+        if s.[1] = '/' then
+          Buffer.add_char b '\\'
+        else
+          Buffer.add_char b s.[1];
+    );
     for k = 2 to l - 1 do
       let c = s.[k] in
       if is_slash c then (
--- ./src/findlib/frontend.ml
+++ ./src/findlib/frontend.ml
@@ -31,10 +31,18 @@
   else
     Sys_error (arg ^ ": " ^ Unix.error_message code)
 
+let is_win = Sys.os_type = "Win32"
+
+let () =
+  match Findlib_config.system with
+    | "win32" | "win64" | "mingw" | "cygwin" | "mingw64" | "cygwin64" ->
+      (try set_binary_mode_out stdout true with _ -> ());
+      (try set_binary_mode_out stderr true with _ -> ());
+    | _ -> ()
 
 let slashify s =
   match Findlib_config.system with
-    | "mingw" | "mingw64" | "cygwin" ->
+    | "win32" | "win64" | "mingw" | "cygwin" | "mingw64" | "cygwin64" ->
         let b = Buffer.create 80 in
         String.iter
           (function
@@ -49,7 +57,7 @@
 
 let out_path ?(prefix="") s =
   match Findlib_config.system with
-    | "mingw" | "mingw64" | "cygwin" ->
+   | "win32" | "win64" | "mingw" | "mingw64" | "cygwin" ->
 	let u = slashify s in
 	prefix ^ 
 	  (if String.contains u ' ' then
@@ -273,11 +281,9 @@
 
 
 let identify_dir d =
-  match Sys.os_type with
-    | "Win32" ->
-	failwith "identify_dir"   (* not available *)
-    | _ ->
-	let s = Unix.stat d in
+  if is_win then
+    failwith "identify_dir";   (* not available *)
+  let s = Unix.stat d in
 	(s.Unix.st_dev, s.Unix.st_ino)
 ;;
 
@@ -459,6 +465,96 @@
       )
       packages
 
+let rewrite_cmd s =
+  if s = "" || not is_win then
+    s
+  else
+    let s =
+      let l = String.length s in
+      let b = Buffer.create l in
+      for i = 0 to pred l do
+        match s.[i] with
+        | '/' -> Buffer.add_char b '\\'
+        | x -> Buffer.add_char b x
+      done;
+      Buffer.contents b
+    in
+    if (Filename.is_implicit s && String.contains s '\\' = false) ||
+      Filename.check_suffix (String.lowercase s) ".exe" then
+      s
+    else
+      let s' = s ^ ".exe" in
+      if Sys.file_exists s' then
+        s'
+      else
+        s
+
+let rewrite_cmd s =
+  if s = "" || not is_win then s else
+  let s =
+    let l = String.length s in
+    let b = Buffer.create l in
+    for i = 0 to pred l do
+      match s.[i] with
+      | '/' -> Buffer.add_char b '\\'
+      | x -> Buffer.add_char b x
+    done;
+    Buffer.contents b
+  in
+  if (Filename.is_implicit s && String.contains s '\\' = false) ||
+     Filename.check_suffix (String.lowercase s) ".exe" then
+    s
+  else
+    let s' = s ^ ".exe" in
+    if Sys.file_exists s' then
+      s'
+    else
+      s
+
+let rewrite_pp cmd =
+  if not is_win then cmd else
+  let module T = struct exception Keep end in
+  let is_whitespace = function
+  | ' ' | '\011' | '\012' | '\n' | '\r' | '\t' -> true
+  | _ -> false in
+  (* characters that triggers special behaviour (cmd.exe, not unix shell) *)
+  let is_unsafe_char = function
+  | '(' | ')' | '%' | '!' | '^' | '<' | '>' | '&' -> true
+  | _ -> false in
+  let len = String.length cmd in
+  let buf = Buffer.create (len + 4) in
+  let buf_cmd = Buffer.create len in
+  let rec iter_ws i =
+    if i >= len then () else
+    let cur = cmd.[i] in
+    if is_whitespace cur then (
+      Buffer.add_char buf cur;
+      iter_ws (succ i)
+    )
+    else
+      iter_cmd i
+  and iter_cmd i =
+    if i >= len then add_buf_cmd () else
+    let cur = cmd.[i] in
+    if is_unsafe_char cur || cur = '"' || cur = '\'' then
+      raise T.Keep;
+    if is_whitespace cur then (
+      add_buf_cmd ();
+      Buffer.add_substring buf cmd i (len - i)
+    )
+    else (
+      Buffer.add_char buf_cmd cur;
+      iter_cmd (succ i)
+    )
+  and add_buf_cmd () =
+    if Buffer.length buf_cmd > 0 then
+      Buffer.add_string buf (rewrite_cmd (Buffer.contents buf_cmd))
+  in
+  try
+    iter_ws 0;
+    Buffer.contents buf
+  with
+  | T.Keep -> cmd
 
 let process_pp_spec syntax_preds packages pp_opts =
   (* Returns: pp_command *)
@@ -549,7 +645,7 @@
       None -> []
     | Some cmd ->
 	["-pp";
-	 cmd ^ " " ^
+	 (rewrite_cmd cmd) ^ " " ^
 	 String.concat " " (List.map Filename.quote pp_i_options) ^ " " ^
 	 String.concat " " (List.map Filename.quote pp_archives) ^ " " ^
 	 String.concat " " (List.map Filename.quote pp_opts)]
@@ -625,9 +721,11 @@
           in
           try
             let preprocessor =
+              rewrite_cmd (
               resolve_path
                 ~base ~explicit:true
-                (package_property predicates pname "ppx") in
+                  (package_property predicates pname "ppx") )
+            in
             ["-ppx"; String.concat " " (preprocessor :: options)]
           with Not_found -> []
        )
@@ -895,6 +993,14 @@
        switch (e.g. -L<path> instead of -L <path>)
      *)
 
+(* We may need to remove files on which we do not have complete control.
+   On Windows, removing a read-only file fails so try to change the
+   mode of the file first. *)
+let remove_file fname =
+  try Sys.remove fname
+  with Sys_error _ when is_win ->
+    (try Unix.chmod fname 0o666 with Unix.Unix_error _ -> ());
+    Sys.remove fname
 
 let ocamlc which () =
 
@@ -1022,9 +1128,12 @@
               
 	      "-intf", 
 	      Arg.String (fun s -> pass_files := !pass_files @ [ Intf(slashify s) ]);
-              
+
 	      "-pp", 
-	      Arg.String (fun s -> pp_specified := true; add_spec_fn "-pp" s);
+	      Arg.String (fun s -> pp_specified := true; add_spec_fn "-pp" (rewrite_pp s));
+
+              "-ppx",
+              Arg.String (fun s -> add_spec_fn "-ppx" (rewrite_pp s));
 	      
 	      "-thread", 
 	      Arg.Unit (fun _ -> threads := threads_default);
@@ -1237,7 +1346,7 @@
     with
       any ->
 	close_out initl;
-	Sys.remove initl_file_name;
+	remove_file initl_file_name;
 	raise any
   end;
 
@@ -1245,9 +1354,9 @@
     at_exit
       (fun () ->
 	let tr f x = try f x with _ -> () in
-	tr Sys.remove initl_file_name;
-	tr Sys.remove (Filename.chop_extension initl_file_name ^ ".cmi");
-	tr Sys.remove (Filename.chop_extension initl_file_name ^ ".cmo");
+	tr remove_file initl_file_name;
+	tr remove_file (Filename.chop_extension initl_file_name ^ ".cmi");
+	tr remove_file (Filename.chop_extension initl_file_name ^ ".cmo");
       );
 
   let exclude_list = [ stdlibdir; threads_dir; vmthreads_dir ] in
@@ -1493,7 +1602,9 @@
 	  [ "-v", Arg.Unit (fun () -> verbose := Verbose);
 	    "-pp", Arg.String (fun s ->
 				 pp_specified := true;
-				 options := !options @ ["-pp"; s]);
+				 options := !options @ ["-pp"; rewrite_pp s]);
+            "-ppx", Arg.String (fun s ->
+				 options := !options @ ["-ppx"; rewrite_pp s]);
 	  ]
       )
     )
@@ -1672,7 +1783,9 @@
 	      Arg.String (fun s -> add_spec_fn "-I" (slashify (resolve_path s)));
 
 	      "-pp", Arg.String (fun s -> pp_specified := true;
-		 	           add_spec_fn "-pp" s);
+                           add_spec_fn "-pp" (rewrite_pp s));
+              "-ppx", Arg.String (fun s -> add_spec_fn "-ppx" (rewrite_pp s));
+
 	    ]
 	)
     )
@@ -1830,7 +1943,10 @@
       output_string ch_out append;
       close_out ch_out;
       close_in ch_in;
-      Unix.utimes outpath s.Unix.st_mtime s.Unix.st_mtime;
+      (try Unix.utimes outpath s.Unix.st_mtime s.Unix.st_mtime
+       with Unix.Unix_error(e,_,_) ->
+         prerr_endline("Warning: setting utimes for " ^ outpath
+                       ^ ": " ^ Unix.error_message e));
 
       prerr_endline("Installed " ^ outpath);
     with
@@ -1882,6 +1998,8 @@
              Unix.openfile (Filename.concat dir owner_file) [Unix.O_RDONLY] 0 in
            let f =
              Unix.in_channel_of_descr fd in
+           if is_win then
+             set_binary_mode_in f false;
            try
              let line = input_line f in
              let is_my_file = (line = pkg) in
@@ -2208,7 +2326,7 @@
     let lines = read_ldconf !ldconf in
     let dlldir_norm = Fl_split.norm_dir dlldir in
     let dlldir_norm_lc = string_lowercase_ascii dlldir_norm in
-    let ci_filesys = (Sys.os_type = "Win32") in
+    let ci_filesys = is_win in
     let check_dir d =
       let d' = Fl_split.norm_dir d in
       (d' = dlldir_norm) || 
@@ -2356,7 +2474,7 @@
       List.iter
         (fun file ->
            let absfile = Filename.concat dlldir file in
-           Sys.remove absfile;
+           remove_file absfile;
            prerr_endline ("Removed " ^ absfile)
         )
         dll_files
@@ -2365,7 +2483,7 @@
     (* Remove the files from the package directory: *)
     if Sys.file_exists pkgdir then begin
       let files = Sys.readdir pkgdir in
-      Array.iter (fun f -> Sys.remove (Filename.concat pkgdir f)) files;
+      Array.iter (fun f -> remove_file (Filename.concat pkgdir f)) files;
       Unix.rmdir pkgdir;
       prerr_endline ("Removed " ^ pkgdir)
     end
@@ -2415,7 +2533,9 @@
 
 
 let print_configuration() =
+  let sl = slashify in
   let dir s =
+    let s = sl s in
     if Sys.file_exists s then
       s
     else
@@ -2453,27 +2573,27 @@
 	   if md = "" then "the corresponding package directories" else dir md
 	  );
 	Printf.printf "The standard library is assumed to reside in:\n    %s\n"
-	  (Findlib.ocaml_stdlib());
+    (sl (Findlib.ocaml_stdlib()));
 	Printf.printf "The ld.conf file can be found here:\n    %s\n"
-	  (Findlib.ocaml_ldconf());
+    (sl (Findlib.ocaml_ldconf()));
 	flush stdout
     | Some "conf" ->
-	print_endline (Findlib.config_file())
+  print_endline (sl (Findlib.config_file()))
     | Some "path" ->
-	List.iter print_endline (Findlib.search_path())
+  List.iter ( fun x -> print_endline (sl x)) (Findlib.search_path())
     | Some "destdir" ->
-	print_endline (Findlib.default_location())
+  print_endline ( sl (Findlib.default_location()))
     | Some "metadir" ->
-	print_endline (Findlib.meta_directory())
+  print_endline ( sl (Findlib.meta_directory()))
     | Some "metapath" ->
         let mdir = Findlib.meta_directory() in
         let ddir = Findlib.default_location() in
-	print_endline 
-          (if mdir <> "" then mdir ^ "/META.%s" else ddir ^ "/%s/META")
+  print_endline ( sl
+          (if mdir <> "" then mdir ^ "/META.%s" else ddir ^ "/%s/META"))
     | Some "stdlib" ->
-	print_endline (Findlib.ocaml_stdlib())
+  print_endline ( sl (Findlib.ocaml_stdlib()))
     | Some "ldconf" ->
-	print_endline (Findlib.ocaml_ldconf())
+  print_endline ( sl (Findlib.ocaml_ldconf()))
     | _ ->
 	assert false
 ;;
@@ -2481,7 +2601,7 @@
 
 let ocamlcall pkg cmd =
   let dir = package_directory pkg in
-  let path = Filename.concat dir cmd in
+  let path = rewrite_cmd (Filename.concat dir cmd) in
   begin
     try Unix.access path [ Unix.X_OK ]
     with
@@ -2647,6 +2767,10 @@
   | Sys_error f ->
       prerr_endline ("ocamlfind: " ^ f);
       exit 2
+  | Unix.Unix_error (e, fn, f) ->
+      prerr_endline ("ocamlfind: " ^ fn ^ " " ^ f
+                     ^ ": " ^ Unix.error_message e);
+      exit 2
   | Findlib.No_such_package(pkg,info) ->
       prerr_endline ("ocamlfind: Package `" ^ pkg ^ "' not found" ^
 		     (if info <> "" then " - " ^ info else ""));
--- ./src/findlib/Makefile
+++ ./src/findlib/Makefile
@@ -90,6 +90,7 @@
 	cat findlib_config.mlp | \
 	        $(SH) $(TOP)/tools/patch '@CONFIGFILE@' '$(OCAMLFIND_CONF)' | \
 	        $(SH) $(TOP)/tools/patch '@STDLIB@' '$(OCAML_CORE_STDLIB)' | \
+			$(SH) $(TOP)/tools/patch '@EXEC_SUFFIX@' '$(EXEC_SUFFIX)' | \
 		sed -e 's;@AUTOLINK@;$(OCAML_AUTOLINK);g' \
 		    -e 's;@SYSTEM@;$(SYSTEM);g' \
 		     >findlib_config.ml
--- ./src/findlib/frontend.ml
+++ ./src/findlib/frontend.ml
@@ -281,10 +281,8 @@
 
 
 let identify_dir d =
-  if is_win then
-    failwith "identify_dir";   (* not available *)
   let s = Unix.stat d in
-	(s.Unix.st_dev, s.Unix.st_ino)
+  (s.Unix.st_dev, s.Unix.st_ino)
 ;;
 
 
