paurkedal / ocaml-caqti

Cooperative-threaded access to relational data
https://paurkedal.github.io/ocaml-caqti/index.html
GNU Lesser General Public License v3.0
307 stars 36 forks source link

Crashes when used via jbuilder utop #9

Closed bobbypriam closed 6 years ago

bobbypriam commented 6 years ago

I hope you don't mind me creating another issue...

─( 19:34:13 )─< command 3 >────────────────────────────────────────────────{ counter: 0 }─
utop # Caqti_lwt.connect (Uri.of_string "postgresql://localhost:5432");;
Exception:
Invalid_argument
 "The dynlink.cma library cannot be used inside the OCaml toplevel".
Raised at file "pervasives.ml", line 33, characters 25-45
Called from file "otherlibs/dynlink/dynlink.ml", line 148, characters 4-97
Called from file "otherlibs/dynlink/dynlink.ml", line 261, characters 2-8
Called from file "list.ml", line 85, characters 12-15
Called from file "fl_dynload.ml", line 37, characters 5-227
Called from file "list.ml", line 85, characters 12-15
Called from file "lib-dynload/caqti_dynload.ml", line 65, characters 10-49
Called from file "lib/caqti_connect.ml", line 31, characters 13-56
Called from file "lib/caqti_connect.ml", line 57, characters 19-50
Called from file "lib/caqti_connect.ml", line 104, characters 11-26
Called from file "//toplevel//", line 1, characters 0-63
Called from file "toplevel/toploop.ml", line 180, characters 17-56

It seems to be related to the dynamic linking. Do you perhaps know how to use it via utop? Here's my current jbuild file:

(jbuild_version 1)

(library
  ((name app)
   (wrapped false)
   (libraries
     (opium lwt lwt.unix
      caqti caqti-dynload caqti-lwt))
   (preprocess (pps (lwt.ppx)))))
paurkedal commented 6 years ago

To run it from utop, link with the specific database instead of using caqti-dynload:

─( 19:21:44 )─< command 0 >───────────────────────────────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # #require "caqti-lwt";;
─( 19:21:44 )─< command 1 >───────────────────────────────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # #require "caqti-driver-postgresql";;
─( 19:21:55 )─< command 2 >───────────────────────────────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # Caqti_lwt.connect (Uri.of_string "postgresql://");;
- : (Caqti_lwt.connection, [> Caqti_error.load_or_connect ]) result =
Ok <module>

I'll add that to the README, and yes requests for documentation are welcome too.

bobbypriam commented 6 years ago

I see, thanks for the clarification.

Can we also bypass caqti-dynload altogether on our project? Say if I already know I want to use postgresql instead of determining dynamically via the connection string. I've tried putting this on my jbuild file:

   (libraries
     (...
      caqti caqti-driver-postgresql caqti-lwt))

But it crashes at runtime saying "Failed to load driver for <postgresql://localhost:5432>: Neither caqti-driver-postgresql nor the dynamic linker is linked into the application.".

The README mentioned about statically linking the driver but I can't seem to find out how to do that.

The reason I am trying to do this is, instead of plain utop, I use jbuilder utop which conveniently requires the dependencies specified in the jbuild file. Using only utop requires me to enumerate the dependencies like you did, which is kind of a chore if your deps list is getting bigger...

paurkedal commented 6 years ago

That should work. Can you try to add (flags (-linkall))? I should maybe add (library_flags (-linkall)) to the driver, or export a global dummy identifier in the driver which can be referenced from initialisation code.

bobbypriam commented 6 years ago

Okay I'll try that as soon as I get to my personal laptop.

bobbypriam commented 6 years ago

Setting (flags (-linkall)) didn't seem to work. I've also tried (flags (:standard -linkall)) as per the jbuilder docs' recommendation, but no luck either. As an extra effort I also tried (no_dynlink) as stated in the jbuild specification, also with no result.

As a reference, here's my full jbuild file:

(jbuild_version 1)

(library
  ((name app)
   (wrapped false)
   (libraries
     (opium lwt lwt.unix
      caqti caqti-driver-postgresql caqti-lwt))
   (flags (-linkall))
   (preprocess (pps (lwt.ppx)))))
paurkedal commented 6 years ago

I see, the problem is that the -linkall must be passed when building the driver library (or maybe on the executable, but putting it on an intermediate library does not help). I have fixed it in master, so can you try to pin the --dev-repo? There is a workaround of adding an module Foo = struct include Caqti_driver_postgresql end, in the main program, but maybe you can keep it pinned until I will release an update. The reference to static linking in the README was just wrong, so I removed it. And thanks for the hint about :standard!

bobbypriam commented 6 years ago

Can confirm that pinning --dev-repo works! Really appreciate the help.