Posted 2022-01-03 21:17:23 GMT
こちらのツイートを目にして、そういえばVAX LISPのFFIって試したことがなかったので、この機会に試してみることにしました。
Cで書かれたルーチンを呼ぶ方法。この手の話、大事だと思うけどあまり書かれていない。過去のbitで説明があったのはAPPLE LISPのCALLくらい? pic.twitter.com/dycR4tjaAI
— zick (@zick_minoh) January 3, 2022
試したのは、紹介されているbit誌のコードで、試した処理系はLiving Computersに設置されているVAX-7000/640上のVAX LISP 3.1です。
まず、Cのコードを作成、
#include <stdio.h>
be_good (times, string)
int times;
char string[];
{
int count;
for (count=0; count < times; count++)
printf ("%s, I must not be so.\n", string);
printf("\n");
return(times);
}
$ cc be_good.c$ link/shareable=[user.masso]be_good be_good,sys$input:/option #改行
universal=be_good #^Zで完了
VAX LISPを起動し下記を定義
(define-external-routine (be-good :image-name "be_good" :entry-point "be_good" :result integer)
(times :lisp-type integer :mechanism :value)
(person :lisp-type string :vax-type :asciz))
call-out
で実行してみる
Lisp> (call-out be-good 10 "Daddy")
Error in SYSTEM::%SP-CALL-OUT:
%LIB-E-ACTIMAGE, error activating image SCSI$DIA0:[SYS0.SYSCOMMON.][SYSLIB]BE_GOOD.EXE;
-RMS-E-FNF, file not foundControl Stack Debugger
Eval #10: (SYSTEM::%SP-CALL-OUT 10 "Daddy" 2 #:G556)
どうもBE_GOOD.EXE
の場所を見付けてくれない様子……。
ファイルの絶対パス指定等を試してみましたが、解明すべき謎が多すぎるので諦めました。
下記のようなマニュアルの他の例は動くようなのでファイルの場所さえ適切に指定できれば動きそうではあります。
(define-external-routine (put-screen :image-name "scrshr"
:entry-point "lib$put_screen"
:result integer)
(chars :lisp-type string)
(line :lisp-type integer
:vax-type :word)
(col :lisp-type integer
:vax-type :word)
(flag :lisp-type integer
:vax-type :word))
このままでは若干寂しいのでcffiで同じ例を試して比較してみることにしました。
#include <stdio.h>
int be_good (int times, char string[])
{
for (int count = 0; count < times; count++)
printf ("%s, I must not be so.\n", string);
printf("\n");
return(times);
}
をlib-be-good.c
として用意し、
gcc -shared be_good.c -o lib-be-good.so
(ql:quickload "cffi")(defpackage "2657427c-2fcb-5f17-abc2-5439545b51fa"
(:use "CL" "CFFI"))
(in-package "2657427c-2fcb-5f17-abc2-5439545b51fa")
(define-foreign-library lib-be-good
(T (:default "lib-be-good")))
(use-foreign-library lib-be-good)
と定義。
VAX LISPのcall-out
に相当しそうな、foreign-funcall
で呼び出してみると、
(with-foreign-string (person "Daddy")
(foreign-funcall "be_good":int 10 :string person
:int))
Daddy, I must not be so.
Daddy, I must not be so.
Daddy, I must not be so.
Daddy, I must not be so.
Daddy, I must not be so.
Daddy, I must not be so.
Daddy, I must not be so.
Daddy, I must not be so.
Daddy, I must not be so.
Daddy, I must not be so.
という風にできました。
with-foreign-string
は無しでも動きますが、一応メモリ周りの処理をしてくれるので利用しています。
VMSでは、Common Language Environmentという言語間で共通の呼出規約が定められていたようで、色々な言語を簡単に混ぜて使えたようです。
マニュアルでもFortranのコードを呼び出す例が紹介されていたりしますが、共通の形式になるので呼び出す側からは元の言語はあまり意識しなくて良い様子です。
■
HTML generated by 3bmd in LispWorks 8.0.0