问题
I'm trying to write a (desperately tiny, simple — I have no idea what I'm doing, let's be real!) compiler in OCaml.
I'd really like to avoid checking any ISO-C code into the project (despite knowing C fairly well; the goal here is to learn and use OCaml exclusively.) Pursuant to this, I need to write a “runtime” for the compiled language in OCaml, compile it separately from the primary project, and then link it against the compiler-itself's output.
Unfortunately, it looks like any external functions — even ones that don't touch any OCaml data-structures / the OCaml heap, are expected to be constructed using OCaml's C macros:
CAMLprim value scheme_entry(value unit) {
int i;
i = 42;
return Val_int(i);
}
This probably isn't an option, if I'm emitting the assembly instructions myself. (At least, not until I learn quite a bit more!)
Is there any way (including hacky ones — this is a personal learning project) to invoke extremely simple functions like the following from OCaml?
_scheme_entry:
movl $42 %eax
ret
For reference, I'm working through Ghuloum's IACC: http://ell.io/tt$ocameel
回答1:
Unfortunately, it looks like any external functions — even ones that don't touch any OCaml data-structures / the OCaml heap, are expected to be constructed using OCaml's C macros:
No, they are not. If your function doesn't touch OCaml at all, or doesn't allocated or works with the allocated values, then you can call functions directly, e.g.,
value scheme_entry(value unit) {
int i;
i = 42;
return Val_int(i);
}
and on OCaml side:
external scheme_entry : unit -> int = "scheme_entry" [@@noalloc]
In the latest releases of OCaml we got even more control, so that we can pass floats and bigger integers without boxing/unboxing. Read here for the further info.
Note, that Val_int
is just a macro that shift a C integer one bit to the left and sets the least significant bit to one, i.e., (((unsigned)(x) << 1)) + 1)
. So, if you don't need to translate OCaml integers to C integers and vice verse, then you don't even need to use this macros, so you runtime can be totally unaware of OCaml, for example:
void runtime_init(void) {
printf("Hello from runtime");
}
and on OCaml side:
val runtime_init : unit -> unit = "runtime_init" [@@noalloc]
Note: the [@@noalloc]
attribute was added in OCaml 4.03, before that version, you should use "noalloc"
, e.g.,
val runtime_init : unit -> unit = "runtime_init" "noalloc"
Of course, your extremely simple function should obey the C calling convention that is appropriate to your particular architecture and operating system. So if your function destroys some registers that should be preserved, you should expect troubles, for example on amd64 ABI you should preserve rbp, rbx, r12-r15. There is nothing OCaml specific with this requirement, just a normal C calling convention.
回答2:
You may want to look into using the ctypes library and associated packages, which are available through OPAM.
opam install ctypes ctypes-foreign posix-types
Example:
open Foreign
open Ctypes
open Posix_types
let getpid = foreign "getpid" (void @-> returning pid_t)
let () = Printf.printf "%d\n" (Pid.to_int (getpid ()))
(Compiling this requires the packages ctypes
, ctypes.foreign
, and posix-types
.)
来源:https://stackoverflow.com/questions/46566761/is-it-possible-to-call-into-c-functions-from-ocaml-without-wrapped-types