このページではJavaScriptを使用しています。

9.拡張機能パッケージ

9-1.概要

9-1-1.AZ-Prolog付属の拡張機能ライブラリ

本パッケージには、機能別にコンパイルされ必要に応じてロードできる拡張機能のダイナミックリンクライブラリが付属しています。一例としてエディタAzEditで言えば、Windows版なら「azedit.dll」、Linux版なら「azedit.so」がそれです。以下ではこれらを総称し「dll/so/dylib」と表記しています。これらは、AZ-Prologのインストールディレクトリ下の「system」ディレクトリ(注1)にソースで提供されていますので、機能の詳細を確認することができ、必要に応じ修正しコンパイルしなおすことができます。


注1.拡張機能ライブラリのソースファイル格納ディレクトリ
Windows版 %AZProlog%¥system¥ext, %AZProlog%¥system¥pl
Linux版 ${AZProlog}/share/azprolog/system/ext, ${AZProlog}/share/azprolog/system/pl
Mac版 ${AZProlog}/share/azprolog/system/ext, ${AZProlog}/share/azprolog/system/pl
*AZPrologはインストール時に設定される環境変数です。

各ディレクトリにはコンパイルのためのmakefileも含まれています。
また、個々の拡張機能を応用したサンプルプログラムがAZ-Prologのインストールディレクトリ下の「sample」ディレクトリ(注2)にソースで提供されていますのでご参照ください。


注2.拡張機能応用サンプルプログラム格納ディレクトリ
Windows版 %AZProlog%¥sample
Linux版 ${AZProlog}/share/azprolog/sample
Mac版 ${AZProlog}/share/azprolog/sample

本パッケージで提供される標準インタプリタをMakeするmakefileはインストールディレクトリ下の「system/make」ディレクトリにありますので、ユーザプログラムをコンパイルし、スタンドアローン実行プログラムを作成する場合の参考にしてください。

9-1-2.「dll/so/dylib」化されている拡張機能を利用するには

「dll/so/dylib」化されている拡張機能を利用するには、利用開始前に次の述語を呼び出してください。

:- dlib_require(拡張子を除いた「dll/so/dylib」名).


提供される各「dll/so/dylib」はインストールディレクトリ下(注3)に格納されており、パスを省略した時はここを参照します。


注3.拡張機能「dll/so/dylib」格納ディレクトリ
Windows版 %AZProlog%¥lib¥ext
Linux版 ${AZProlog}/lib/azprolog/ext/
Mac版 ${AZProlog}/lib/azprolog/ext/

<例>- dlib_require(mecab).

  この述語が失敗した場合は、次の述語でステータスを取得できます。

  :- dlib_get_error_str(S),name(A,S).


ユーザー作成の「dll/so/dylib」も同様に呼び込むことができます。
但し、「/static」オプションを付けてコンパイルした拡張インタプリタ(ユーザプログラムをスタティックリンク)からは、組込述語 dlib_require/1 で他の「dll/so/dylib」を呼ぶことはできなくなるので注意してください。この場合、必要な拡張機能があれば、それらも合わせてスタティックリンクする必要があります。その方法については「9-1-5.拡張機能のスタティックリンク方法」を参照してください。


