本パッケージには、機能別にコンパイルされ必要に応じてロードできる拡張機能のダイナミックリンクライブラリが付属しています。一例としてエディタAzEditで言えば、Windows版なら「azedit.dll」、Linux版なら「azedit.so」がそれです。以下ではこれらを総称し「dll/so/dylib」と表記しています。これらは、AZ-Prologのインストールディレクトリ下の「system」ディレクトリ(注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 |
各ディレクトリにはコンパイルのためのmakefileも含まれています。
また、個々の拡張機能を応用したサンプルプログラムがAZ-Prologのインストールディレクトリ下の「sample」ディレクトリ(注2)にソースで提供されていますのでご参照ください。
Windows版 | %AZProlog%¥sample |
Linux版 | ${AZProlog}/share/azprolog/sample |
Mac版 | ${AZProlog}/share/azprolog/sample |
本パッケージで提供される標準インタプリタをMakeするmakefileはインストールディレクトリ下の「system/make」ディレクトリにありますので、ユーザプログラムをコンパイルし、スタンドアローン実行プログラムを作成する場合の参考にしてください。
「dll/so/dylib」化されている拡張機能を利用するには、利用開始前に次の述語を呼び出してください。
:- dlib_require(拡張子を除いた「dll/so/dylib」名).
提供される各「dll/so/dylib」はインストールディレクトリ下(注3)に格納されており、パスを省略した時はここを参照します。
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.拡張機能のスタティックリンク方法」を参照してください。
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) |
ダイナミックリンクライブラリ(dll/so)や共有ライブラリ(dylib)が提供されている拡張機能では、関係するソースファイルやMakeifileも合わせて提供されています。これらを参考にすると、PrologやC言語で書かれたユーザ定義の機能の追加もAZ-Prologの拡張ライブラリとして利用できるようになります。
ここでは、dll/so/dylibの基本的な作り方について簡単に説明します。
dll/so/dylibを作成するためのソースは、Prolog、C言語、または両方で記述することができます。
Prologで記述する場合、ライブラリのエントリポイントになる述語(他モジュールから呼ばれる述語)はpublic宣言(7-4.(2)参照)されていなければなりません。この場合、これらの述語を組込み述語として登録するための初期化プログラムは、コンパイラazpcがC言語ソースコードを生成する際に自動的に作られます。ファイル名またはモジュール名(7-4.(1)参照)は、この初期化関数の名前の一部になるため、C言語の関数名として妥当なものである必要があります。
C言語で記述する場合は、AZ-Prologの提供するC言語インターフェース(詳細は8章参照)に則って述語(関数)を定義しますが、初期化関数は自ら定義する必要があります。初期化関数の定義については、8-2-2.に解説されています。
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とします。
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);
}
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コンパイラは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); }
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).
拡張機能をスタティックリンクして、コンパイルされた実行モジュールに予め組込んでしまうこともできます。この場合は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
が必要になります。このファイルもリンクするか、コンサルトしてから確認してください。