c/c++与chibi-scheme互相调用
测试环境是mac
chibi-scheme是scheme/lisp的一种实现,适合作为脚本语言嵌入到c/c++程序中
chibi-scheme官方文档写的很清楚,只是没有实例
外国友人写的相关教程结合实例,写的很清楚
代码库地址 里的c2scheme目录是示例代码
大体分成三步
- 加载scheme文件
- 调用scheme函数代码,传递参数,接收返回值
- scheme代码调用c/c++代码,传递参数,接收返回值
callme.scm
(import (chibi))
(define (say-hello)
(display "hello world from scheme")
(newline))
加载scheme文件
构造字符串,然后加载
obj1 = sexp_c_string(ctx, "callme.scm", -1);
sexp_load(ctx, obj1, NULL);
调用scheme函数代码,传递参数,接收返回值
调用scheme函数代码
sexp_eval_string(ctx, "(say-hello)", -1, NULL);
传递参数
arg_val = sexp_make_fixnum(4);
arg_sym = sexp_intern(ctx, "arg", -1);
sexp_env_define(ctx, sexp_context_env(ctx), arg_sym, arg_val);
file_path = sexp_c_string(ctx, "callme.scm", -1);
sexp_load(ctx, file_path, NULL);
接收返回值
ret = sexp_eval_string(ctx, "(square arg)", -1, NULL);
int result = -1;
if (sexp_integerp(ret)) {
result = sexp_unbox_fixnum(ret);
}
callme.scm
(define (square a)
(* a a))
scheme代码调用c/c++代码,传递参数,接收返回值
callme.scm
(define (say-hello)
(display "hello world from scheme")
(newline)
(hello-user "chibi-scheme"))
hello-user是c/c++函数,传递一个字符串
在c/c++中横线会转换成下划线
定义头文件
c2scheme.h
extern void hello_user(const char* tmp);
定义stub文件
c2scheme.stub
(c-include "c2scheme.h")
(define-c void hello-user (string))
stub文件主要便于生成对应的c/c++文件
然后运行
DYLD_LIBRARY_PATH=. ./chibi-scheme ./tools/chibi-ffi c2scheme/c2scheme.stub
会生成对应的c/c++文件,我们看下它的内容
c2scheme.c
/* Automatically generated by chibi-ffi; version: 0.4 */
#include <chibi/eval.h>
#include "c2scheme.h"
/*
types: ()
enums: ()
*/
sexp sexp_hello_user_stub (sexp ctx, sexp self, sexp_sint_t n, sexp arg0) {
sexp res;
if (! sexp_stringp(arg0))
return sexp_type_exception(ctx, self, SEXP_STRING, arg0);
res = ((hello_user(sexp_string_data(arg0))), SEXP_VOID);
return res;
}
sexp sexp_init_library (sexp ctx, sexp self, sexp_sint_t n, sexp env, const char* version, const sexp_abi_identifier_t abi) {
sexp_gc_var3(name, tmp, op);
if (!(sexp_version_compatible(ctx, version, sexp_version)
&& sexp_abi_compatible(ctx, abi, SEXP_ABI_IDENTIFIER)))
return SEXP_ABI_ERROR;
sexp_gc_preserve3(ctx, name, tmp, op);
op = sexp_define_foreign(ctx, env, "hello-user", 1, sexp_hello_user_stub);
if (sexp_opcodep(op)) {
sexp_opcode_return_type(op) = SEXP_VOID;
sexp_opcode_arg1_type(op) = sexp_make_fixnum(SEXP_STRING);
}
sexp_gc_release3(ctx);
return SEXP_VOID;
}
只需要实现hello_user这个函数即可.
我们在main.cpp里实现这个方法
void hello_user(const char* tmp){
printf("in hello user %s \n", tmp);
}
将来可以把函数的声明和实现统一规划到别的文件去,这里只是做个示例。
完整代码及编译运行脚本在上面的仓库地址。
注意 (import (chibi)) 这是需要加载chibi-scheme的lib目录下的scm文件,默认搜索目录是./lib和.目录,所以当运行目录在别的地方时,需要添加module搜索目录
sexp_add_module_directory(ctx, tmp=sexp_c_string(ctx,"../lib",-1), SEXP_TRUE);