0

How can I compile a jocaml source file which needs the cryptokit package (successfully compiled with the companion ocaml) with the ocamlbuild tool?

When I execute the command ocamlbuild -pkg cryptokit -use-jocaml a.native I get this error:

Warning: tag "package" does not expect a parameter, but is used with parameter "cryptokit"¬
+ jocamlopt -I /prefix/lib/ocaml -I /prefix/lib/ocaml/site-lib/cryptokit -I /prefix/lib/ocaml/site-lib/num /prefix/lib/ocaml/unix.cmxa /prefix/lib/ocaml/nums.cmxa /prefix/lib/ocaml/site-lib/cryptokit/cryptokit.cmxa a.cmx -o a.native¬
File "_none_", line 1:¬ 
Error: Files /prefix/lib/ocaml/unix.cmxa¬
       and /prefix/lib/ocaml/unix.cmxa¬
              both define a module named Unix¬
              Command exited with code 2.¬ 
              Compilation unsuccessful after building 4 targets (3 cached) in 00:00:00.

Essentially, the ocaml Unix module clashes with himself. This error only pops when I include Cryptokit (with -pkg cryptokit) probably because Cryptokit requires Unix. a.ml can in fact be empty and still reproduce the error.

I tried to add the -use-ocamlfind flag but as it also uses ocamlfind to get the compiler, it selects the ocaml compiler instead of the jocaml one.

By executing sequentially the same commands as ocamlbuild (displayed by -verbose 1), I got that when I execute the last one without /.../unix.cmxa then there is no more clash, but the wrong Unix module is loaded: it's the one from ocaml and not from jocaml, so it it completely crashes when I use any jocaml feature in a.ml:

jocamlopt -I /prefix/lib/ocaml -I /prefix/lib/ocaml/site-lib/cryptokit -I /prefix/lib/ocaml/site-lib/num /prefix/lib/ocaml/nums.cmxa /prefix/lib/ocaml/site-lib/cryptokit/cryptokit.cmxa a.cmx -o a.native

However, when I also remove the -I /prefix/lib/ocaml part, then it compiles successfully:

jocamlopt -I /prefix/lib/ocaml/site-lib/cryptokit -I /prefix/lib/ocaml/site-lib/num /prefix/lib/ocaml/nums.cmxa /prefix/lib/ocaml/site-lib/cryptokit/cryptokit.cmxa a.cmx -o a.native

To summarize, I got it to work by executing manually a modification of the last command, but I would like to get ocamlbuild working.

I think this error has to do with the fact that Cryptokit requires the Unix module: as I compiled it with ocaml and not jocaml, at the linking stage it tries to link with the ocaml stdlib one (which needs to be included) and not the jocaml stdlib one (which is implicitly included as part of the stdlib).

Lapinot
  • 1,305
  • 2
  • 9
  • 11

2 Answers2

1

I had no idea there were active users of the ocamlbuild+JOcaml combination! By curiosity, would you say a bit more about what you are using JOCaml+cryptokit for?

I don't know much about Cryptokit or JOCaml, but it looks like your main problem is not related to ocamlbuild. If I understand correctly, (1) Cryptokit needs Unix and (2) JOCaml needs to use its own variant of Unix. If this is correct, compiling Cryptokit against ocaml's Unix and expecting it to work when linked with a JOCaml program that itself requires JOCaml's Unix is bound to create a lot of trouble. If this work in your case, it must be because either the part of Cryptokit you use doesn't actually require Unix, or the JOCaml program you are testing with does not actually require JOCaml's Unix. In the long run, it would probably be best to compile Cryptokit with JOCaml directly (I don't know how comfortable you are with the OCaml ecosystem in general, but I would personally try to build an OPAM switch where ocaml{c,opt} are aliases for jocaml{c,opt} and build programs from that).

Regarding the ocamlbuild specific part, it's hard to give any accurate advice without a tarball to be able to reproduce your setup and experiment with it. But I would try one of the two following options:

  • You can use -use-ocamlfind and teach ocamlfind to use jocaml instead of ocaml by using the OCAMLFIND_COMMANDS environment variable (see man ocamlfind)
  • You can avoid -use-ocamlfind entirely and instead call ocamlfind as a command-line tool to get the location of the cryptokit library (ocamlfind query cryptokit). You would then not use -pkg cryptokit but pass the path yourself (with -lflags and -cflags or by modifying your myocamlbuild.ml configuration file).
gasche
  • 31,259
  • 3
  • 78
  • 100
  • Actually I think I am quite alone in the active user community ;) I am using cryptokit+jocaml for a student project of distributed rainbow tables (generating and searching in rainbow tables with a computer cluster) (I know rainbow tables are obsolete!). Regarding the hacky linking against not-the-right Unix module: this is said to be supported by the jocaml devs: "binary compatibility for matching versions" (I mean: it's ugly but it works :D). There is an official ocaml+jocaml opam switch but it is buggy. – Lapinot Oct 30 '15 at 16:29
  • I just tried to install cryptokit from the jocaml switch, and indeed it doesn't work. jocaml does not include a lot of the stuff taken for granted of OCaml compilers (eg. `ocamldoc`), so it doesn't work very well as a stand-alone compiler. – gasche Oct 30 '15 at 17:59
  • Would you post a minimal source somewhere that I could use to test your ocamlbuild+jocaml failure? – gasche Oct 30 '15 at 18:01
  • Actually an empty file does the work, if you want to be sure its compiled with jocaml and cryptokit you can add the `open Cryptokit` and `def foo() = 0` lines. Actually the bugs only comes when requiring `unix` package (directly or indirectly): eg `ocamlbuild -use-jocaml -use-ocamlfind -pkg unix foo.ml` – Lapinot Oct 30 '15 at 18:36
0

Elaborating on the -use-ocamlfind option as suggested by gasche, I got it to work with the addition of a small nasty hack: removing "unix" from the requires field of the META file of the cryptokit package. It works because jocaml links everything with threads and unix by default (a real solution would have been to disable this behavior, but it seems a lot harder). So the working compilation command is:

ocamlbuild -use-ocamlfind -use-jocaml -pkg cryptokit a.ml

I think it is possible to generalize this to any package that uses either unix or threads when compiling with jocaml. A subsidiary question is whether it is possible to do this dynamically with a _tags or myocamlbuild.ml file (note: comment if this remark needs to be moved).

Lapinot
  • 1,305
  • 2
  • 9
  • 11
  • This is interesting and quite clever! As a next step, I would try (I don't think the dynamically change you suggest would work) to simply modify `$(opam config var lib)/unix/META` to remove the "archive" lines. This is only a sane move, of course, in a switch that *only* handles jocaml stuff, as it globally change the way the "unix" package is handled on that switch. So even if you don't use the `+jocaml` switch per se, you need a jocaml-specific alias for this. – gasche Oct 30 '15 at 20:04