9-1-3.拡張機能のOS別実装一覧表
Win  Linux/Mac dll/so/dylib 機能拡張 リンク方法 備考
× 9-2..素性構造型 基本インタプリタにリンク済(スタティック)  
9-3.制約論理 :- dlib_require(clp). 提供ソースファイル:clp.pl(*1)
× 9-4.並列処理支援機構 子プロセス用インタプリタ(prolog_c)にリンク済(スタティック) 提供ソースファイル:mlt_child.pl、mlt_parent.pl(*2)
× 9-5.CGIインターフェースとユーティリティ CGIインタプリタ(prologcgi) にリンク済(スタティック) 提供ソースファイル:prologcgi.pl(*2)
9-6.鬼車 :- dlib_require(oniguruma). 提供ソースファイル:oniguruma.c(*1)
事前準備: 正規表現ライブラリ”鬼車"はパッケージに同梱。最新版に差し替える場合のみダウンロード・インストール
9-7.Mecab/Cabocha :- dlib_require(mecab). 提供ソースファイル:mecab.c、aze_cenc.c、aze_api.c(*1)
事前準備:形態素解析エンジン”MeCab”ダウンロード・インストール
9-8.ソケット :- dlib_require(socket).
:- dlib_require(socket_ssl).
:- dlib_require(websock).
提供ソースファイル:socket.c、socket_ssl.c、websock.c client.c util.c(*1)
事前準備: [socket_ssl]OpenSSL、Cryptoダウンロード・インストール
限定機能:Unix(ドメイン)ソケット(socketライブラリ)、WebSocketはLinux版のみ
9-9.Redisインターフェース :- dlib_require(redis). 提供ソースファイル:redis.c、putil.c、putil.h(*1)
事前準備:Key-ValueストアRedisサーバ/hiredis(Cクライアント)ダウンロード・インストール
× 9-10.ODBC :- dlib_require(odbc).
提供ソースファイル:odbc_prolog.pl、odbc.c(*1)
事前準備: RDBMS(MS-ACCESS、SQL Server等)/ODBCドライバダウンロード・インストール、データソース設定、ODBC接続テスト
× × 9-11.OLEオートメーション 基本インタプリタにリンク済(スタティック)  
9-12.エディタ(AzEdit)     :- dlib_require(azedit). 提供ソースファイル:azedit.pl(*1)
× 9-13.その他 各インタプリタにリンク済(スタティック)
若干の違いあり(CGIインタプリタにmanual.plは含まれない等)
提供ソースファイル:iso_pred.pl,utility.pl,setof.pl,manual.plなど(*2)

*1:ダイナミックリンクする拡張機能のソースファイルはsystem/ext以下の機能別サブディレクトリあります。
*2:スタティックリンクされている拡張機能のソースファイルはsystem/plの直下にあります。

9-1-4.dll/so/dylibの基本的な作り方

ダイナミックリンクライブラリ(dll/so)や共有ライブラリ(dylib)が提供されている拡張機能では、関係するソースファイルやMakeifileも合わせて提供されています。これらを参考にすると、PrologやC言語で書かれたユーザ定義の機能の追加もAZ-Prologの拡張ライブラリとして利用できるようになります。
ここでは、dll/so/dylibの基本的な作り方について簡単に説明します。


1. ソースプログラムを書く時の注意点

dll/so/dylibを作成するためのソースは、Prolog、C言語、または両方で記述することができます。
Prologで記述する場合、ライブラリのエントリポイントになる述語(他モジュールから呼ばれる述語)はpublic宣言(7-4.(2)参照)されていなければなりません。この場合、これらの述語を組込み述語として登録するための初期化プログラムは、コンパイラazpcがC言語ソースコードを生成する際に自動的に作られます。ファイル名またはモジュール名(7-4.(1)参照)は、この初期化関数の名前の一部になるため、C言語の関数名として妥当なものである必要があります。
C言語で記述する場合は、AZ-Prologの提供するC言語インターフェース(詳細は8章参照)に則って述語(関数)を定義しますが、初期化関数は自ら定義する必要があります。初期化関数の定義については、8-2-2.に解説されています。


2. Makefileの書き方

9-1-3. の一覧表からも分かるように、拡張機能のdll/so/dylibは、1)Prologソースのみで記述されたもの(clp、azedit等)、2)C言語だけで記述されたもの(oniguruma、redis等)、3)Prolog、C言語両方で記述されたもの(odbc等)があります。Prologのソースは、azpcによってC言語に変換された後は、他のC言語で記述されたソースファイルと扱いは同じになります。ここでは1) ~3) の場合について、Windows/Linux/Macそれぞれの環境でdll/so/dylibを生成する場合のMakefileを考えます。ソースファイル名は、Prologで書かれたものはplmodule.pl、C言語で書かれたものはcmodule.cで統一します。また、生成されるdll/so/dylibは、1ファイルのみから生成される場合はソースファイルと同じベースネームとします(plmodule.plからはplmodule.dll/plmodule.soと言う具合)。複数ファイルから生成する場合は、いずれのソースファイル名にも依存しないmydlib.dll/mydlib.so/mydlib.dylibとします。

A.Windows版の場合

Windows環境でのmakeにはnmake.exe(「Microsoft Visual Studio 2013 for Windows Desktop」と一緒にインストールされる)を使用します。
Cコンパイラにはcl.exe(VC++のコマンドラインコンパイラ)を使用し、dllを生成するためにazpdll.libをリンクします。

