(* Lightweight thread library for Objective Caml
 * http://www.ocsigen.org/lwt
 * Module Myocamlbuild
 * Copyright (C) 2010 Jérémie Dimino
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, with linking exceptions;
 * either version 2.1 of the License, or (at your option) any later
 * version. See COPYING file for details.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *)

(* Keep that in sync with the list in discover.ml *)
let search_paths = [
  "/usr";
  "/usr/local";
  "/opt";
  "/opt/local";
  "/sw";
  "/mingw";
]

(* OASIS_START *)
(* DO NOT EDIT (digest: 4c177063a31680580ca13639e7a11972) *)
module OASISGettext = struct
# 21 "/home/chambart/bordel/oasis/oasis/src/oasis/OASISGettext.ml"
  
  let ns_ str = 
    str
  
  let s_ str = 
    str
  
  let f_ (str : ('a, 'b, 'c, 'd) format4) =
    str
  
  let fn_ fmt1 fmt2 n =
    if n = 1 then
      fmt1^^""
    else
      fmt2^^""
  
  let init = 
    []
  
end

module OASISExpr = struct
# 21 "/home/chambart/bordel/oasis/oasis/src/oasis/OASISExpr.ml"
  
  
  
  open OASISGettext
  
  type test = string 
  
  type flag = string 
  
  type t =
    | EBool of bool
    | ENot of t
    | EAnd of t * t
    | EOr of t * t
    | EFlag of flag
    | ETest of test * string
    
  
  type 'a choices = (t * 'a) list 
  
  let eval var_get t =
    let rec eval' = 
      function
        | EBool b ->
            b
  
        | ENot e -> 
            not (eval' e)
  
        | EAnd (e1, e2) ->
            (eval' e1) && (eval' e2)
  
        | EOr (e1, e2) -> 
            (eval' e1) || (eval' e2)
  
        | EFlag nm ->
            let v =
              var_get nm
            in
              assert(v = "true" || v = "false");
              (v = "true")
  
        | ETest (nm, vl) ->
            let v =
              var_get nm
            in
              (v = vl)
    in
      eval' t
  
  let choose ?printer ?name var_get lst =
    let rec choose_aux = 
      function
        | (cond, vl) :: tl ->
            if eval var_get cond then 
              vl 
            else
              choose_aux tl
        | [] ->
            let str_lst = 
              if lst = [] then
                s_ "<empty>"
              else
                String.concat 
                  (s_ ", ")
                  (List.map
                     (fun (cond, vl) ->
                        match printer with
                          | Some p -> p vl
                          | None -> s_ "<no printer>")
                     lst)
            in
              match name with 
                | Some nm ->
                    failwith
                      (Printf.sprintf 
                         (f_ "No result for the choice list '%s': %s")
                         nm str_lst)
                | None ->
                    failwith
                      (Printf.sprintf
                         (f_ "No result for a choice list: %s")
                         str_lst)
    in
      choose_aux (List.rev lst)
  
end


module BaseEnvLight = struct
# 21 "/home/chambart/bordel/oasis/oasis/src/base/BaseEnvLight.ml"
  
  module MapString = Map.Make(String)
  
  type t = string MapString.t
  
  let default_filename =
    Filename.concat 
      (Sys.getcwd ())
      "setup.data"
  
  let load ?(allow_empty=false) ?(filename=default_filename) () =
    if Sys.file_exists filename then
      begin
        let chn =
          open_in_bin filename
        in
        let st =
          Stream.of_channel chn
        in
        let line =
          ref 1
        in
        let st_line = 
          Stream.from
            (fun _ ->
               try
                 match Stream.next st with 
                   | '\n' -> incr line; Some '\n'
                   | c -> Some c
               with Stream.Failure -> None)
        in
        let lexer = 
          Genlex.make_lexer ["="] st_line
        in
        let rec read_file mp =
          match Stream.npeek 3 lexer with 
            | [Genlex.Ident nm; Genlex.Kwd "="; Genlex.String value] ->
                Stream.junk lexer; 
                Stream.junk lexer; 
                Stream.junk lexer;
                read_file (MapString.add nm value mp)
            | [] ->
                mp
            | _ ->
                failwith
                  (Printf.sprintf
                     "Malformed data file '%s' line %d"
                     filename !line)
        in
        let mp =
          read_file MapString.empty
        in
          close_in chn;
          mp
      end
    else if allow_empty then
      begin
        MapString.empty
      end
    else
      begin
        failwith 
          (Printf.sprintf 
             "Unable to load environment, the file '%s' doesn't exist."
             filename)
      end
  
  let var_get name env =
    let rec var_expand str =
      let buff =
        Buffer.create ((String.length str) * 2)
      in
        Buffer.add_substitute 
          buff
          (fun var -> 
             try 
               var_expand (MapString.find var env)
             with Not_found ->
               failwith 
                 (Printf.sprintf 
                    "No variable %s defined when trying to expand %S."
                    var 
                    str))
          str;
        Buffer.contents buff
    in
      var_expand (MapString.find name env)
  
  let var_choose lst env = 
    OASISExpr.choose
      (fun nm -> var_get nm env)
      lst
end


module MyOCamlbuildFindlib = struct
# 21 "/home/chambart/bordel/oasis/oasis/src/plugins/ocamlbuild/MyOCamlbuildFindlib.ml"
  
  (** OCamlbuild extension, copied from 
    * http://brion.inria.fr/gallium/index.php/Using_ocamlfind_with_ocamlbuild
    * by N. Pouillard and others
    *
    * Updated on 2009/02/28
    *
    * Modified by Sylvain Le Gall 
    *)
  open Ocamlbuild_plugin
  
  (* these functions are not really officially exported *)
  let run_and_read = 
    Ocamlbuild_pack.My_unix.run_and_read
  
  let blank_sep_strings = 
    Ocamlbuild_pack.Lexers.blank_sep_strings
  
  let split s ch =
    let x = 
      ref [] 
    in
    let rec go s =
      let pos = 
        String.index s ch 
      in
        x := (String.before s pos)::!x;
        go (String.after s (pos + 1))
    in
      try
        go s
      with Not_found -> !x
  
  let split_nl s = split s '\n'
  
  let before_space s =
    try
      String.before s (String.index s ' ')
    with Not_found -> s
  
  (* this lists all supported packages *)
  let find_packages () =
    List.map before_space (split_nl & run_and_read "ocamlfind list")
  
  (* this is supposed to list available syntaxes, but I don't know how to do it. *)
  let find_syntaxes () = ["camlp4o"; "camlp4r"]
  
  (* ocamlfind command *)
  let ocamlfind x = S[A"ocamlfind"; x]
  
  let dispatch =
    function
      | Before_options ->
          (* by using Before_options one let command line options have an higher priority *)
          (* on the contrary using After_options will guarantee to have the higher priority *)
          (* override default commands by ocamlfind ones *)
          Options.ocamlc     := ocamlfind & A"ocamlc";
          Options.ocamlopt   := ocamlfind & A"ocamlopt";
          Options.ocamldep   := ocamlfind & A"ocamldep";
          Options.ocamldoc   := ocamlfind & A"ocamldoc";
          Options.ocamlmktop := ocamlfind & A"ocamlmktop"
                                  
      | After_rules ->
          
          (* When one link an OCaml library/binary/package, one should use -linkpkg *)
          flag ["ocaml"; "link"; "program"] & A"-linkpkg";
          
          (* For each ocamlfind package one inject the -package option when
           * compiling, computing dependencies, generating documentation and
           * linking. *)
          List.iter 
            begin fun pkg ->
              flag ["ocaml"; "compile";  "pkg_"^pkg] & S[A"-package"; A pkg];
              flag ["ocaml"; "ocamldep"; "pkg_"^pkg] & S[A"-package"; A pkg];
              flag ["ocaml"; "doc";      "pkg_"^pkg] & S[A"-package"; A pkg];
              flag ["ocaml"; "link";     "pkg_"^pkg] & S[A"-package"; A pkg];
              flag ["ocaml"; "infer_interface"; "pkg_"^pkg] & S[A"-package"; A pkg];
            end 
            (find_packages ());
  
          (* Like -package but for extensions syntax. Morover -syntax is useless
           * when linking. *)
          List.iter begin fun syntax ->
          flag ["ocaml"; "compile";  "syntax_"^syntax] & S[A"-syntax"; A syntax];
          flag ["ocaml"; "ocamldep"; "syntax_"^syntax] & S[A"-syntax"; A syntax];
          flag ["ocaml"; "doc";      "syntax_"^syntax] & S[A"-syntax"; A syntax];
          flag ["ocaml"; "infer_interface"; "syntax_"^syntax] & S[A"-syntax"; A syntax];
          end (find_syntaxes ());
  
          (* The default "thread" tag is not compatible with ocamlfind.
           * Indeed, the default rules add the "threads.cma" or "threads.cmxa"
           * options when using this tag. When using the "-linkpkg" option with
           * ocamlfind, this module will then be added twice on the command line.
           *                        
           * To solve this, one approach is to add the "-thread" option when using
           * the "threads" package using the previous plugin.
           *)
          flag ["ocaml"; "pkg_threads"; "compile"] (S[A "-thread"]);
          flag ["ocaml"; "pkg_threads"; "link"] (S[A "-thread"]);
          flag ["ocaml"; "pkg_threads"; "infer_interface"] (S[A "-thread"])
  
      | _ -> 
          ()
  
end

module MyOCamlbuildBase = struct
# 21 "/home/chambart/bordel/oasis/oasis/src/plugins/ocamlbuild/MyOCamlbuildBase.ml"
  
  (** Base functions for writing myocamlbuild.ml
      @author Sylvain Le Gall
    *)
  
  
  
  open Ocamlbuild_plugin
  
  type dir = string 
  type file = string 
  type name = string 
  type tag = string 
  
# 55 "/home/chambart/bordel/oasis/oasis/src/plugins/ocamlbuild/MyOCamlbuildBase.ml"
  
  type t =
      {
        lib_ocaml: (name * dir list) list;
        lib_c:     (name * dir * file list) list; 
        flags:     (tag list * (spec OASISExpr.choices)) list;
      } 
  
  let env_filename =
    Pathname.basename 
      BaseEnvLight.default_filename
  
  let dispatch_combine lst =
    fun e ->
      List.iter 
        (fun dispatch -> dispatch e)
        lst 
  
  let dispatch t e = 
    let env = 
      BaseEnvLight.load 
        ~filename:env_filename 
        ~allow_empty:true
        ()
    in
      match e with 
        | Before_options ->
            let no_trailing_dot s =
              if String.length s >= 1 && s.[0] = '.' then
                String.sub s 1 ((String.length s) - 1)
              else
                s
            in
              List.iter
                (fun (opt, var) ->
                   try 
                     opt := no_trailing_dot (BaseEnvLight.var_get var env)
                   with Not_found ->
                     Printf.eprintf "W: Cannot get variable %s" var)
                [
                  Options.ext_obj, "ext_obj";
                  Options.ext_lib, "ext_lib";
                  Options.ext_dll, "ext_dll";
                ]
  
        | After_rules -> 
            (* Declare OCaml libraries *)
            List.iter 
              (function
                 | lib, [] ->
                     ocaml_lib lib;
                 | lib, dir :: tl ->
                     ocaml_lib ~dir:dir lib;
                     List.iter 
                       (fun dir -> 
                          flag 
                            ["ocaml"; "use_"^lib; "compile"] 
                            (S[A"-I"; P dir]))
                       tl)
              t.lib_ocaml;
  
            (* Declare C libraries *)
            List.iter
              (fun (lib, dir, headers) ->
                   (* Handle C part of library *)
                   flag ["link"; "library"; "ocaml"; "byte"; "use_lib"^lib]
                     (S[A"-dllib"; A("-l"^lib); A"-cclib"; A("-l"^lib)]);
  
                   flag ["link"; "library"; "ocaml"; "native"; "use_lib"^lib]
                     (S[A"-cclib"; A("-l"^lib)]);
                        
                   flag ["link"; "program"; "ocaml"; "byte"; "use_lib"^lib]
                     (S[A"-dllib"; A("dll"^lib)]);
  
                   (* When ocaml link something that use the C library, then one
                      need that file to be up to date.
                    *)
                   dep  ["link"; "ocaml"; "use_lib"^lib] 
                     [dir/"lib"^lib^"."^(!Options.ext_lib)];
  
                   (* TODO: be more specific about what depends on headers *)
                   (* Depends on .h files *)
                   dep ["compile"; "c"] 
                     headers;
  
                   (* Setup search path for lib *)
                   flag ["link"; "ocaml"; "use_"^lib] 
                     (S[A"-I"; P(dir)]);
              )
              t.lib_c;
  
              (* Add flags *)
              List.iter
              (fun (tags, cond_specs) ->
                 let spec = 
                   BaseEnvLight.var_choose cond_specs env
                 in
                   flag tags & spec)
              t.flags
        | _ -> 
            ()
  
  let dispatch_default t =
    dispatch_combine 
      [
        dispatch t;
        MyOCamlbuildFindlib.dispatch;
      ]
  
end


open Ocamlbuild_plugin;;
let package_default =
  {
     MyOCamlbuildBase.lib_ocaml =
       [
          ("src/core/lwt", ["src/core"]);
          ("src/unix/lwt-unix", ["src/unix"]);
          ("src/react/lwt-react", ["src/react"]);
          ("tests/test", ["tests"]);
          ("src/text/lwt-text", ["src/text"]);
          ("syntax/lwt-syntax", ["syntax"]);
          ("src/top/lwt-top", ["src/top"]);
          ("src/preemptive/lwt-preemptive", ["src/preemptive"]);
          ("src/simple_top/lwt-simple-top", ["src/simple_top"]);
          ("src/glib/lwt-glib", ["src/glib"]);
          ("syntax/lwt-syntax-log", ["syntax"]);
          ("src/extra/lwt-extra", ["src/extra"]);
          ("syntax/optcomp", ["syntax"]);
          ("syntax/lwt-syntax-options", ["syntax"]);
          ("src/ssl/lwt-ssl", ["src/ssl"])
       ];
     lib_c =
       [
          ("lwt-unix",
            "src/unix",
            ["src/unix/lwt_config.h"; "src/unix/lwt_unix.h"]);
          ("lwt-text", "src/text", []);
          ("lwt-glib", "src/glib", [])
       ];
     flags =
       [
          (["oasis_library_lwt_unix_cclib"; "link"],
            [
               (OASISExpr.EBool true, S []);
               (OASISExpr.EFlag "libev", S [A "-cclib"; A "-lev"]);
               (OASISExpr.ENot (OASISExpr.ETest ("os_type", "Win32")),
                 S [A "-cclib"; A "-lpthread"]);
               (OASISExpr.EAnd
                  (OASISExpr.ENot (OASISExpr.ETest ("os_type", "Win32")),
                    OASISExpr.EFlag "libev"),
                 S [A "-cclib"; A "-lpthread"; A "-cclib"; A "-lev"]);
               (OASISExpr.ETest ("os_type", "Win32"),
                 S [A "-cclib"; A "ws2_32.lib"]);
               (OASISExpr.EAnd
                  (OASISExpr.ETest ("os_type", "Win32"),
                    OASISExpr.EFlag "libev"),
                 S [A "-cclib"; A "ws2_32.lib"; A "-cclib"; A "-lev"]);
               (OASISExpr.EAnd
                  (OASISExpr.ETest ("os_type", "Win32"),
                    OASISExpr.ENot (OASISExpr.ETest ("os_type", "Win32"))),
                 S [A "-cclib"; A "ws2_32.lib"; A "-cclib"; A "-lpthread"]);
               (OASISExpr.EAnd
                  (OASISExpr.EAnd
                     (OASISExpr.ETest ("os_type", "Win32"),
                       OASISExpr.ENot (OASISExpr.ETest ("os_type", "Win32"))),
                    OASISExpr.EFlag "libev"),
                 S
                   [
                      A "-cclib";
                      A "ws2_32.lib";
                      A "-cclib";
                      A "-lpthread";
                      A "-cclib";
                      A "-lev"
                   ])
            ]);
          (["oasis_library_lwt_unix_cclib"; "ocamlmklib"; "c"],
            [
               (OASISExpr.EBool true, S []);
               (OASISExpr.EFlag "libev", S [A "-lev"]);
               (OASISExpr.ENot (OASISExpr.ETest ("os_type", "Win32")),
                 S [A "-lpthread"]);
               (OASISExpr.EAnd
                  (OASISExpr.ENot (OASISExpr.ETest ("os_type", "Win32")),
                    OASISExpr.EFlag "libev"),
                 S [A "-lpthread"; A "-lev"]);
               (OASISExpr.ETest ("os_type", "Win32"), S [A "ws2_32.lib"]);
               (OASISExpr.EAnd
                  (OASISExpr.ETest ("os_type", "Win32"),
                    OASISExpr.EFlag "libev"),
                 S [A "ws2_32.lib"; A "-lev"]);
               (OASISExpr.EAnd
                  (OASISExpr.ETest ("os_type", "Win32"),
                    OASISExpr.ENot (OASISExpr.ETest ("os_type", "Win32"))),
                 S [A "ws2_32.lib"; A "-lpthread"]);
               (OASISExpr.EAnd
                  (OASISExpr.EAnd
                     (OASISExpr.ETest ("os_type", "Win32"),
                       OASISExpr.ENot (OASISExpr.ETest ("os_type", "Win32"))),
                    OASISExpr.EFlag "libev"),
                 S [A "ws2_32.lib"; A "-lpthread"; A "-lev"])
            ])
       ];
     }
  ;;

let dispatch_default = MyOCamlbuildBase.dispatch_default package_default;;

(* OASIS_STOP *)

open Ocamlbuild_plugin

let pkg_config flags =
  with_temp_file "lwt" "pkg-config"
    (fun tmp ->
       Command.execute ~quiet:true & Cmd(S[A "pkg-config"; S flags; Sh ">"; A tmp]);
       List.map (fun arg -> A arg) (string_list_of_file tmp))

let define_c_library ?(msvc = false) ~name ~c_name () =
  let tag = Printf.sprintf "use_C_%s" name in

  (* Get compile flags. *)
  let opt = pkg_config [A "--cflags"; A c_name] in

  (* Get linking flags. *)
  let lib =
    if msvc then
      (* With msvc we need to pass "glib-2.0.lib" instead of
         "-lglib-2.0" otherwise executables will fail. *)
      pkg_config [A "--libs-only-L"; A c_name] @ pkg_config [A "--libs-only-l"; A "--msvc-syntax"; A c_name]
    else
      pkg_config [A "--libs"; A c_name]
  in

  (* Add flags for linking with the C library: *)
  flag ["ocamlmklib"; "c"; tag] & S lib;

  (* C stubs using the C library must be compiled with the library
     specifics flags: *)
  flag ["c"; "compile"; tag] & S (List.map (fun arg -> S[A"-ccopt"; arg]) opt);

  (* OCaml libraries must depends on the C library: *)
  flag ["link"; "ocaml"; tag] & S (List.map (fun arg -> S[A"-cclib"; arg]) lib)

let () =
  dispatch
    (fun hook ->
       dispatch_default hook;
       match hook with
         | Before_options ->
             Options.make_links := false

         | After_rules ->
             dep ["file:src/unix/lwt_unix_stubs.c"] ["src/unix/lwt_unix_unix.c"; "src/unix/lwt_unix_windows.c"];
             dep ["pa_optcomp"] ["src/unix/lwt_config.ml"];

             (* Internal syntax extension *)
             List.iter
               (fun base ->
                  let tag = "pa_" ^ base and file = "syntax/pa_" ^ base ^ ".cmo" in
                  flag ["ocaml"; "compile"; tag] & S[A"-ppopt"; A file];
                  flag ["ocaml"; "ocamldep"; tag] & S[A"-ppopt"; A file];
                  flag ["ocaml"; "doc"; tag] & S[A"-ppopt"; A file];
                  dep ["ocaml"; "ocamldep"; tag] [file])
               ["lwt_options"; "lwt"; "lwt_log"; "optcomp"];

             (* Optcomp for .mli *)
             flag ["ocaml"; "compile"; "pa_optcomp_standalone"] & S[A"-pp"; A "./syntax/optcomp.byte"];
             flag ["ocaml"; "ocamldep"; "pa_optcomp_standalone"] & S[A"-pp"; A "./syntax/optcomp.byte"];
             flag ["ocaml"; "doc"; "pa_optcomp_standalone"] & S[A"-pp"; A "./syntax/optcomp.byte"];
             dep ["ocaml"; "ocamldep"; "pa_optcomp_standalone"] ["syntax/optcomp.byte"];

             (* Use an introduction page with categories *)
             tag_file "lwt-api.docdir/index.html" ["apiref"];
             dep ["apiref"] ["apiref-intro"];
             flag ["apiref"] & S[A "-intro"; P "apiref-intro"; A"-colorize-code"];

             (* Glib bindings: *)
             let env = BaseEnvLight.load ~allow_empty:true ~filename:MyOCamlbuildBase.env_filename () in
             let msvc = BaseEnvLight.var_get "ccomp_type" env = "msvc" in
             if BaseEnvLight.var_get "glib" env = "true" || BaseEnvLight.var_get "all" env = "true" then
               define_c_library ~msvc ~name:"glib" ~c_name:"glib-2.0" ();

             let opts = S[A "-ppopt"; A "-let"; A "-ppopt"; A ("windows=" ^ if BaseEnvLight.var_get "os_type" env <> "Unix" then "true" else "false")] in
             flag ["ocaml"; "compile"; "pa_optcomp"] & opts;
             flag ["ocaml"; "ocamldep"; "pa_optcomp"] & opts;
             (*flag ["ocaml"; "doc"; "pa_optcomp"] & opts; Does not work... *)

             flag ["ocaml"; "link"; "toplevel"] & A"-linkpkg";

             let env = BaseEnvLight.load () in
             let stdlib_path = BaseEnvLight.var_get "standard_library" env in

             (* Try to find the path where compiler libraries are: *)
             let compiler_libs =
               let stdlib = String.chomp stdlib_path in
               try
                 let path =
                   List.find Pathname.exists [
                     stdlib / "compiler-libs";
                     stdlib / "compiler-lib";
                     stdlib / ".." / "compiler-libs";
                     stdlib / ".." / "compiler-lib";
                   ]
                 in
                 path :: List.filter Pathname.exists [ path / "typing"; path / "utils"; path / "parsing" ]
               with Not_found ->
                 []
             in

             (* Add directories for compiler-libraries: *)
             let paths = List.map (fun path -> S[A"-I"; A path]) compiler_libs in
             List.iter
               (fun stage -> flag ["ocaml"; stage; "use_compiler_libs"] & S paths)
               ["compile"; "ocamldep"; "doc"; "link"];

             dep ["file:src/top/toplevel_temp.top"] ["src/core/lwt.cma";
                                                     "src/react/lwt-react.cma";
                                                     "src/unix/lwt-unix.cma";
                                                     "src/text/lwt-text.cma";
                                                     "src/top/lwt-top.cma"];

             flag ["file:src/top/toplevel_temp.top"] & S[A"-I"; A"src/unix";
                                                         A"-I"; A"src/text";
                                                         A"src/core/lwt.cma";
                                                         A"src/react/lwt-react.cma";
                                                         A"src/unix/lwt-unix.cma";
                                                         A"src/text/lwt-text.cma";
                                                         A"src/top/lwt-top.cma"];

             (* Expunge compiler modules *)
             rule "toplevel expunge"
               ~dep:"src/top/toplevel_temp.top"
               ~prod:"src/top/lwt_toplevel.byte"
               (fun _ _ ->
                  let directories =
                    stdlib_path
                    :: "src/core"
                    :: "src/react"
                    :: "src/unix"
                    :: "src/text"
                    :: "src/top"
                    :: (List.map
                          (fun lib ->
                             String.chomp
                               (run_and_read
                                  ("ocamlfind query " ^ lib)))
                          ["findlib"; "react"; "unix"; "text"])
                  in
                  let modules =
                    List.fold_left
                      (fun set directory ->
                         List.fold_left
                           (fun set fname ->
                              if Pathname.check_extension fname "cmi" then
                                StringSet.add (module_name_of_pathname fname) set
                              else
                                set)
                           set
                           (Array.to_list (Pathname.readdir directory)))
                      StringSet.empty directories
                  in
                  Cmd(S[A(stdlib_path / "expunge");
                        A"src/top/toplevel_temp.top";
                        A"src/top/lwt_toplevel.byte";
                        A"outcometree"; A"topdirs"; A"toploop";
                        S(List.map (fun x -> A x) (StringSet.elements modules))]));

             (* Search for a header file in standard directories. *)
             let search_header header =
               let rec loop = function
                 | [] ->
                     None
                 | dir :: dirs ->
                     if Sys.file_exists (dir ^ "/include/" ^ header) then
                       Some dir
                     else
                       loop dirs
               in
               loop search_paths
             in

             (* Add directories for libev and pthreads *)
             let flags dir =
               flag ["ocamlmklib"; "c"; "use_stubs"] & A("-L" ^ dir ^ "/lib");
               flag ["c"; "compile"; "use_stubs"] & S[A"-ccopt"; A("-I" ^ dir ^ "/include")];
               flag ["link"; "ocaml"; "use_stubs"] & S[A"-cclib"; A("-L" ^ dir ^ "/lib")]
             in
             begin
               match search_header "ev.h", search_header "pthread.h" with
                 | None, None -> ()
                 | Some path, None | None, Some path -> flags path
                 | Some path1, Some path2 when path1 = path2 -> flags path1
                 | Some path1, Some path2 -> flags path1; flags path2
             end

         | _ ->
             ())

