I want to compile some OCaml bytecode and have it run on Windows and Unix-type systems. My source code works fine if I recompile it on each platform, but the bytecode isn't portable.
Sample code:
open Unix
let on_windows = Filename.dir_sep <> "/";;
Printf.printf "On windows: %b\n" on_windows;;
let child = create_process "gpg" (Array.of_list ["gpg"; "--version"]) stdin stdout stderr;;
Printf.printf "Child %d\n" child;;
Build command:
ocamlbuild -use-ocamlfind -pkg unix test.byte
If I compile on Windows and run on Linux, I get
Fatal error: unknown C primitive `win_waitpid'
If I compile on Linux and run on Windows I get:
Fatal error: unknown C primitive `unix_waitpid'
How can I make the bytecode work everywhere?
Obviously, the reason is that ocaml unix library has different names for C stubs depending on the platform, and this hinders bytecode portability. I do not see the way out except for patching stub names..
Merely renaming the C symbols doesn't work because there are two completely different versions of the unix.ml module (though with the same interface). If you link your code statically, you'll get the one for the build platform and it won't work on the other platform.
The solution is to create and distribute a .cma archive (with the Unix module not linked in) rather than an executable. Then use ocaml
to link dynamically on the target platform:
http://roscidus.com/blog/blog/2013/07/07/ocaml-binary-compatibility/#windows--linux-compatibility
Update: This isn't safe. When you do ocaml /path/to/script.ml
, it adds the current directory (not the directory containing the script) to the start of the search path. Thus:
$ cd /tmp
$ /usr/bin/myprog
will first try to load myprog's libraries (e.g. unix.cma
) from /tmp
.
Should be fixed in 4.03: http://caml.inria.fr/mantis/view.php?id=6081
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With