1) Prologソースファイルからのdllファイル生成Makefile
plmodule.plをazpcでコンパイルしてplmodule.cを生成し、これをCコンパイラでコンパイル・リンクしてplmodule.dllを生成します。

# Makefile  Windows版dll生成用(Prologソースから)
CC=cl
LIB_PREFIX     = %AZProlog%lib
LIB_PREFIX_EXT = %AZProlog%libext
CFLAGS = -nologo -w -O2 -Ox -DWIN32 -DDLL -I. -I"%AZProlog%include"
plmodule.dll: plmodule.c
	$(CC) $(CFLAGS) plmodule.c /LD "$(LIB_PREFIX)azpdll.lib" 
plmodule.c: plmodule.pl
	azpc -p plmodule.pl /ncc
install:
	copy plmodule.dll "$(LIB_PREFIX_EXT)"

2) C言語ソースファイルからのdllファイル生成Makefile
cmodule.cからcmodule.dllを生成します。

# Makefile  Windows版dll生成用(Cソースから)
CC=cl
LIB_PREFIX     = %AZProlog%lib
LIB_PREFIX_EXT = %AZProlog%libext
CFLAGS = -nologo -w -O2 -Ox -DWIN32 -DDLL -I. -I"%AZProlog%include"
LDLIBS=
cmodule.dll: cmodule.c
	$(CC) $(CFLAGS) cmodule.c /LD "$(LIB_PREFIX)azpdll.lib" 

install:
	copy cmodule.dll "$(LIB_PREFIX_EXT)"

3) Prolog、C言語の両ソースファイルからのdllファイル生成Makefile
plmodule.pl、cmodule.cからmydlib.dllを生成します。dllの初期化のためにinitiator.cがリンクされていることに注意してください。
initiator.cについては続いて説明しています。

# Makefile  Windows版dll生成用(Prolog,Cソースから)
CC=cl
LIB_PREFIX     = %AZProlog%lib
LIB_PREFIX_EXT = %AZProlog%libext
CFLAGS = -nologo -w -O2 -Ox -DWIN32 -DDLL -I. -I"%AZProlog%include"
LDLIBS=
default: mydlib.dll
plmodule.c: plmodule.pl
	azpc -p plmodule.pl /ncc
mydlib.dll: cmodule.c plmodule.c initiator.c
	$(CC) $(CFLAGS) cmodule.c plmodule.c initiator.c /LD "$(LIB_PREFIX)azpdll.lib" 
	rename cmodule.dll mydlib.dll
install:
	copy mydlib.dll "$(LIB_PREFIX_EXT)"

$(CC)によって生成されるdllの名前は、ソースファイル並びの先頭のファイル名(ベースネーム、上記の例では、cmodule)と同じになるので、これをmydlib.dllにrenameしています。この部分は、以下の様にinitiator.cの名前をmydlib.cに変えてソース並びの先頭に持って来れば、renameの必要はなくなります。

mydlib.dll: mydlib.c cmodule.c plmodule.c
	$(CC) $(CFLAGS) mydlib.c cmodule.c plmodule.c /LD "$(LIB_PREFIX)azpdll.lib" 

initiator.c(またはmydlib.c)は以下のような内容になっています。AZ-Prologインタプリタのトップレベルでdlib_require(mydlib)を実行すると関数initiate_mydlib()が呼ばれるので、そこから各モジュールの初期化関数が呼ばれることになります。

extern int initiate_plmodule(Frame*);
extern int initiate_cmodule(Frame*);
__declspec(dllexport) int initiate_mydlib(Frame *Env){
initiate_plmodule(Env);
initiate_cmodule(Env);
}

B.Linux版の場合

Cコンパイラはgccを用い、「-shared -dynamiclib」オプションの指定でso(Shared Object)ファイルを生成します。


1) Prologソースファイルからのsoファイル生成Makefile
plmodule.plをazpcでコンパイルしてplmodule.cを生成し、これをCコンパイラでコンパイル・リンクしてplmodule.soを生成します。

