我试图在OCaml中编写一个(非常小,很简单 - 我不知道我在做什么,让它成为真实!)编译器。
我真的很想避免将任何 ISO-C代码检入项目中(尽管很了解C;这里的目标是专门学习和使用OCaml。)根据这一点,我需要为OCaml中的编译语言编写一个“运行时”,将其与主项目分开编译,然后将其与编译器本身的输出相关联。
不幸的是,它看起来像任何外部函数 - 即使那些不接触任何OCaml数据结构/ OCaml堆的函数也应该使用OCaml' C构建宏:
CAMLprim value scheme_entry(value unit) {
int i;
i = 42;
return Val_int(i);
}
如果我自己发出装配说明,这可能不是一个选择。 (至少,直到我学到更多东西!)
是否有任何方式(包括hacky - 这是个人学习项目)从OCaml调用极其简单的函数,如下所示?
_scheme_entry:
movl $42 %eax
ret
作为参考,我正在通过Ghuloum的IACC工作:http://ell.io/tt$ocameel
答案 0 :(得分:3)
不幸的是,看起来任何外部函数 - 即使不接触任何OCaml数据结构/ OCaml堆的函数 - 都应该使用OCaml的C宏构建:
不,他们不是。如果您的功能根本没有接触OCaml,或者没有分配或使用分配的值,那么您可以直接调用函数,例如,
value scheme_entry(value unit) {
int i;
i = 42;
return Val_int(i);
}
和OCaml方面:
external scheme_entry : unit -> int = "scheme_entry" [@@noalloc]
在OCaml的最新版本中,我们获得了更多的控制权,因此我们可以在没有装箱/拆箱的情况下传递浮点数和更大的整数。请阅读here以获取更多信息。
注意,Val_int
只是一个宏,它将C整数向左移一位,并将最低有效位设置为1,即(((unsigned)(x) << 1)) + 1)
。因此,如果您不需要将OCaml整数转换为C整数和反之,那么您甚至不需要使用此宏,因此运行时可能完全不知道OCaml,例如:
void runtime_init(void) {
printf("Hello from runtime");
}
和OCaml方面:
val runtime_init : unit -> unit = "runtime_init" [@@noalloc]
注意:OCaml 4.03中添加了[@@noalloc]
属性,在该版本之前,您应该使用"noalloc"
,例如,
val runtime_init : unit -> unit = "runtime_init" "noalloc"
当然,您非常简单的函数应该遵循适合您的特定体系结构和操作系统的C调用约定。因此,如果你的函数破坏了一些应该保留的寄存器,你应该会遇到麻烦,例如在amd64 ABI上你应该保留rbp,rbx,r12-r15。 OCaml没有特定于此要求的东西,只是一个普通的C调用约定。
答案 1 :(得分:2)
您可能需要考虑使用可通过OPAM获得的ctypes library及相关软件包。
opam install ctypes ctypes-foreign posix-types
示例:
open Foreign
open Ctypes
open Posix_types
let getpid = foreign "getpid" (void @-> returning pid_t)
let () = Printf.printf "%d\n" (Pid.to_int (getpid ()))
(对此进行编译需要包ctypes
,ctypes.foreign
和posix-types
。)