aantron / luv

Cross-platform asynchronous I/O and system calls
https://aantron.github.io/luv
MIT License
276 stars 26 forks source link

Attempt to `#require "luv"` in OCaml toplevel fails on Windows #142

Open polytypic opened 1 year ago

polytypic commented 1 year ago

An attempt to #require "luv" in OCaml toplevel fails on Windows. Here is sample output:

OCaml version 4.14.0
Enter #help;; for help.

# #use "topfind";;
- : unit = ()
Findlib has been successfully loaded. Additional directives:
  #require "package";;      to load a package
  #list;;                   to list the available packages
  #camlp4o;;                to load camlp4 (standard syntax)
  #camlp4r;;                to load camlp4 (revised syntax)
  #predicates "p,q,...";;   to set these predicates
  Topfind.reset();;         to force that packages will be reloaded
  #thread;;                 to enable threads

- : unit = ()
# #require "luv";;
C:\Users\polytypic\work\opamroot\4.14.0\lib\bigarray-compat: added to search path
C:\Users\polytypic\work\opamroot\4.14.0\lib\bigarray-compat\bigarray_compat.cma: loaded
C:\Users\polytypic\work\opamroot\4.14.0\lib\bytes: added to search path
C:\Users\polytypic\work\opamroot\4.14.0\lib\stdlib-shims: added to search path
C:\Users\polytypic\work\opamroot\4.14.0\lib\stdlib-shims\stdlib_shims.cma: loaded
C:\Users\polytypic\work\opamroot\4.14.0\lib\integers: added to search path
C:\Users\polytypic\work\opamroot\4.14.0\lib\integers\integers.cma: loaded
C:\Users\polytypic\work\opamroot\4.14.0\lib\ctypes: added to search path
C:\Users\polytypic\work\opamroot\4.14.0\lib\ctypes\ctypes.cma: loaded
C:\Users\polytypic\work\opamroot\4.14.0\lib\ctypes\ctypes-top.cma: loaded
C:\Users\polytypic\work\opamroot\4.14.0\lib\luv\c_type_descriptions: added to search path
C:\Users\polytypic\work\opamroot\4.14.0\lib\luv\c_type_descriptions\luv_c_type_descriptions.cma: loaded
C:\Users\polytypic\work\opamroot\4.14.0\lib\luv\c_function_descriptions: added to search path
C:\Users\polytypic\work\opamroot\4.14.0\lib\luv\c_function_descriptions\luv_c_function_descriptions.cma: loaded
C:\Users\polytypic\work\opamroot\4.14.0\lib\ocaml: added to search path
C:\Users\polytypic\work\opamroot\4.14.0\lib\luv\c: added to search path
C:\Users\polytypic\work\opamroot\4.14.0\lib\luv\c\luv_c.cma: loaded
No master relocation table
Cannot load required shared library dllluv_c_stubs.
Reason: C:\Users\polytypic\work\opamroot\4.14.0\lib/stublibs\dllluv_c_stubs.dll: Cannot resolve ntohs.
C:\Users\polytypic\work\opamroot\4.14.0\lib\result: added to search path
C:\Users\polytypic\work\opamroot\4.14.0\lib\result\result.cma: loaded
C:\Users\polytypic\work\opamroot\4.14.0\lib\luv: added to search path
C:\Users\polytypic\work\opamroot\4.14.0\lib\luv\luv.cma: loaded
Line 1:
Error: Reference to undefined global `Luv_c_generated_functions'

The same seems to happen with other OCaml tools (I've tested utop and mdx) that run OCaml bytecode and also with other OCaml versions (I've tested with 5.0.0).

The No master relocation table message seems to point to flexdll which is used by OCaml on Windows.

I don't know how to exactly fix this problem, but my understanding is that with flexdll one needs to link applications and libraries using the special flexlink tool.

polytypic commented 1 year ago

I made an experiment to try to use Ctypes to link to a custom DLL on Windows such that the result OCaml library could be loaded in the OCaml toplevel on Windows. It seems to work! (~Well, building via opam pin . -y still fails for some reason. That seems to be a problem with a specific OCaml switch.~)

polytypic commented 1 year ago

With an ugly hack to use flexlink in dune (replacing libtool invocation)

   (bash
    "x86_64-w64-mingw32-ar rcs libuv.a `find src -path '*/.libs/*.o'`")
   (bash
    "flexlink -chain mingw64 -o dlluv.dll `find src -path '*/.libs/*.o'`")

and manual addition of two prototypes with __declspec(dllimport)

extern __declspec(dllimport) _NETIOAPI_SUCCESS_ NETIOAPI_API ConvertInterfaceIndexToLuid(
    NET_IFINDEX InterfaceIndex,
    PNET_LUID   InterfaceLuid
);

extern __declspec(dllimport) _NETIOAPI_SUCCESS_ NETIOAPI_API ConvertInterfaceLuidToNameW(
    const NET_LUID *InterfaceLuid,
    PWSTR          InterfaceName,
    SIZE_T         Length
);

I managed to build luv such that I could #require "luv" in Windows:

C:\Users\polytypic\work\luv>dune utop
────────────────────────┬──────────────────────────────────────────────────────────────┬────────────────────────
                        │ Welcome to utop version 2.10.0 (using OCaml version 4.14.0)! │
                        └──────────────────────────────────────────────────────────────┘

Type #utop_help for help about using utop.

─( 15:18:20 )─< command 0 >──────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # #require "luv";;
─( 15:18:21 )─< command 1 >──────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop #

Obviously some fine tuning is needed for a proper PR.