# Makefile ---- Linux版so生成用(Prologソースから)
INST_PREFIX = $(AZProlog)
CCOPT = -I.  -I$(INST_PREFIX)/include
LDOPT =  -L$(INST_PREFIX)/lib
CFLAGS = -Wall -O2 $(CCOPT) 
AZPCFLAGS = /message /s_verbos /cc $(CC) /ccopt "$(CCOPT)" /link_opt "$(LDOPT)"
AZPC = azpc
CC=gcc
plmodule.so: plmodule.c
	$(CC) $(CFLAGS) -fPIC -o plmodule.o -c plmodule.c
	$(CC) -shared -dynamiclib -o $@ plmodule.o
	chmod 644 $@
plmodule.c: plmodule.pl
	$(AZPC) -p $< /ncc $(AZPCFLAGS)

2) C言語ソースファイルからのsoファイル生成Makefile
cmodule.cからcmodule.soを生成します。

# Makefile ---- Linux版so生成用(Cソースから)
CCOPT = 
CFLAGS = -Wall -O2 $(CCOPT) 
CC=gcc
cmodule.so: cmodule.c
	$(CC) $(CFLAGS) -fPIC -o cmodule.o -c cmodule.c 
	$(CC) -shared -dynamiclib -o $@ cmodule.o 
	chmod 644 $@

3) Prolog、C言語の両ソースファイルからのsoファイル生成Makefile
plmodule.pl、cmodule.cからmydlib.soを生成します。初期化のためにinitiator.cがリンクされていることに注意してください。

# Makefile ---- Linux版so生成用(Prolog、Cソースから)
INST_PREFIX = $(AZProlog)
CCOPT = -I.  -I$(INST_PREFIX)/include
LDOPT =  -L$(INST_PREFIX)/lib
CFLAGS = -Wall -O2 $(CCOPT) 
AZPCFLAGS = /message /s_verbos /cc $(CC) /ccopt "$(CCOPT)" /link_opt "$(LDOPT)"
AZPC = azpc
CC=gcc
default: mydlib.so
plmodule.c: plmodule.pl
	$(AZPC) -p $< /ncc $(AZPCFLAGS)
mydlib.so: cmodule.c plmodule.c initiator.c
	$(CC) $(CFLAGS) -fPIC -o cmodule.o -c cmodule.c 
	$(CC) $(CFLAGS) -fPIC -o plmodule.o -c plmodule.c
	$(CC) $(CFLAGS) -fPIC -o initiator.o -c initiator.c
	$(CC) -shared -dynamiclib -o $@ cmodule.o plmodule.o initiator.o
	chmod 644 $@

initiator.cは以下のような内容になっています。AZ-Prologインタプリタのトップレベルでdlib_require(mydlib)を実行すると関数initiate_mydlib()が呼ばれるので、そこから各モジュールの初期化関数が呼ばれることになります。

extern int initiate_plmodule(Frame*);
extern int initiate_cmodule(Frame*);
int initiate_mydlib(Fram *Env){
    initiate_plmodule(Env);
    initiate_cmodule(Env);
}

C.Mac版の場合

Cコンパイラはgccを用い、「-dynamiclib」オプションの指定でdylib(共有ライブラリ)ファイルを生成します。


1) Prologソースファイルからのdylibファイル生成Makefile
plmodule.plをazpcでコンパイルしてplmodule.cを生成し、これをCコンパイラでコンパイル・リンクしてplmodule.dylibを生成します。

# Makefile ---- Mac版dylib生成用(Prologソースから)
INST_PREFIX = $(AZProlog)
CCOPT = -I.  -I$(INST_PREFIX)/include -fno-strict-aliasing
LDOPT =  -L$(INST_PREFIX)/lib
CFLAGS = -Wall -Wno-deprecated-declarations -O2 -DMAC $(CCOPT) 
AZPCFLAGS = /message /s_verbos /cc $(CC) /ccopt "$(CCOPT)" /link_opt "$(LDOPT)"
AZPC = azpc
CC=gcc
plmodule.dylib: plmodule.c
    $(CC) $(CFLAGS) -fPIC -o plmodule.o -c plmodule.c
    $(CC) -dynamiclib -Wl,-undefined -Wl,dynamic_lookup -o $@ plmodule.o -lc
    chmod 644 $@
plmodule.c: plmodule.pl
    $(AZPC) -p $< /ncc $(AZPCFLAGS)


