C言語でのWSTP開発(Linux)
このドキュメントでは,Linuxシステム上で,C言語で書かれたWolfram Symbolic Transfer Protocol (WSTP)プログラムをコンパイルし実行する方法を説明する.(「WSTPと外部プログラム通信」はWolfram言語とC言語の両方でWSTPプログラムを書く方法を記述したものである.)
このドキュメントは,コンパイラや他の開発ツールの使い方を教えたり,C言語でのプログラミング方法を教えたりするものではない.WSTPプログラムの構築や実行で問題がある場合は,このドキュメントの「トラブルシューティング」をご覧いただきたい.
このドキュメントで記述されていることの多くは,Linux独特のものであり,サポートされるすべてのLinuxプラットフォームに当てはまる.別のプラットフォームでWSTPプログラムをコンパイルし実行する方法については,そのプラットフォームの開発者ガイドをご参照いただきたい.
Cコンパイラ | C++コンパイラ | ||
"Linux" | gcc (GCC) 4.4.6 20110731 (Red Hat 4.4.6-3) | g++ (GCC) 4.4.6 20110731 (Red Hat 4.4.6-3) | |
"Linux-x86-64" | gcc (GCC) 4.4.6 20110731 (Red Hat 4.4.6-3) | g++ (GCC) 4.4.6 20110731 (Red Hat 4.4.6-3) |
上記に加え,WSTP APIをコンパイルするにはlibuuid開発ライブラリが必要である.これはDebianシステムではuuid-dev,Red HatとSuseではlibuuid-develと呼ばれる.
WSTP Developer Kit (WSDK)は,Wolframシステムディレクトリの$InstallationDirectory/SystemFiles/Links/WSTP/DeveloperKit/$SystemIDディレクトリにある.
推奨されるインストール
CompilerAdditionsのインストール
WSTPプログラムを構築するのに必要なWSTPコンポーネントは,Wolframシステムのインストーラですでにインストールされている.これらのコンポーネントを使う方法の一つとして,これらをWolframシステムのディレクトリに残したままにしておき,コンパイラを呼び出すときにそのコンポーネントの完全パス名を指定するというものがある.「WSTPプログラムの構築」セクションの例題「makefiles」ではこのアプローチを使う.
別の方法として,コンパイラがこれらのフコンポーネント(wstp.h,libWSTP32i4.a,libWSTP32i4.so,libWSTP64i4.a,libWSTP64i4.so)を自動的に検索するディレクトリにコンポーネントをコピーするというものがある.このディレクトリは通常/usr/includeおよび/usr/libであるが,システムにより異なる可能性がある.多くのシステムでは,すべてのユーザにこれらのディレクトリへの書込み許可があるとは限らない.
WSTPExamplesのインストール
WSTPフレームワークコンポーネント
CompilerAdditionsディレクトリ
wstp.h
wstp.hはCあるいはC++のソースファイルに含まれなければならないヘッダファイルであり,コンパイラによって見付けられる場所になければならない.このヘッダファイルは,ソースファイルと同じディレクトリにコピーすることも,標準ヘッダファイルと同じ場所にコピーすることもできる.また,ヘッダファイルの検索パスにWSTPディレクトリを加えた場合はそのままの場所に置いておくこともできる.
libWSTP32i4.a/libWSTP64i4.a
これはWSTP関数すべてを含む静的ライブラリであり,プロジェクトに含まれていなければならない.このライブラリはソースファイルを同じディレクトリにコピーすることができる.また,ライブラリの検索パスにWSTPディレクトリを加えた場合は,そのままの場所に置いておくこともできる.32/64はWSTPライブラリが32ビットバージョンか64ビットバージョンかを示している.
libWSTP32i4.so/libWSTP64i4.so
これはWSTP関数すべてを含む動的共有ライブラリであり,プロジェクトに含まれていなければならない.このライブラリはソースファイルを同じディレクトリ,あるいは/libや/usr/libというシステム規模の場所にコピーすることができる.また,ライブラリの検索パスにWSTPディレクトリを加えた場合は,そのままの場所に置いておくこともできる.32/64はWSTPライブラリが32ビットバージョンか64ビットバージョンかを示している.
wsprep
wsprepはテンプレートファイルを処理することにより自動的にWSTPプログラムを書くアプリケーションである.このアプリケーションは,プロジェクトと同じディレクトリにコピーするか,それへのエイリアスを作っておくと便利である.
wscc
wsccはWSTPソースファイルを前処理しコンパイルするスクリプトである.
WSTPExamplesディレクトリ
PrebuiltExamplesフォルダ
このフォルダにはすでに構築された例題プログラムが含まれている.「WSTPプログラムの実行」ではそのプログラムのうちの2つを実行する方法を説明する.「WSTPプログラムの構築」ではWSTPExamplesフォルダのソースコードを使って自分でプログラムを構築する方法を説明する.
WSTPプログラムを構築する一般的な手順は,WSTP関数を呼び出すCあるいはC++のソースファイルにwstp.hを加え,ソースファイルをコンパイルし,結果のオブジェクトコードをlibWSTP32i4.a,libWSTP64i4.a,libWSTP32i4.so,libWSTP64i4.soライブラリか,アプリケーションによって必要とされる他の標準ライブラリに連結するというものである.アプリケーションがWSTPテンプレートメカニズムを使っている場合,テンプレートファイルはまずwsprepを使ってCのソースファイルに処理されなければならない.
WSTPのテンプレートファイルを使う
「WSTPと外部プログラム通信」で説明してあるようにプログラムでWSTPテンプレートメカニズムを使う場合は,wsprepアプリケーションを使ってテンプレートエントリを含むソースファイルを同時に前処理しなければならない.テンプレートエントリは,テンプレートキーワードを含む行の列である.各エントリは,評価されたときに,関連付けられたC関数を呼び出すWolfram言語関数を定義する.wsprepがそのようなソースファイルを処理するとき,テンプレートエントリをC関数に変換し,他のテキストを変更せずに渡し,WSTPを使ってリモート手続き呼び出しメカニズムを実装する追加のC関数を書き出す.結果はコンパイルの準備ができたCのソースファイルである.
は,addtwo.tmのテンプレートエントリと他のテキストからCのソースファイルaddtwotm.cを生成する.それからCコンパイラを使って出力ファイルをコンパイルする.プログラムの構築にmakeユーティリティを使っている場合は,makefileに以下の規則と類似の規則を加えることができる.
WSTPプログラムを構築する
次は,addtwoとfactorを含むWSDKのサンプルプログラムを構築するのに必要な,サンプルのmakefileである.サンプルプログラム(この場合はaddtwo)を構築するためにはWSTPExamplesディレクトリで以下のコマンドを評価する.
Makefileを使う
# This makefile can be used to build all or some of the sample
# programs. To build all of them, use the command
# 'make all'. To build one, say addtwo, use the command
# 'make addtwo'.
WSTPLINKDIR = /usr/local/Wolfram/Mathematica/10.0/SystemFiles/Links/WSTP/DeveloperKit
SYS = Linux # Set this value with the result of evaluating $SystemID
CADDSDIR = ${WSTPLINKDIR}/${SYS}/CompilerAdditions
INCDIR = ${CADDSDIR}
LIBDIR = ${CADDSDIR}
EXTRALIBS = -lm -lpthread -lrt -lstdc++ -ldl -libuuid # Set these with appropriate libs for your system.
WSTPLIB = WSTP32i4 # Set this to WSTP64i4 if using a 64-bit system
WSPREP = ${CADDSDIR}/wsprep
all : addtwo bitops counter factor factor2 factor3 quotient reverse sumalist
addtwo : addtwotm.o addtwo.o
${CC} -I${INCDIR} addtwotm.o addtwo.o -L${LIBDIR} -l${WSTPLIB} ${EXTRALIBS} -o $@
bitops : bitopstm.o bitops.o
${CC} -I${INCDIR} bitopstm.o bitops.o -L${LIBDIR} -l${WSTPLIB} ${EXTRALIBS} -o $@
counter : countertm.o
${CC} -I${INCDIR} countertm.o -L${LIBDIR} -l${WSTPLIB} ${EXTRALIBS} -o $@
factor : factor.o
${CC} -I${INCDIR} factor.o -L${LIBDIR} -l${WSTPLIB} ${EXTRALIBS} -o $@
factor2 : factor2.o
${CC} -I${INCDIR} factor2.o -L${LIBDIR} -l${WSTPLIB} ${EXTRALIBS} -o $@
factor3 : factor3.o
${CC} -I${INCDIR} factor3.o -L${LIBDIR} -l${WSTPLIB} ${EXTRALIBS} -o $@
quotient : quotient.o
${CC} -I${INCDIR} quotient.o -L${LIBDIR} -l${WSTPLIB} ${EXTRALIBS} -o $@
reverse : reversetm.o
${CC} -I${INCDIR} reversetm.o -L${LIBDIR} -l${WSTPLIB} ${EXTRALIBS} -o $@
sumalist : sumalisttm.o sumalist.o
${CC} -I${INCDIR} sumalisttm.o sumalist.o -L${LIBDIR} -l${WSTPLIB} ${EXTRALIBS} -o $@
.c.o :
${CC} -c -I${INCDIR} $<
addtwotm.c : addtwo.tm
${WSPREP} $? -o $@
bitopstm.c : bitops.tm
${WSPREP} $? -o $@
countertm.c : counter.tm
${WSPREP} $? -o $@
reversetm.c : reverse.tm
${WSPREP} $? -o $@
sumalisttm.c : sumalist.tm
${WSPREP} $? -o $@
以下の表を使うと,使用中のシステム上でWSTPプログラムの接続に必要な追加のライブラリが判別できる.
$SystemID | EXTRALIBS | |
"Linux" | -lm -lpthread -lrt -lstdc++ -ldl -luuid | |
"Linux-x86-64" | -lm -lpthread -lrt -lstdc++ -ldl -luuid |
wsccを使う
wsccはWSTPソースファイルを前処理してコンパイルするスクリプトである.これはファイル名が.tmで終わるファイルすべてのWSTPテンプレートを前処理して,その結果のCソースコードに対してccを呼ぶ.wsccはコマンドラインオプションと他のファイルを直接ccに渡す.次がwsccを使ってaddtwoアプリケーションを構築するコマンドである.
wscc addtwo.tm addtwo.c -o addtwo
「WSTPプログラムの構築」の手順は,WSTPExamplesディレクトリのソースコードを使って2つのWSTPプログラムを構築する方法を説明するものである.これらの2つのプログラムaddtwoとfactorはすでにPrebuiltExamplesフォルダの中に構築されている.自分で構築する前にすでに構築された例題を実行してみて,WSTPシステム追加分がインストールされ正常に動いていることを確認し,プログラムが適切に構築されるとどのようなことが起こるかを学んでおくとよい.
WSTPプログラムにはaddtwoプログラムで要約されるものとfactorプログラムで要約されるものの2つの基本的な形式がある.addtwoプログラムで要約されるものはインストール可能なプログラムである.インストール可能なプログラムは,呼出しメカニズムを介してCプログラムをカーネルに接続することにより,カーネルに新しい機能を提供する.この新しい機能を取得するためには,Wolfram言語のユーザはInstall[]関数を実行しなければならない.addtwoの例題では,引数として提供される2つの数を足すAddTwo[]と呼ばれる新しい関数を加えることになる.カーネルとインストール可能プログラムは互いにのみ通信し合える特別な関係を持つ.インストール可能プログラムが実行されるとき,接続のために情報を提供する必要がある.factorプログラムで要約されるものは,フロントエンドである.フロントエンドはリンクを作成したり管理したりする作業をすべて行う.factorの例題に加え,WolframシステムフロントエンドとWolfram言語カーネルもフロントエンドタイプの例である.フロントエンドは実行するために追加の情報を必要としないが,通常実行中のある段階で接続を確立する.
Wolfram言語カーネルからすでに構築された例題を実行する
最初の例題プログラム,addtwoはWolfram言語にインストールされているWSTPテンプレートプログラムである.つまり,このプログラムは背景で実行し,Wolfram言語のサービスとして,外部でコンパイルされた1つあるいは複数の関数を提供する.Wolfram言語ユーザにとって,これらの関数は組込みのように見える.addtwoプログラムは,C関数のaddtwo()の呼出しとしてWolfram言語関数AddTwo[]を定義するテンプレートファイルを使う.テンプレートメカニズムについては「WSTPと外部プログラム通信」で説明してある.このプログラムのソースコードは以下のようなものである.
:Begin:
:Function: addtwo
:Pattern: AddTwo[i_Integer, j_Integer]
:Arguments: { i, j }
:ArgumentTypes: { Integer, Integer }
:ReturnType: Integer
:End:
:Evaluate: AddTwo::usage = "AddTwo[x, y] gives the sum of two machine integers x and y."
int addtwo( int i, int j)
{
return i+j;
}
int main(int argc; char* argv[])
{
return WSMain(argc, argv);
}
2つの機械整数の和が機械整数に適合しない場合,あるいはどちらかの引数が機械整数でない場合にどうなるかを見てみる(2^31-1は最大の機械整数である.コンパイラが2バイト整数を使う場合は2^15-1が最大のC intである):
すでに構築された例題内からWolfram言語カーネルを起動する
2つ目の例題プログラムのfactorは,Wolfram言語カーネルが背景で動いており,factorのサービスとしてカーネルの計算サービス(この場合はユーザによって入力された整数を因数分解する機能)を提供するという意味で,Wolframシステムのフロントエンドであると言える.
サポートされるリンクプロトコル
C関数のWSOpenArgcArgv(),およびWolfram言語関数のLinkOpen[]については,「WSTPと外部プログラム通信」で説明してある.LinuxマシンではLinkProtocolオプションの適正な値は"TCPIP","TCP","SharedMemory","Pipes","IntraProcess"である.LinkProtocolは接続の一端から他方へとデータを転送するのに使われるメカニズムである.LinkMode->Launchリンクのデフォルトのプロトコルは"SharedMemory"である."SharedMemory"はLinkMode->ListenリンクおよびLinkMode->Connectリンクのデフォルトでもある.
"TCPIP"プロトコルと"TCP"プロトコルでは,リンク名は符号のない16ビットの整数である. "TCPIP"のリンク名が整数であっても,WSOpenArgcArgv()およびLinkOpen[]への桁の列として与えられる.
- プログラムが動作するまでコンパイラの最適化をオフにする.これによりコンパイラはより速く,デバッグはより簡単になる.その上最適化ツールが壊れている可能性や,問題の原因になっている可能性もある.最適化されたコードはスタックを使い,コードのバグを表示するか隠すかという点で最適化されていないコードとは違うように登録される.例えば,局所変数のポインタを返すというよくある間違いは,スタックおよび登録の使用によって問題を引き起すことも起こさないこともある.
- WSTPライブラリ関数からの戻り値をチェックするか,プログラムのキーポイントでWSError()を呼び出すかする.WSTPは通常,何が悪かったのかを知らせることができる.
- ファイルwstp.h,libWSTP32i4.a,libWSTP32i4.so(64ビットプラットフォームではlibWSTP64i4.*)はマッチした集合である.WSTPの前リリースを使っていた場合は,アプリケーションを構築する場合にコンポーネントを混同しないように注意する必要がある.
- 使用中のCコンパイラがプロトタイプをサポートするかどうかをチェックする.サポートしない場合,コードを変更したりプロジェクトの構築方法を変えたりする必要がある.これについては「WSTPプログラムを構築する」のセクションで説明してある.