opamp_sando's blog

クソザコが割りと適当なことを書くためにある備忘録です。あとたまに普通の日記も書きます

初めてのCFFI

初めてCFFIを使ってみた。わかりやすくするために、自分で作った特に何の役にも絶たない共有ライブラリの関数をCommon Lispで呼び出してみた。

とりあえずCで適当なヘッダーとC言語ファイルを作る。

以下がtestlib.h

#ifndef TESTLIB_H
#define TESTLIB_H
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct hogehoge {
  char first[128];
  char last[128];
};

typedef struct hogehoge hoge_d;

void helloworld(char* name);

hoge_d* init_hogehoge(char* first,char* last);

void hello(hoge_d *data);

#endif

次のがtestlib.c

#include"testlib.h"

void helloworld(char* name){
  printf("hello %s\n",name);
}

hoge_d* init_hogehoge(char* first,char* last){
  hoge_d* data = (hoge_d*)malloc(sizeof(hoge_d));
  strcpy(data->first,first);
  strcpy(data->last,last);
  return data;
}

void hello(hoge_d *data){
  printf("hello %s %s\n",data->first,data->last);
}

コンパイルしてsoファイルを作る。

$ gcc -shared testlib.c -o libtestlib.so -fPIC

ここまでできたらCommon LispのREPLに入って呼び出してみる。
まずは準備をする。

> (ql:quickload :cffi)
> (defpackage :cffi-test (:use :common-lisp :cffi))
> (in-package :cffi-test)

次にライブラリを探すディレクトリを指定する。どうやらforeign-library-directoriesを設定したらいいようだ。
stringかpathnameか何かで指定できるようだが、pathnameならディレクトリ形式で指定する。

> (setf *foreign-library-directories* (list #p"/path/to/so/dir/"))

そして、ライブラリを定義する。

(define-foreign-library libtestlib 
  (:unix (:default "libtestlib"))
  (:t (:default "libtestlib")))

定義したら読み込む。

> (use-foreign-library libtestlib)

これで全部の準備ができたので、defcfunでCの関数を定義していく。

> (defcfun ("helloworld" helloworld) :void (name :string))

まず、名前を渡してhello worldするだけの関数を呼び出す。上のように定義するとhelloworldという名前でCommon LispからC言語で定義したhelloworld関数を呼び出せるようになる。

> (helloworld "opamp")

ポインタや複数引数も難なくできた。

> (defcfun ("init_hogehoge" init-hogehoge) :pointer (first :string last :string))
> (defcfun ("hello" hello) :void (data :pointer))

これで

> (defvar *p* (init-hogehoge "opamp" "sando"))
> (hello *p*) ; "hello opamp sando"と表示される

参考資料

https://common-lisp.net/project/cffi/manual/cffi-manual.html

http://bis83gb.hatenadiary.jp/entry/2013/06/29/132421

https://common-lisp.net/project/cffi/manual/html_node/_002aforeign_002dlibrary_002ddirectories_002a.html

Firefox ブラウザ無料ダウンロード