2) C言語ソースファイルからのdylibファイル生成Makefile
cmodule.cからcmodule.dylibを生成します。

# Makefile ---- Mac版dylib生成用(Cソースから)
CCOPT = 
CFLAGS = -Wall -Wno-deprecated-declarations -O2 -DMAC $(CCOPT) 
CC=gcc
cmodule.dylib: cmodule.c
    $(CC) $(CFLAGS) -fPIC -o cmodule.o -c cmodule.c
    $(CC) -dynamiclib -Wl,-undefined -Wl,dynamic_lookup -o $@ cmodule.o -lc
    chmod 644 $@


3) Prolog、C言語の両ソースファイルからのdylibファイル生成Makefile
plmodule.pl、cmodule.cからmydlib.dylibを生成します。初期化のためにinitiator.cがリンクされていることに注意してください。

# Makefile ---- Mac版dylib生成用(Prolog、Cソースから)
INST_PREFIX = $(AZProlog)
CCOPT = -I.  -I$(INST_PREFIX)/include
LDOPT =  -L$(INST_PREFIX)/lib
CFLAGS = -Wall -Wno-deprecated-declarations -O2 -DMAC $(CCOPT) 
AZPCFLAGS = /message /s_verbos /cc $(CC) /ccopt "$(CCOPT)" /link_opt "$(LDOPT)"
AZPC = azpc
CC=gcc
default: mydlib.dylib
plmodule.c: plmodule.pl
    $(AZPC) -p $< /ncc $(AZPCFLAGS)
mydlib.dylib: cmodule.c plmodule.c initiator.c
    $(CC) $(CFLAGS) -fPIC -o cmodule.o -c cmodule.c 
    $(CC) $(CFLAGS) -fPIC -o plmodule.o -c plmodule.c
    $(CC) $(CFLAGS) -fPIC -o initiator.o -c initiator.c
    $(CC) -dynamiclib -Wl,-undefined -Wl,dynamic_lookup -o $@ cmodule.o plmodule.o initiator.o -lc
    chmod 644 $@

initiator.cは以下のような内容になっています。AZ-Prologインタプリタのトップレベルでdlib_require(mydlib)を実行すると関数initiate_mydlib()が呼ばれるので、そこから各モジュールの初期化関数が呼ばれることになります。

extern int initiate_plmodule(Frame*);
extern int initiate_cmodule(Frame*);
int initiate_mydlib(Frame *Env){
    initiate_plmodule(Env);
    initiate_cmodule(Env);
}


3. Makeの仕方と動作確認

1) Makeの仕方
Windowsの場合は「VS2013 x64(32ビットならx86) Cross Tools コマンドプロンプト」(7-1参照)上でnmake.exeを実行します。このコマンドプロンプトでは、nmake.exeやcl.exeをコマンドラインで実行するのに必要な環境設定が全てされています。Linux版またはMac版ならシェルターミナルからmakeを実行します。ならシェルターミナルからmakeを実行します。4.2で説明したMakefileであれば、いずれも引数(ターゲット指定)なしで実行します。生成されたdll/so/dylibファイルはnmake.exeまたはmakeを実行したカレントディレクトリに置かれます。


2) 動作確認
Windows、LinuxまたはMacいずれの場合も、AZ-Prologを起動して述語 dlib_require/1 でdll/so/dylibを呼び出します。dll/so/dylibファイルはAZ-Prologを起動したディレクトリにあるものとし、仮にmylib.dllまたはmylib.soまたはmylib.dylibとします。yesと表示されれば無事ロードされ、初期化が完了したことになります。

| ?-dlib_require('./mydlib').
yes

後は、実装した述語を実行して、正しく呼び出されることを確認してください。 上記の例のように、dll/so/dylibをパスで指定することもできますが、dll/so/dylibのサーチパス(組込述語 dlib_get_searchi_path/1 で確認ができます)上に置けば、以下のように名前で指定することができます。

| ?-dlib_require(mydlib).


9-1-5.拡張機能のスタティックリンク方法

拡張機能をスタティックリンクして、コンパイルされた実行モジュールに予め組込んでしまうこともできます。この場合は1ファイルだけで実行可能なので、可搬性は高くなります。
例として、AZ-Prologインタプリタにユーザ定義のpmodule.plとエディタAzEditをスタティックに組み込む場合を考えます。


