IDLから外部のプログラムを実行するにはいくつか方法がある。IDLプロンプトから単に外部プログラムを実行するだけなら $
を使う。Windows では新たに開いたコマンドプロンプトの中でプログラムが実行されるが、プログラム終了後すぐに閉じてしまう。
$ ; シェルが起動する (Unixのコマンドライン版IDLのみ)
$ls
$\ls ; ls --color 等のaliasが定義されていて、lsの結果にエスケープシーケンスが含まれる場合
$cp file1 file2
IDLのプログラム中から実行する場合や、外部プログラムとの間でデータをやりとりする場合には SPAWN
を使う。noshell
キーワードを指定すると、新たにシェルを起動しないため速くなる。
spawn ; シェルが起動する
spawn, 'ls -l' ; lsの結果を画面に表示する
spawn, 'ls -l', result ; lsの結果(標準出力)を変数result(文字列の配列)に格納する
spawn, 'ls -l no_such_file', result, errresult ; 3番目の引数を指定すると標準エラー出力が格納される
spawn, ['ls', '-l'], result, /noshell ; noshellキーワードを指定すると、シェルを経由せずに実行するため速い。ただし、シェルの内部コマンドは使えない。また、引数は文字列の配列として渡す必要がある。
spawn, 'dir', result, /hide ; Windowsでは hide キーワードを指定すると、コマンドプロンプトが最小化された状態で実行される
spawn, 'sleep 10 &' ; Unixで子プロセスを非同期に実行する
基本的なファイル操作はなるべくIDL自身がもつファイル操作機能(FILE_SEARCH
、FILE_COPY
、FILE_MKDIR
など)を使うほうが移植性の高いプログラムとなる。
子プロセスとして起動した外部プログラムとの間でパイプによるデータのやりとりを行うことができる。
子プロセスの標準入力・出力両方を同時に利用する場合にはデッドロックに注意。出力のバッファリングはオフにしておく(C言語の場合、setbuf(stdout, NULL);
)。IDLでは非同期I/Oを使うのが難しいので、標準入力・出力両方で同時にパイプのバッファサイズ(x64のLinuxのデフォルトは64KiB)を超える大量のデータを扱う(例えば外部プログラムをフィルタとして使う)ことは困難だと思われる。
子プロセスが終了後に、WRITEUでパイプに書き込もうとするとエラーとなり、% WRITEU: Error encountered writing to file. Unit: 100, File: <prog> Broken pipe
というメッセージが表示される。
データをxzで圧縮しながらファイルに保存した後、それを展開しながら読み込む例:
; xzで圧縮したデータを書き込む
data = bytscl(dist(1000))
spawn, 'xz > file.xz', unit=unit
writeu, unit, data
free_lun, unit
; xzで圧縮されたデータを読み込む
data2 = bytarr(1000,1000)
spawn, ['unxz', '-c', 'file.xz'], unit=unit, /noshell
readu, unit, data2
free_lun, unit
IDLから外部のダイナミックライブラリ内の関数を呼び出すことができる。ただし、引数は特殊な方法で渡されるため、IDLから呼び出されることを想定されていない関数を利用する場合には、引数の変換を行うラッパー関数が必要になる。AUTO_GRUE
キーワードをつけることで、自動的にラッパー関数を生成しコンパイルしてくれる。以下はすべてx86_64のLinux環境での例。
; 引数を取らず、32bit整数を返す関数を呼ぶ (getpid(2)は呼び出し元のプロセスIDを返す)
pid = call_external('libc.so.6', 'getpid')
; 2つの32bit整数の引数をとり、32bit整数を返す関数を呼ぶ (kill(2)で2つ目の引数に0を指定すると何も起こらないので、プロセスの存在確認に使える)
result = call_external('libc.so.6', 'kill', pid, 0L, /auto_glue, /all_value)
; 1つの倍精度実数の引数をとり、倍精度実数を返す関数を呼ぶ (平方根)
result = call_external('libm.so.6', 'sqrt', 2d, /auto_glue, /all_value, /d_value)
AUTO_GRUE
キーワードにより作成されるラッパー関数を含むライブラリは、IDLの実行バイナリがあるディレクトリのce_glueサブディレクトリ(標準では存在しない)、または !MAKE_DLL.COMPILE_DIRECTORY
システム変数が指すディレクトリに保存される。
WRITE_WRAPPER
キーワードを指定することでラッパー関数のソースコードを出力できる。WRITE_WRAPPER
キーワードをつけた場合、実際に関数の呼び出しは行われない。
result = call_external('libm.so.6', 'sqrt', 2d, write_wrapper = 'wrapper.c', /all_value, /d_value)
IDLのインストールディレクトリ(IDL_DIR)以下のexternal/call_externalにCALL_EXTERNAL
のサンプルプログラムがある。
# Intel Fortran Compilerの場合
ifort -shared -fpic example.f -o example.so
# GFortranの場合
gfortran -shared example1.f -o example1.so -fPIC