(* -*- tuareg -*- *)

(* To make this build verbose:

   1. dune build -p luv -j 1 --verbose --no-buffer
   2. Remove --silent and --enable-silent-rules from sh configure
   3. Pass V=1 instead of V=0 to make
   4. Remove --silent --no-warnings from sh libtool
   5. Unwrap all the commands from (ignore-outputs ...) *)

let foreign_archives, uv_library_flag, include_dirs, i_option, install_h =
  let use_system_libuv =
    match Sys.getenv "LUV_USE_SYSTEM_LIBUV" with
    | "yes" -> true
    | _ -> false
    | exception Not_found -> false
  in

  if use_system_libuv then
    "",
    "-luv",
    "",
    "",
    false
  else
    "(foreign_archives uv)",
    "",
    "(include_dirs vendor/libuv/include)",
    "-I .",
    true

let () = Jbuild_plugin.V1.send @@ {|

; The final FFI module, containing all the OCaml bits, and linked with libuv.
(library
 (name luv_c)
 (public_name luv.c)
 (wrapped false)
 (modules Luv_c_generated_functions)
 (libraries ctypes luv_c_function_descriptions threads)
 (foreign_stubs
  (language c)
  (names c_generated_functions helpers)
  |}^ include_dirs ^{|)
 |}^ foreign_archives ^{|
 (c_library_flags |}^ uv_library_flag ^{| (:include extra_libs.sexp)))

|}^ (if not install_h then "" else {|

(rule
 (deps (glob_files uv/*.h))
 (action (copy vendor/libuv/include/uv.h uv.h)))

(install
 (section lib)
 (package luv)
 (files
  (uv.h as uv.h)
  (uv/aix.h as uv/aix.h)
  (uv/bsd.h as uv/bsd.h)
  (uv/darwin.h as uv/darwin.h)
  (uv/errno.h as uv/errno.h)
  (uv/linux.h as uv/linux.h)
  (uv/os390.h as uv/os390.h)
  (uv/posix.h as uv/posix.h)
  (uv/sunos.h as uv/sunos.h)
  (uv/threadpool.h as uv/threadpool.h)
  (uv/tree.h as uv/tree.h)
  (uv/unix.h as uv/unix.h)
  (uv/version.h as uv/version.h)
  (uv/win.h as uv/win.h)))

|}) ^{|



; The vendored libuv.
(rule
 (targets libuv.a dlluv%{ext_dll})
 (deps (source_tree vendor))
 (action (progn
  (bash "cp -r vendor/configure/* vendor/libuv/")
  (chdir vendor/libuv (progn
   (bash
    "sh configure --host `ocamlc -config | awk '/^host:/ {print $NF}'` \
      'CC=%{cc}' CFLAGS=-DNDEBUG --silent --enable-silent-rules")
   (ignore-outputs (bash
    "$([ '%{os_type}' = Unix ] && echo %{make} || echo make) V=0 -j 4 \
      -o aclocal.m4 -o Makefile.in -o configure \
      -o configure.status -o Makefile libuv.la"))
   (ignore-outputs (bash
    "sh libtool --silent --no-warnings --mode install cp libuv.la `pwd`"))))
  (bash "cp vendor/libuv/libuv.a .")
  (ignore-outputs (bash
   "cp vendor/libuv/libuv.so.1.0.0 dlluv.so || \
    cp vendor/libuv/libuv.1.dylib dlluv.so || \
    cp vendor/bin/libuv-1.dll dlluv.dll")))))

(rule
 (targets extra_libs.sexp)
 (action (ignore-outputs (bash "\
   if ocamlc -config | grep mingw; then \
     echo '(-ldbghelp -liphlpapi -lole32 -lpsapi -luserenv)' > extra_libs.sexp; \
   else \
     echo '()' > extra_libs.sexp; \
   fi"))))



; Everything below is the bindings generation process using ctypes. It produces
; two OCaml modules, Luv_c_generated_functions and Luv_c_generated_types.

; Type bindings (Luv_c_generated_types).
(library
 (name luv_c_type_descriptions)
 (public_name luv.c_type_descriptions)
 (modules Luv_c_type_descriptions)
 (libraries ctypes))

(executable
 (name generate_types_start)
 (modules Generate_types_start)
 (libraries ctypes.stubs luv_c_type_descriptions))

(rule
 (with-stdout-to generate_types_step_2.c
  (run ./generate_types_start.exe)))

; Based partially on
;   https://github.com/avsm/ocaml-yaml/blob/master/types/stubgen/jbuild#L20
(rule
 (targets generate_types_step_2.exe)
 (deps (:c generate_types_step_2.c) helpers.h shims.h)
 (action (bash "\
  if [ '%{ocaml-config:ccomp_type}' = 'msvc' ]; then \
    %{cc} %{c} \
    -I '%{lib:ctypes:.}' \
    -I '%{ocaml_where}' \
    |}^ i_option ^{| /Fe\"%{targets}\"; \
  else \
    %{cc} %{c} \
    -I '%{lib:ctypes:.}' \
    -I '%{ocaml_where}' \
    |}^ i_option ^{| -o %{targets}; \
  fi")))

(rule
 (with-stdout-to luv_c_generated_types.ml
  (run ./generate_types_step_2.exe)))

; Function bindings.
(library
 (name luv_c_function_descriptions)
 (public_name luv.c_function_descriptions)
 (flags (:standard -w -9-16-27))
 (wrapped false)
 (modules Luv_c_generated_types Luv_c_function_descriptions Luv_c_types)
 (libraries ctypes luv_c_type_descriptions))

(executable
 (name generate_c_functions)
 (modules Generate_c_functions)
 (libraries ctypes.stubs luv_c_function_descriptions))

(executable
 (name generate_ml_functions)
 (modules Generate_ml_functions)
 (libraries ctypes.stubs luv_c_function_descriptions))

(rule
 (with-stdout-to c_generated_functions.c
  (run ./generate_c_functions.exe luv_stub)))

(rule
 (with-stdout-to luv_c_generated_functions.ml
  (run ./generate_ml_functions.exe luv_stub)))

|}