1) 拡張機能のソースファイルを一緒にコンパイル・リンクする方法

azedit.plと言うソースファイルが提供されているので、これを一緒にコンパイル・リンクする方法は以下の通りです。

Windows > azpc -p plmodule.pl /i /e myprolog /static "%AZProlog%¥system¥ext¥azedit¥azedit.pl"
Linux $ azpc -p plmodule.pl /i /e myprolog /static ${AZProlog}/share/azprolog/system/ext/azedit/azedit.pl
Mac $ azpc -p plmodule.pl /i /e myprolog /static ${AZProlog}/share/azprolog/system/ext/azedit/azedit.pl

2) スタティックリンクライブラリをリンクする方法

Linux版では拡張機能のsoファイル、Mac版では拡張機能のdylibファイルのみならず、スタティックリンクライブラリも提供されており、その生成方法も各拡張機能のMakefileに公開されています。Windows版では現時点で拡張機能のスタティックリンクライブラリは提供されておりません。
ここでは、Linux版またはMac版について、提供されたスタティックリンクライブラリをリンクした実行モジュールを生成する方法を解説します。

例として、エディタAzEditを組み込む方法は以下のようになります。AzEditのスタティックライブラリはlib_azedit.aなので、"-L ${AZProlog}/lib/azprolog/ext -l_azedit"で指定しています。

    $ azpc -p plmodule.pl initiator.c /i /e myprolog /link_opt2 "-L ${AZProlog}/lib/azprolog/ext -l_azedit" /static

ここでinitiator.cは、以下の通りです。

extern int initiate_azedit(Frame*);
void initiate_initiator(Frame *Env){
    initiate_azedit(Env);
}

実行プログラムを生成する際、azpcはuserfile.cと言うファイルを作成して、この中に各モジュールの初期化関数の呼び出しを並べた関数user_file()を自動生成します(8-2-2参照)。但し、ライブラリの初期化関数呼び出しは現時点では自動的には書かれないので、手書きしてやる必要があります。initiator.cはリンクするライブラリの初期化関数呼び出しを並べたファイルです。このファイルはazpcによって1つのモジュールと見なされ、このモジュールの初期化関数(initiate_initiator())の呼び出しはuserfile.cに書かれるので、この関数内に必要なライブラリの初期化関数呼び出しを並べて置けばよいことになります。
但し、拡張機能ライブラリが、更に外部ライブラリを参照している場合は、それらもリンクしなければなりません。

外部ライブラリが必要になる拡張機能の例として、Redisクライアントを組み込む方法は以下のようになります。外部ライブラリは「/lib hiredis」で与えています。

  $ azpc -p plmodule.pl initiator.c /i /e myprolog /link_opt2 "-L ${AZProlog}/lib/azprolog/ext -l_redis" /static /lib hiredis

iniitiator.cはazeditの場合と同様ですが、以下の通りです。

extern int initiate_redis(Frame*);
void initiate_initiator(Frame *Env){
    initiate_redis(Env);
}


以下に、拡張機能をスタティックリンクする際に必要となるライブラリの指定方法をまとめておきます。

拡張機能スタティックリンク時の必要ライブラリ

機能拡張 拡張機能スタティックライブラリ 外部ライブラリ
制約論理 clp "-L ${AZProlog}/lib/azprolog/ext -l_clp" なし
鬼車 oniguruma "-L ${AZProlog}/lib/azprolog/ext -l_oniguruma" /lib onig
めかぶ mecab "-L ${AZProlog}/lib/azprolog/ext -l_mecab" /lib mecab
ソケット socket "-L ${AZProlog}/lib/azprolog/ext -l_socket" なし
               socket_ssl "-L ${AZProlog}/lib/azprolog/ext -l_socket_ssl" /lib ssl /lib crypto
               websock "-L ${AZProlog}/lib/azprolog/ext -l_websock" /lib websockets
Redis redis "-L ${AZProlog}/lib/azprolog/ext -l_redis" /lib hiredis
エディタ azedit "-L ${AZProlog}/lib/azprolog/ext -l_azedit"
なし

*鬼車の場合、提供サンプルoniguruma.plで動作確認をする場合、${AZProlog}/share/azprolog/system/pl/utility.pl
が必要になります。このファイルもリンクするか、コンサルトしてから確認してください。