c/c++与chibi-scheme互相调用

测试环境是mac

chibi-scheme是scheme/lisp的一种实现,适合作为脚本语言嵌入到c/c++程序中

chibi-scheme官方文档写的很清楚,只是没有实例

外国友人写的相关教程结合实例,写的很清楚

代码库地址 里的c2scheme目录是示例代码

大体分成三步

  1. 加载scheme文件
  2. 调用scheme函数代码,传递参数,接收返回值
  3. 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);  

视频链接
B站
Youtube